06300059.txt 30-Jun-00


WinExec with returncode

Hi Mike,

thanks for reply.
here's the code of my winexec function.
can you, or anybody else, tell me if that works.

regards,
markus mitterauer

FUNCTION MyWinExec( sAppl AS STRING, sCmdLine AS STRING );
  AS DWORD
  LOCAL dwErr AS DWORD
  LOCAL sErr AS PSZ
  LOCAL xSi AS _winstartupinfo
  LOCAL xPi AS _winProcess_information
  LOCAL hProc AS PTR
  LOCAL dwExitCode AS DWORD
  xSi := MemAlloc( _sizeof( _winstartupinfo ) )
  xSi := MemSet( xSi, 0, _Sizeof( _winstartupinfo ) )
  xSi.cb := _sizeof( _winstartupinfo )
  xSi.dwX := 0
  xSi.dwY := 0
  xSi.dwXSize := 0
  xSi.dwYSize := 0
  xSi.dwXCountChars := 0
  xSi.dwYCountChars := 0
  xSi.dwFillAttribute := 0
  xSi.dwFlags := STARTF_USESHOWWINDOW
  xSi.wShowWindow := SW_ShowDefault
  xSi.cbReserved2 := 0
  xPi := MemAlloc( _sizeof( _WINProcess_information ) )
  xPi := MemSet(xPi, 0, _Sizeof(_winProcess_information))
  IF CreateProcess( PSZ(sAppl), PSZ(sCmdLine),;
    null_ptr, null_ptr,TRUE,;
    create_default_error_mode + idle_priority_class, ;
    null_ptr, null_psz, xSi, xPi )
    // CreateProcess() successful
    hProc := xPi.hProcess
  ELSE
    // CreateProcess() failed
    dwErr := GetLastError()
    IF 0 == FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER+;
      FORMAT_MESSAGE_FROM_SYSTEM+;
      FORMAT_MESSAGE_FROM_STRING,;
      null_ptr, dwErr, ;
      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),;
      sErr,0,null_ptr )
      MessageBox( 0, PSZ("FormatMessage"), ;
        PSZ("MyWinExec() Error"), boxiconhand )
    ENDIF
    MessageBox( 0, PSZ(sErr), ;
      PSZ("MyWinExec() - CreateProcess - Error#"+;
      NTrim( dwErr )), boxiconhand )
  ENDIF
  MemFree( xSi )
  MemFree( xPi )
  IF .not. hProc == NULL_PTR

    // this is a bit brutal, but it should work
    // i am open for improvements
    dwExitCode := STILL_ACTIVE
    DO WHILE dwExitCode == STILL_ACTIVE
      IF GetExitCodeProcess(hProc,@dwExitCode)
      ELSE
      MessageBox( 0, ;
        PSZ("Error calling GetExitCodeProcess()!"),;
        PSZ("MyWinExec() Error"), boxiconhand )
        dwExitCode := 999999
      ENDIF
     *  MessageLoop() // peekmessage() -> dispatchmessage()
    END DO
  ENDIF
RETURN dwExitCode


Markus,

If your problem is that CreateProcess fails, I'd try passing
  NULL_PTR as the first parameter, and the full commandline
  as the second parameter. That approach works for me.
Incidentally, you could cut down your number of lines of
  code if you initialise structures with IS instead of AS.
  This automatically allocates memory for them on the stack,
  so you don't have to explicitly MemAlloc/MemFree them.
  Also, unlike C and Pascal, VO initialises variables to
  their appropriate null values, so you don't need the
  MemSet or the explicit 0 assignments.
Also, I notice that you set the priority of your new process
  to IDLE_PRIORITY_CLASS. Is this a good idea, considering
  that you're suspending your main app until this process
  terminates?

Regards,
Mike


Hi Mike,

thanks for reply.
CreateProcess don't fails.
maybe i was not precise enough. i'm not sure that my
  function does not work, because i'm getting always the
  return value zero.
i tried to user IS instead AS and removed the
  MemAlloc/MemFree/MemSet lines and then when compiling i
  get the error 'illegal use of an IS variable' at the line
  of CreateProcess.
yes, my app should wait until the other process completed.
  (in the specific case i started sybase sql anywhere's ISQL
  and want to know if the script to execute fails or not.)

regards,
markus


Markus,

>

maybe i was not precise enough. i'm not sure that my
  function does not work, because i'm getting always the
  return value zero.
>
I see. Maybe the problem isn't at your end - what error
  codes do you expect back from iSQL?
>
then when compiling i get the error 'illegal use of an IS
  variable' at the line of CreateProcess.
>
That's because you need to pass the address of an IS
  variable, i.e. @struct rather than struct.
>
(in the specific case i started sybase sql anywhere's ISQL
  and want to know if the script to execute fails or not.)
>
Have you tried writing a little test program that calls
  ExitProcess() to test whether your program picks up the
  return value? If it works, the problem may be with the
  sybase app.

Mike


Mike,

