Running an external program from an ASM running program [?]

Started by frktons, September 16, 2010, 01:30:28 PM

Previous topic - Next topic

frktons

If a MASM program is running, and at some point it needs to run an
external program and getting back the control when the called prog finishes,
what kind of instructions have I to use?

Let's talk for the moment of a console program calling another external console
program:

Prog1.exe  --- Run ------> Prog2.exe ----> End Prog2.exe ----> Prog1.exe regains control


Thanks

Frank
Mind is like a parachute. You know what to do in order to use it :-)


clive

From the CRT there are also exec,spawn,system functions. Depends what you want to do with command line, environment variables, and return codes.
It could be a random act of randomness. Those happen a lot as well.

frktons

Quote from: dedndave on September 16, 2010, 02:37:46 PM
CreateProcess

Hi Dave, welcome back.  :bg
You are a little bit too verbose. Shouldn't it be enough to write CP?  :lol

Come on, when you feel like, post an addendum to this code, that INVOKE the CreateProcess
to run the selected prog:


;-------------------------------------------------------------------------------
; Call a OpenFileDialog through a MACRO
; Select an EXE file
; Run it
; Displays some stuff when back.
;-------------------------------------------------------------------------------


include \masm32\include\masm32rt.inc

; -------------------------------------------------------------------------

.data

   ConTitle  db "  ----------     **  Example running an external prog  **",
                "----------", 0  


   CaptionText   BYTE  "Open Prog to Run",0

   szFilter      BYTE  "All files *.*",0,"*.*",0,
                       "Executable files *.exe",0,"*.exe",0,    
                       "Text files *.txt",0,"*.txt",0,
                       "Assembly files *.asm",0,"*.asm",0,
                       "Resource files *.rc",0,"*.rc",0,0
                       
; -------------------------------------------------------------------------

.data?

   hFile     HANDLE ?
   cci       CONSOLE_CURSOR_INFO <>        


   wHnd      HANDLE ?
   rHnd      HANDLE ?

   windowSize SMALL_RECT <>
   bufferSize COORD      <>
   startPoint COORD      <>

   howmany dd ?
   buffer  INPUT_RECORD <>    

   PtrFileName   DWORD ?            

.code

start:


; -------------------------------------------------------------------------

Main PROC

   CALL   InitProc

   CALL   ConsoleSize

   print " Press any key and choose the prog to run: ",13,10,13,10

   CALL   AnyKey    

   mov PtrFileName, OpenFileDlg (0,0, addr CaptionText, addr szFilter)  

   print " The chosen prog is: "

   print DWORD PTR PtrFileName, 13,10,13,10

   print " Press a key to run it ", 13,10,13,10

   CALL   AnyKey    
   
; -------------------------------------------------------------------------
; Here we call the selected prog to run
; -------------------------------------------------------------------------


; -------------------------------------------------------------------------

   print " Back from the called prog", 13,10,13,10

   CALL   AnyKey  

   CALL   ShowTheCursor

   INVOKE ExitProcess,0

   ret

Main ENDP

; -------------------------------------------------------------------------  

ConsoleSize PROC

   INVOKE SetConsoleTitle, ADDR ConTitle
 
   CALL   HideTheCursor

   INVOKE SetConsoleWindowInfo, wHnd, TRUE, ADDR windowSize

   INVOKE SetConsoleScreenBufferSize, wHnd, DWORD PTR bufferSize

   ret

ConsoleSize ENDP

; -------------------------------------------------------------------------

ShowTheCursor PROC

   INVOKE GetConsoleCursorInfo,wHnd,addr cci
   mov cci.bVisible,TRUE
   INVOKE SetConsoleCursorInfo,wHnd,addr cci
   ret
   
ShowTheCursor ENDP

; -------------------------------------------------------------------------
   


HideTheCursor PROC

   INVOKE GetConsoleCursorInfo,wHnd,addr cci
   mov cci.bVisible,FALSE
   INVOKE SetConsoleCursorInfo,wHnd,addr cci
   ret
   
