Page 1 of 1

RunProgram, then send it a message?

Posted: Fri Oct 23, 2020 3:10 am
by Seymour Clufley
Is there a cross-platform way to make a command line utility stop? I have a Windows solution, in case anyone needs it:

Code: Select all

Structure RunProgramExtendedStructure
  ProgramID.i
  WindowHandle.i
EndStructure

Procedure.i EnumWindowsCallBack(hwnd.i, param.i)
  
  Protected *RunProgramExtended.RunProgramExtendedStructure
  
  Result.i = #True
  *RunProgramExtended = param
  If GetWindowThreadProcessId_(hwnd, @PID.i)
    If PID = *RunProgramExtended\ProgramID
      *RunProgramExtended\WindowHandle = hwnd
      Result = #False
    EndIf
  EndIf
  
  ProcedureReturn Result
  
EndProcedure



prog.i = RunProgram(exe,param,folder,#PB_Program_Open)

*Buffer = AllocateMemory(#MAX_PATH * SizeOf(Character), #PB_Memory_NoClear)
RunProgramExtended.RunProgramExtendedStructure\ProgramID = ProgramID(prog)

starttime.i = Date()
While ProgramRunning(prog)
  If RunProgramExtended\WindowHandle = 0
    EnumWindows_(@EnumWindowsCallBack(), @RunProgramExtended)
  EndIf
  
  If (Date()-starttime)>4 ; after 4 seconds, tell it to shut down
    PostMessage_(RunProgramExtended\WindowHandle,#WM_KEYDOWN,#VK_Q,0)
    PostMessage_(RunProgramExtended\WindowHandle,#WM_KEYUP,#VK_Q,0)
  EndIf
  Delay(50)
Wend

CloseProgram(prog)
but I'm wondering if there is a direct way to communicate with a program started using RunProgram, rather than faking keystrokes?

If not, are there equivalents of the keystroke code above, but for Mac and Linux?

Thank you.

Re: RunProgram, then send it a message?

Posted: Fri Oct 23, 2020 6:47 am
by infratec

Code: Select all

WriteProgramString()
Example:

Code: Select all

EnableExplicit


Structure RunProgramExtendedStructure
  ProgramID.i
  WindowHandle.i
EndStructure


Procedure.i EnumWindowsCallBack(hwnd.i, param.i)
 
  Protected Result.i, PID.l, Length.i, *RunProgramExtended.RunProgramExtendedStructure
 
 
  Result = #True
  *RunProgramExtended = param
  If GetWindowThreadProcessId_(hwnd, @PID)
    If PID = *RunProgramExtended\ProgramID
      *RunProgramExtended\WindowHandle = hwnd
      Result = #False
    EndIf
  EndIf
 
  ProcedureReturn Result
 
EndProcedure


Define Compiler.i, *Buffer, Length.i, Title$, NewTitle$, StartTime.i
Define RunProgramExtended.RunProgramExtendedStructure


Compiler = RunProgram("cmd","","", #PB_Program_Open | #PB_Program_Read | #PB_Program_Write)
If Compiler
 
  *Buffer = AllocateMemory(#MAX_PATH * SizeOf(Character), #PB_Memory_NoClear)
  If *Buffer
   
    RunProgramExtended\ProgramID = ProgramID(Compiler)
    
    StartTime = Date()
    
    While ProgramRunning(Compiler)
      
      If Date() - StartTime > 4
        StartTime = Date()
        WriteProgramStringN(Compiler, "exit")
      EndIf
      
      If RunProgramExtended\WindowHandle = 0
        EnumWindows_(@EnumWindowsCallBack(), @RunProgramExtended)
      Else
        Length = GetWindowText_(RunProgramExtended\WindowHandle, *Buffer, #MAX_PATH)
        If Length
          ;Debug Length
          NewTitle$ = PeekS(*Buffer, Length)
          If Title$ <> NewTitle$
            Title$ = NewTitle$
            Debug "Title: " + Title$
          EndIf
        EndIf
      EndIf
     
      Length = AvailableProgramOutput(Compiler)
      If Length
        If ReadProgramData(Compiler,*Buffer, Length)
          Debug PeekS(*Buffer, Length, #PB_UTF8|#PB_ByteLength)
        EndIf
      EndIf
    Wend
   
    FreeMemory(*Buffer)
  EndIf
 
  CloseProgram(Compiler) ; Close the connection to the program
EndIf

Re: RunProgram, then send it a message?

Posted: Fri Oct 23, 2020 1:13 pm
by Seymour Clufley
Thanks, Infratec. I can't believe I was looking through the Help file for ages this morning but somehow didn't see that command!

Re: RunProgram, then send it a message?

Posted: Fri Oct 23, 2020 2:15 pm
by Marc56us
On my PC Windows with PB 5.72 LTS
Works on x86 version but not on x64

Code: Select all

Waiting for executable to start...
Executable type: Windows - x64  (64bit, Unicode)
Executable started.
[ERROR] Line: 18
[ERROR] Invalid memory access. (read error at address 1074013176)
The Program was killed.
Line 18:

Code: Select all

    If PID = *RunProgramExtended\ProgramID
:(

Re: RunProgram, then send it a message?

Posted: Fri Oct 23, 2020 3:53 pm
by Shardik
Marc56us wrote:On my PC Windows with PB 5.72 LTS
Works on x86 version but not on x64
In

Code: Select all

EnumWindowsCallBack(hwnd.i, param.l)
you have to change param.l to param.i to work correctly with 32 and 64 bit... :wink:

Re: RunProgram, then send it a message?

Posted: Fri Oct 23, 2020 5:44 pm
by infratec
Yes that's right, I looked in the win32 API where it is declared as LongParam.
I changed the listing above.