1. Arnaud Bailly
  2. PowerBuilder
  3. Friday, 20 March 2020 18:34 PM UTC

I am trying to write a simple console application for the purpose of running (unit or integration) tests of existing PB code in various libraries. The idea is that I have a dedicated target XXXXTest that includes libraries from the main project and run specialised test functions, displaying the result of each function in the console.

I am currently struggling with the basic problem of having the console wait for the application to terminate. I have followed the code from https://www.rgagnon.com/pbdetails/powerbuilder-print-to-the-console.html and this works fine but the output looks like the following:

$> myapptest.exe
$> hello

eg. the console does not wait for the termination of the process which means the process' output comes after the console returns.

Any clue on how to solve this issue?


Olan Knight Accepted Answer Pending Moderation
  1. Saturday, 21 March 2020 23:55 PM UTC
  2. PowerBuilder
  3. # 1

Arnaud -

   Are you looking to have a multi-threaded application? One where the main process is running separately from the OTHER process, which is running utterly independently in a separate thread?

   I have been working on such a module recently and it is FAR more difficult than I had expected, mainly becuase there is zero documentation on how to write such code, and no indication of what the rules and restriction are for multi-threaded code.

   Here is what I have discovered so far:

Coding a multi-threaded object
1.  The NVO can NOT declare any instance object that is AutoInstantiated (AI)
2.  A multi-threaded (MT) NVO has no access to any object or variable in the
    parent exe

3.  The NVO can declare but cannot USE any object that includes an AI object
    or that accesses a global variable

4.  You cannot debug a MT NVO; you must use MessageBoxes
5.  When any error occures in the NVO, the entire NVO fails silently and

6.  Can only pass NVOs and primitives as parameters to NVO function from the
    parent exe

7.  When declared, variables are NOT set to NULL;
    you must SetNull (x) manually if you want to use IsNull() in your code

8.  Do not use objects from the PFC, use primitives;
    example: use datastore, not n_ds

From the parent EXE:
A.  You cannot DESTROY the MT NVO, you must use ShareObjectUnRegister

B.  After calling ShareObjectUnRegister, it takes at least 3 seconds for the
    object to actually be destroyed.

C.  Cannot use IsValid(), must use SharedObjectGet() to see if the NVO still

   Meanwhile, I'm still trying to figure out how to get the NVO to communicate with the parent EXE; i.e. how to do a callback.


   Here's the function that invokes the multi-threaded module AutoRpts. The basics are:

// Instance variable in the calling module

// Object       :  w_cabs_frame
// Function     :  of_get_autorpt_ptr()
// Ancestor     :  None
// Access       :  Public
// Arguments    :  None
// Returns      :  u_nv_autorpt        The pointer to the Autorpt NVO
// Throws       :  None
// Description  :  This function returns the pointer to the AutoRpt
//                 NVO. It is this NVO that will be used for all
//                 AutoRpt processing.
// How we got here:
//                 ue_modules
//                     of_check_AutoRpt (FALSE)
//                         of_start_autorpt
//                             of_get_autorpt_ptr
// Revision History
// Developer    Date          Version     Description
// ---------    -----------   ---------   -------------------------------
// O Knight     20-JAN-2020   #2666065:  Initial version.
errorReturn        lret_rc
long                ll_rc
string            ls_hdr, ls_err

// Since someone is requesting a pointer to the NVO,
// create it if it does not yet exist

lret_rc = SharedObjectGet (AUTORPTS_NAME, inv_autorpt)    
IF (lret_rc <> SUCCESS!) THEN

    // Multi-threaded invocation
    lret_rc = SharedObjectRegister ("u_nv_autorpt", AUTORPTS_NAME)
    IF (lret_rc = SUCCESS!) THEN
        lret_rc = SharedObjectGet (AUTORPTS_NAME, inv_autorpt)    
        IF (lret_rc = SUCCESS!) THEN
            // The multi-threaded AutoRpts object has been created.    
            ls_hdr = "Error Accessing AutoRpts"
            ls_err = "An error occurred while getting a pointer to the " + 