HideTheCursor ENDP

; -------------------------------------------------------------------------

InitProc PROC

    INVOKE AllocConsole

   INVOKE GetStdHandle, STD_INPUT_HANDLE
   mov rHnd,eax

   INVOKE GetStdHandle, STD_OUTPUT_HANDLE
   mov wHnd,eax  

   mov windowSize.Left, 0
   mov windowSize.Right, 79
   mov windowSize.Top, 0
   mov windowSize.Bottom, 24
 

   mov bufferSize.x, 80
   mov bufferSize.y, 25

   mov startPoint.x, 0
   mov startPoint.y, 0


   ret

InitProc ENDP


; -------------------------------------------------------------------------
;Returns: key code in buffer.KeyEvent.wVirtualKeyCode WORD size
; -------------------------------------------------------------------------

AnyKey PROC

again:  

   INVOKE ReadConsoleInput,rHnd,offset buffer,1,offset howmany
   cmp buffer.EventType,KEY_EVENT
   jnz again

   cmp buffer.KeyEvent.bKeyDown,0
   jz again

   ret

AnyKey ENDP


; -------------------------------------------------------------------------
 
end start          



Quote from: clive on September 16, 2010, 03:04:38 PM
From the CRT there are also exec,spawn,system functions. Depends what you want to do with command line, environment variables, and return codes.

Any solution is just fine, if you show me the code to do it.  :P

Frank

Mind is like a parachute. You know what to do in order to use it :-)

untio

Hi,
When I need to call another process and wait until it is finished I use CreateProcess to create it and I use:
BOOL GetExitCodeProcess(
  HANDLE hProcess,
  LPDWORD lpExitCode
);
to wait until it is finished. The value pointed by lpExitCode is STILL_ACTIVE (259) until the process is finished. What I do is enter into a loop that includes a Sleep(someValue) and a call to GetExitCodeProcess.
But this can bring a big problem if the other process returns 259. I have never encountered this case.
Please forgive my errors.

clive

Quote from: frktons
Any solution is just fine, if you show me the code to do it.  :P

Uhm, half the battle is knowing what WIN32 or CRT functions to use, the web is rife with documentation, the examples will probably be in C, but transcribing that to an INVOKE, or manually PUSHing the arguments and CALLing shouldn't be too hard.

Then again there are simple approaches and more complex ones, like for instance whether the EXE is pulled from a specific place, if the PATH is used, if it is a shell function (CD, DIR, etc), what command line parameters need passing, do you want to alter the environment variables. You've indicated you want to regain control after the child app is finished, but you could have it go off on it's own.
It could be a random act of randomness. Those happen a lot as well.

frktons

Quote from: clive on September 16, 2010, 03:53:27 PM
Quote from: frktons
Any solution is just fine, if you show me the code to do it.  :P

Uhm, half the battle is knowing what WIN32 or CRT functions to use, the web is rife with documentation, the examples will probably be in C, but transcribing that to an INVOKE, or manually PUSHing the arguments and CALLing shouldn't be too hard.

Then again there are simple approaches and more complex ones, like for instance whether the EXE is pulled from a specific place, if the PATH is used, if it is a shell function (CD, DIR, etc), what command line parameters need passing, do you want to alter the environment variables. You've indicated you want to regain control after the child app is finished, but you could have it go off on it's own.

Hi clive.

I'm looking for a simple one. If you look at the code I posted above:

http://www.masm32.com/board/index.php?topic=14824.msg120765#msg120765

I simply do:

1) choose the exe to execute
2) run it [missing part]
3) display "I'm back"

So no command line parameters, or anything else for the time being,
only an INVOKE to a CRT function, or CreateProcess API will suffice.
The only thing, I don't know the exact calling parameters for each of
them, or if I have to declare something and in which shape.

So just to start any of them will be fine.

Frank
Mind is like a parachute. You know what to do in order to use it :-)

Tedd