in case of success it returns 0 else anthing >0 (says the
  help file).
i tryed to check the return code with a batch file and the
  ERRORLEVEL variable.
IS: my fault, thanks for your VO lession. ;-)
no i don't tried yet, but i'll do.

Regards,
markus


Hi Mike,

thank you very much for your support, but i'm afraid i've
  waisted your time.
the function really worked from the beginning, but iSQL
  wasn't always giving back the expected return value, only
  under certain circumstances, And i had also another bug in
  my application.
the test apps i wrote now showed me this. (i attached the
  source if you, or someone else, could use it.)
sorry.

Regards,
markus mitterauer

FUNCTION MyWinExec( sAppl AS STRING, sCmdLine AS STRING );
  AS INT
  LOCAL dwErr AS DWORD
  LOCAL sErr AS PSZ
  LOCAL xSi IS _winstartupinfo
  LOCAL xPi IS _winProcess_information
  LOCAL hProc AS PTR
  LOCAL iExitCode AS INT

  xSi.cb := _sizeof( _winstartupinfo )
  xSi.dwX := 0
  xSi.dwY := 0
  xSi.dwXSize := 0
  xSi.dwYSize := 0
  xSi.dwXCountChars := 0
  xSi.dwYCountChars := 0
  xSi.dwFillAttribute := 0
  xSi.dwFlags := STARTF_USESHOWWINDOW
  xSi.wShowWindow := SW_ShowDefault
  xSi.cbReserved2 := 0
  IF CreateProcess( PSZ(sAppl), PSZ(sCmdLine),;
    null_ptr, null_ptr,TRUE,;
    create_default_error_mode + idle_priority_class, ;
    null_ptr, null_psz, @xSi, @xPi )
    // CreateProcess() successful
    hProc := xPi.hProcess
  ELSE
    // CreateProcess() failed
    dwErr := GetLastError()
    MessageBox( 0, PSZ(sErr), PSZ("MyWinExec();
      - CreateProcess - Error #"+NTrim(dwErr )), ;
      boxiconhand )
  ENDIF
  IF .not. hProc == NULL_PTR
    // this is a bit brutal, but it should work
    // i am open for improvements
    iExitCode := STILL_ACTIVE
    DO WHILE iExitCode == STILL_ACTIVE
      IF GetExitCodeProcess(hProc,@iExitCode)
      ELSE
        MessageBox( 0, ;
          PSZ("Error calling GetExitCodeProcess()!"),;
          PSZ("MyWinExec() Error"), boxiconhand )
        iExitCode := 999999
      ENDIF
      MessageLoop() // peekmessage() -> dispatchmessage()
    END DO
  ENDIF
RETURN iExitCode
FUNCTION MessageLoop( oWindow )
  // VB-Pendant: DoEvent
  LOCAL msg  IS _WINMSG
  LOCAL hwnd AS PTR
  IF IsNil(oWindow)
    // Allow all windows to receive events
    hwnd := null_ptr
  ELSE
    // Allow a specific window to receive events
    hwnd := oWindow:Handle()
  ENDIF
  DO WHILE ( PeekMessage( @msg, hwnd, 0, 0, PM_REMOVE ) )
    *  TranslateMessage( @msg )
    DispatchMessage( @msg )
  ENDDO
RETURN NIL


I wonder if we're all missing an important point here on
  this one.

In looking for the return code, won't the WinExec() - or
  anything else really - return pretty well immediately it
  has completed its task?
And isn't its task simply to START the other application?
So it starts the other application and returns; both
  applications ar now running, and - and this is perhaps the
  key - your application, the one that called the winExec(),
  is already past the point where it needs (expects) to see
  the return code.
Or it's seeing the return code correctly, but that return
  code is not really telling you what you expect to see.
What I think a more appropriate approach to the problem
  might be to have the application that you started with the
  winExec() call send a message to the principal application
  when it's finished its tasks. Hide or minimise the
  principal application perhaps while the subordinate app is
  running, but have its event loop look for the finish
  message from its child.
Logic flow might be something like ..
  Start OwnerApp
  Do stuff
  winExec( ChildApp )
  Minimise OwnerApp
  OwnerApp message handler remains active
  ChildApp starts
  Does its stuff
  Send completion message to OwnerApp
  ChildApp Ends
  OwnerApp recieves message from ChildApp
  OwnerApp awakens itself
  OwnerApp continues processing
Am I making any sense ?

Gary Stark


Gary,

>
I wonder if we're all missing an important point here on
  this one.
>
If you go back and read Markus' code sample from a few posts
  back and you'll see that after CreateProcess (NOT WinExec
  - WinExec is a 16-bit compatibility function that should
  no longer be used - anyway, it doesn't return a valid
  process handle in a 32-bit environment) returns there is a
  loop wherein GetExitCodeProcess is called with the handle
  of the child process until it no longer returns the value
  STILL_ACTIVE. When the child process terminates,
  GetExitCodeProcess will return it's exit code, and the
  calling process breaks out of it's loop.

Mike