object ~"INV_AUTORPT~". ~r~n~r~n"
            IF (lret_rc <> SUCCESS!) THEN
                IF (lret_rc = SharedObjectCreateInstanceError!) THEN
                    ls_err = ls_err + "SharedObjectCreateInstanceError! "  + &
                             "- The local reference to the shared object " + &
                             "could not be created."

                ELSEIF (lret_rc = SharedObjectNotExistsError!) THEN
                    ls_err = ls_err + "SharedObjectNotExistsError! "       + &
                             " - The instance name has not been registered."
                END IF
            END IF
        END IF
        ls_hdr = "Error Creating AutoRpts"
        ls_err = "An error occurred attempting to create the " + &
                 "multi-threaded object
~"INV_AUTORPT~". ~r~n~r~n"
        CHOOSE CASE lret_rc
            CASE SharedObjectExistsError!
                 ls_err = ls_err + "SharedObjectExistsError! - The " + &
                          "instance name has already been used."

            CASE SharedObjectCreateInstanceError!
                 ls_err = ls_err + "SharedObjectCreateInstanceError! - " + &
                          "The object could not be created."

            CASE SharedObjectCreatePBSessionError!
                 ls_err = ls_err + "SharedObjectCreatePBSessionError! - " + &
                          "The shared object session could not be created."

            CASE ELSE
        END CHOOSE        
    END IF

IF (ls_err <> "") THEN
    MessageBox (ls_hdr, ls_err, StopSign!)
    gnv_app.of_logit (".")
    gnv_app.of_logit ("  -----  Error starting INV_AUTORPTS  -----")
    gnv_app.of_logit (ls_hdr)
    gnv_app.of_logit (ls_err)
    gnv_app.of_logit (".")

// Return the pointer to the AutoRpt NVO
RETURN inv_autorpt

Hope this helps,


  1. Arnaud Bailly
  2. Monday, 23 March 2020 08:41 AM UTC
Actually no, it does not help much but thanks for reply Olan :) I am trying to do something much simpler, namely have a single threaded console application whereby the (hopefully parent process) console waits for the (child process) termination before returning to the prompt.
  1. Helpful
  1. Olan Knight
  2. Monday, 23 March 2020 22:26 PM UTC
  1. Helpful
  1. Arnaud Bailly
  2. Wednesday, 25 March 2020 08:23 AM UTC
Olan, Thank you for your suggestion but this code says

> This program shows how to execute other programs and wait for them to finish before continuing.

I don't want to execute OTHER programs but I want to execute THIS program and have the console wait for it to complete its job.
  1. Helpful
There are no comments made yet.
John Fauss Accepted Answer Pending Moderation
  1. Friday, 20 March 2020 19:27 PM UTC
  2. PowerBuilder
  3. # 2

Hi, Amaud - 

You may wish to examine the PB code in Roland Smith's RunAndWait free code at his TopWizProgramming.com web site, and see if the technique is applicable to your particular needs.


Regards, John

  1. Arnaud Bailly
  2. Saturday, 21 March 2020 13:39 PM UTC
Hi John, Thanks for the advice. I came across this example while searching the. internet and it's not exactly what I am looking for: In this example, the main program waits for another program to terminate which, obviously waits. But in my case I am looking for a way to have the console wait for the main program to terminate. I suspect this has to do with the way powerbuilder compiles the application but given my lack of knowledge of both PB and windows system programming, I am a bit at a loss here.

If I do a start /wait myapptest.exe then it works as expected

>start /wait progsaftest.exe

Hello world

from Real's HowTo


  1. Helpful
There are no comments made yet.
  • Page :
  • 1

There are no replies made for this question yet.
However, you are not allowed to reply to this question.