Quote from: untio on September 16, 2010, 03:48:07 PM
Hi,
When I need to call another process and wait until it is finished I use CreateProcess to create it and I use:
BOOL GetExitCodeProcess(
  HANDLE hProcess,
  LPDWORD lpExitCode
);
to wait until it is finished. The value pointed by lpExitCode is STILL_ACTIVE (259) until the process is finished. What I do is enter into a loop that includes a Sleep(someValue) and a call to GetExitCodeProcess.
But this can bring a big problem if the other process returns 259. I have never encountered this case.
Please forgive my errors.

You should use WaitForSingleObject which will put your process to sleep until the other process exits (or a timeout is reached.) Then you can call GetExitCodeProcess to see whatever it returned (if required.) No polling required :bg
No snowflake in an avalanche feels responsible.

Tedd

Once you've got the name of the program you want to run, using CreateProcess is straightforward, as long as you don't want to do anything fancy (just run it!)

You have to fill out a STARTUPINFO struct, but most of that can be zeroed, and then you call CreateProcess passing that struct as one of the parameters, and most of the other parameters can be zeroed :bg
No snowflake in an avalanche feels responsible.

frktons

Quote from: Tedd on September 16, 2010, 04:21:25 PM
Once you've got the name of the program you want to run, using CreateProcess is straightforward, as long as you don't want to do anything fancy (just run it!)

You have to fill out a STARTUPINFO struct, but most of that can be zeroed, and then you call CreateProcess passing that struct as one of the parameters, and most of the other parameters can be zeroed :bg


As a matter of fact I did this way, and it worked:


; -------------------------------------------------------------------------
; Here we call the selected prog to run
; -------------------------------------------------------------------------


    invoke memfill,ADDR StartUpInfo,SIZEOF StartUpInfo,0 ; fill STARTUPINFO
   
    mov StartUpInfo.cb,SIZEOF StartUpInfo ;

    fn CreateProcess,0,DWORD PTR PtrFileName,0,0,0,0,0,0,ADDR StartUpInfo,ADDR ProcessInfo

; -------------------------------------------------------------------------


Any other solution using CRT functions?

Frank
Mind is like a parachute. You know what to do in order to use it :-)

frktons

The only problem is that after I call the other console app, back from it
I've no more control, the calling prog terminates as well.

::)
Mind is like a parachute. You know what to do in order to use it :-)

jj2007

 :wink
QuoteLaunch
   Launch "Notepad.exe"
   Launch "Notepad.exe MyNewFile.txt"
   Launch "Notepad.exe MyNewFile.txt", SW_MINIMIZE
   Launch "Notepad.exe MyNewFile.txt", SW_MAXIMIZE, 2000   ; cmd, show, timeout in ms
Rem[/color]   returns CreateProcess error code in eax
[/b]

Tedd

Prog1.exe:  CreateProcess [Prog2.exe] ==> hProcess
<Prog2.exe created>

Prog1.exe:  WaitForSingleObject [hProcess]
<Prog1.exe waiting>

Prog2.exe: ...do stuff...
<Prog2.exe exit>

Prog1.exe:  ...continue...
No snowflake in an avalanche feels responsible.

frktons

Quote from: jj2007 on September 16, 2010, 04:42:22 PM
:wink
QuoteLaunch
   Launch "Notepad.exe"
   Launch "Notepad.exe MyNewFile.txt"
   Launch "Notepad.exe MyNewFile.txt", SW_MINIMIZE
   Launch "Notepad.exe MyNewFile.txt", SW_MAXIMIZE, 2000   ; cmd, show, timeout in ms
Rem[/color]   returns CreateProcess error code in eax
[/b]

Hi Jochen. This other one is quite new for me.  ::)

What is it? A MACRO? A function? Or what? Where do I find the documentation?

Thanks.

Quote from: Tedd on September 16, 2010, 04:43:02 PM
Prog1.exe:  CreateProcess [Prog2.exe] ==> hProcess
<Prog2.exe created>

Prog1.exe:  WaitForSingleObject [hProcess]
<Prog1.exe waiting>

Prog2.exe: ...do stuff...
<Prog2.exe exit>

Prog1.exe:  ...continue...


Well an example speaks more than 1000 words.
Here it is the complete prog, so why it closes when back from the
called prog? I surely need some other instructions, like  WaitForSingleObject [hProcess],
how and where I put it in the following code?

;-------------------------------------------------------------------------------
; Call a OpenFileDialog through a MACRO
; Select an EXE file
; Run it
; Displays some stuff when back.
;-------------------------------------------------------------------------------


include \masm32\include\masm32rt.inc

; -------------------------------------------------------------------------

.data

    ConTitle  db "  ----------     **  Example running an external prog  **     ----------", 0   


    CaptionText   BYTE  "Open Prog to Run",0

    szFilter      BYTE  "All files *.*",0,"*.*",0,
                        "Executable files *.exe",0,"*.exe",0,   
                        "Text files *.txt",0,"*.txt",0,
                        "Assembly files *.asm",0,"*.asm",0,
                        "Resource files *.rc",0,"*.rc",0,0
                       
; -------------------------------------------------------------------------

.data?

    hFile     HANDLE ?
    cci       CONSOLE_CURSOR_INFO <>       


    wHnd      HANDLE ?
    rHnd      HANDLE ?

    windowSize SMALL_RECT <>
    bufferSize COORD      <>
    startPoint COORD      <>

    howmany dd ?
    buffer  INPUT_RECORD <>     

    PtrFileName   DWORD ?   

    StartUpInfo STARTUPINFO <>
    ProcessInfo  PROCESS_INFORMATION <>         

.code

start:


; -------------------------------------------------------------------------

Main PROC

    CALL   InitProc

    CALL   ConsoleSize

    print " Press any key and choose the prog to run: ",13,10,13,10

    CALL   AnyKey   

    mov PtrFileName, OpenFileDlg (0,0, addr CaptionText, addr szFilter) 

    print " The chosen prog is: "

    print DWORD PTR PtrFileName, 13,10,13,10

    print " Press a key to run it ", 13,10,13,10

    CALL   AnyKey   
   
; -------------------------------------------------------------------------
; Here we call the selected prog to run
; -------------------------------------------------------------------------


    invoke memfill,ADDR StartUpInfo,SIZEOF StartUpInfo,0 ; fill STARTUPINFO
   
    mov StartUpInfo.cb,SIZEOF StartUpInfo ;

    INVOKE CreateProcess,DWORD PTR PtrFileName,0,0,0,0,0,0,0,ADDR StartUpInfo,ADDR ProcessInfo
   
; -------------------------------------------------------------------------

    CALL   InitProc

    CALL   ConsoleSize

    CALL   ClearScreen

    print " Back from the called prog", 13,10,13,10

    CALL   AnyKey 

    CALL   ShowTheCursor

    INVOKE ExitProcess,0

    ret

Main ENDP

; -------------------------------------------------------------------------   

ConsoleSize PROC

    INVOKE SetConsoleTitle, ADDR ConTitle
 
    CALL   HideTheCursor

    INVOKE SetConsoleWindowInfo, wHnd, TRUE, ADDR windowSize

    INVOKE SetConsoleScreenBufferSize, wHnd, DWORD PTR bufferSize

    ret

ConsoleSize ENDP

; -------------------------------------------------------------------------

ShowTheCursor PROC

    INVOKE GetConsoleCursorInfo,wHnd,addr cci
    mov cci.bVisible,TRUE
    INVOKE SetConsoleCursorInfo,wHnd,addr cci
    ret
   
ShowTheCursor ENDP

; -------------------------------------------------------------------------
   


HideTheCursor PROC

    INVOKE GetConsoleCursorInfo,wHnd,addr cci
    mov cci.bVisible,FALSE
    INVOKE SetConsoleCursorInfo,wHnd,addr cci
    ret
   
HideTheCursor ENDP

; -------------------------------------------------------------------------

InitProc PROC

    INVOKE AllocConsole

    INVOKE GetStdHandle, STD_INPUT_HANDLE
    mov rHnd,eax

    INVOKE GetStdHandle, STD_OUTPUT_HANDLE
    mov wHnd,eax 

    mov windowSize.Left, 0
    mov windowSize.Right, 79
    mov windowSize.Top, 0
    mov windowSize.Bottom, 24
   

    mov bufferSize.x, 80
    mov bufferSize.y, 25

    mov startPoint.x, 0
    mov startPoint.y, 0


    ret

InitProc ENDP


; -------------------------------------------------------------------------
;Returns: key code in buffer.KeyEvent.wVirtualKeyCode WORD size
; -------------------------------------------------------------------------

AnyKey PROC

again: 

    INVOKE ReadConsoleInput,rHnd,offset buffer,1,offset howmany
    cmp buffer.EventType,KEY_EVENT
    jnz again

    cmp buffer.KeyEvent.bKeyDown,0
    jz again

    ret

AnyKey ENDP


; -------------------------------------------------------------------------

ClearScreen proc

  ; -----------------------------------------------------------
  ; This procedure reads the column and row count, multiplies
  ; them together to get the number of characters that will fit
  ; onto the screen, writes that number of blank spaces to the
  ; screen, set the screen buffer attributes and reposition
  ; the prompt at position 0,0.
  ; -----------------------------------------------------------

    LOCAL hOutPut:DWORD
    LOCAL noc    :DWORD
    LOCAL cnt    :DWORD
    LOCAL sbi    :CONSOLE_SCREEN_BUFFER_INFO

    invoke GetStdHandle,STD_OUTPUT_HANDLE
    mov hOutPut, eax

    invoke GetConsoleScreenBufferInfo,hOutPut,ADDR sbi

    mov eax, sbi.dwSize     ; 2 word values returned for screen size

  ; -----------------------------------------------
  ; extract the 2 values and multiply them together
  ; -----------------------------------------------
    mov ecx, eax
    shr eax, 16
    mul cx
    mov cnt, eax

    invoke FillConsoleOutputCharacter, hOutPut, 32, cnt, NULL, ADDR noc

    movzx ecx,sbi.wAttributes
    invoke FillConsoleOutputAttribute, hOutPut, ecx, cnt, NULL, ADDR noc

    invoke SetConsoleCursorPosition, hOutPut, NULL

    ret

ClearScreen endp


; -------------------------------------------------------------------------
 
end start           



Frank
Mind is like a parachute. You know what to do in order to use it :-)

ToutEnMasm

Here a sample:
The called program can terminate or not with the end of the caller
Quote
invoke Execute_Independant_Win,NULL,NULL,SADR("notepad")

Quote
;################################################################
;----------------------------------------------------------------------------------------------------
Execute_Independant_Win proc hexeProg:DWORD ,NomProg:DWORD, Param:DWORD ;la ligne parametre addr
   ; processInfo   PROCESS_INFORMATION <> ;structure API
   ;---------- creer le process
   mov startInfo.cb,sizeof STARTUPINFO   
   invoke GetStartupInfo,ADDR startInfo
   invoke CreateProcess,hexeProg,Param,NULL,NULL,FALSE,\
      NORMAL_PRIORITY_CLASS,NULL,NULL,ADDR startInfo,ADDR processInfo
   .if eax == FALSE
   INVOKE     MessageBox, NULL,SADR("Execute_Independant_Win failed"),\
            SADR("CreateProcess Failed"), MB_YESNO
   .else
      ;indépendant
      invoke CloseHandle,processInfo.hProcess
      mov processInfo.hProcess,0
      invoke CloseHandle,processInfo.hThread
      mov processInfo.hThread,0
   .endif
   
FindeExecute_Independant_Win:
   ret
Execute_Independant_Win endp
;#########################################################################