Jump to content

Pass parameter to a running process


Recommended Posts

Instead of using hotkey I want to pass parameter from parent program to close the child program.
I try using Run($Exepath & ' True') & StdinWrite($pid, 'True') but it not closing the child program properly.

parent

;~~~~ parent
#include <GUIConstantsEx.au3>
#include <constants.au3>

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

Global $FName = 'Child.exe'
Global $Exepath = @ScriptDir & '\' & $FName
Global $pid

__gui1()

Func __gui1()
    Local $hGUI = GUICreate("Gui 1", 180, 150, 100, 100)
    Local $idButton1 = GUICtrlCreateButton("Start", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Stop", 10, 50, 80, 30)
    Local $idLabel = GUICtrlCreateLabel('', 10, 90, 80, 50 )
    Local $o_String

    GUICtrlSetState($idButton2, $GUI_DISABLE)
    GUISetState(@SW_SHOW, $hGUI)

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)
        Switch $aMsg[1]
            Case $hGUI
                Switch $aMsg[0]
                    Case $GUI_EVENT_CLOSE
                        ExitLoop

                    Case $idButton1
                        GUICtrlSetState($idButton1, $GUI_DISABLE)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                        GUICtrlSetData($idLabel, 'process start')

                        $o_String = ''
                        $pid = Run($Exepath, '', '', $STDIN_CHILD + $STDOUT_CHILD)
                        GUICtrlSetData($idLabel, $pid)

                    Case $idButton2
                        GUICtrlSetState($idButton1, $GUI_ENABLE)
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        GUICtrlSetData($idLabel, 'process stop')

                        Run($Exepath & ' True')
                        ;StdinWrite($pid, 'True')
                        
                        ;If ProcessExists($pid) Then
                            ;ProcessClose($pid)
                        ;Endif

                        $o_String = StdoutRead($pid)
                        ConsoleWrite( $o_String & @CRLF )

                EndSwitch
        EndSwitch
    WEnd
    GUIDelete($hGUI)
EndFunc

Child

;~~~~ Child
;~ Instead of using hotkey 
;~ I want to pass parameter from parent program
HotKeySet("{ESC}", "__Flag")

Global $bflag = False
__Example()

;If ($CmdLine[0] = 0) Then __Example()
;If StringInStr($CmdLine[1], 'True') Then __Flag()  ;not closing the program properly

Func __Example()
    Local $i = 0
    While 1
        If $bflag = True Then __Terminate()
        ConsoleWrite( $i & @CRLF )
        $i = $i + 1

        Sleep(250)
    WEnd
EndFunc   ;==>__Example

Func __Flag()
    ConsoleWrite( ' ' & $bflag & @CRLF )
    $bflag = True
    ConsoleWrite( ' ' & $bflag & @CRLF )
EndFunc   ;==> __Flag()

Func __Terminate()
    ConsoleWrite( ' The End ' & @CRLF )
    Exit
EndFunc   ;==> __Terminate()

 

Link to post
Share on other sites

@Subz Before posting I try using INI and that’s work.
Due to lack of coding knowledge I thought it’s possible to pass parameter to a running application using Run & StdinWrite function.

working code using INI as bridge....

parent

#include <GUIConstantsEx.au3>
#include <constants.au3>

Global $FName = 'Child.exe'
Global $Exepath = @ScriptDir & '\' & $FName
Global $__INIPath = @ScriptDir & "\IniFlag.ini"
Global $pid

__gui1()

Func __gui1()
    Local $hGUI = GUICreate("Gui 1", 180, 150, 100, 100)
    Local $idButton1 = GUICtrlCreateButton("Start", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Stop", 10, 50, 80, 30)
    Local $idLabel = GUICtrlCreateLabel('', 10, 90, 80, 50 )
    Local $o_String

    GUICtrlSetState($idButton2, $GUI_DISABLE)
    GUISetState(@SW_SHOW, $hGUI)

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)
        Switch $aMsg[1]
            Case $hGUI
                Switch $aMsg[0]
                    Case $GUI_EVENT_CLOSE
                        ExitLoop

                    Case $idButton1
                        GUICtrlSetState($idButton1, $GUI_DISABLE)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                        GUICtrlSetData($idLabel, 'process start')
                        IniWrite($__INIPath, "Flag_Param", "Child_flag", "False")

                        $o_String = ''
                        $pid = Run($Exepath, '', '', $STDIN_CHILD + $STDOUT_CHILD)

                    Case $idButton2
                        GUICtrlSetState($idButton1, $GUI_ENABLE)
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        GUICtrlSetData($idLabel, 'process stop')
                        IniWrite($__INIPath, "Flag_Param", "Child_flag", "True")
                        ProcessWait($FName)

                        $o_String = StdoutRead($pid)
                        ConsoleWrite( $o_String & @CRLF )

                EndSwitch
        EndSwitch
    WEnd

    GUIDelete($hGUI)
EndFunc

Child

;~~~~ Child
Global $bflag = False
__Example()

Func __Example()
    Local $__INIPath = @ScriptDir & "\IniFlag.ini"
    Local $o_String
    Local $i = 0
    While 1
        $o_String = IniRead($__INIPath, "Flag_Param", "Child_flag", "False")
        If StringInStr($o_String, "True") Then __Flag()
        If $bflag = True Then __Terminate()
        
        ConsoleWrite( $i & @CRLF )
        $i = $i + 1
        Sleep(250)
    WEnd
EndFunc   ;==>__Example

Func __Flag()
    ConsoleWrite( ' ' & $bflag & @CRLF )
    $bflag = True
    ConsoleWrite( ' ' & $bflag & @CRLF )
EndFunc   ;==> __Flag()

Func __Terminate()
    ConsoleWrite( ' The End ' & @CRLF )
    Exit
EndFunc   ;==> __Terminate()

@argumentum I haven’t look into your udf but I will try to make it work using your udf or _WM_COPYDATA.

Link to post
Share on other sites
Posted (edited)

WM_COPYDATA taken from @KaFu Enforce Single Instance of Program via WM_COPYDATA thread.

parent

#include <GUIConstantsEx.au3>
#include <constants.au3>

Global $TITLE_RECEIVER = 'Test_Child_Window'
global const $WM_COPYDATA = 0x004A
Global $FName = 'Child.exe'
Global $Exepath = @ScriptDir & '\' & $FName
Global $pid

__gui1()

Func __gui1()
    Local $h_Pidhwnd
    Local $hGUI = GUICreate("Gui 1", 180, 150, 100, 100)
    Local $idButton1 = GUICtrlCreateButton("Start", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Stop", 10, 50, 80, 30)
    Local $idLabel = GUICtrlCreateLabel('', 10, 90, 80, 50 )
    Local $o_String

    GUICtrlSetState($idButton2, $GUI_DISABLE)
    GUISetState(@SW_SHOW, $hGUI)

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)
        Switch $aMsg[1]
            Case $hGUI
                Switch $aMsg[0]
                    Case $GUI_EVENT_CLOSE
                        ExitLoop

                    Case $idButton1
                        GUICtrlSetState($idButton1, $GUI_DISABLE)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                        GUICtrlSetData($idLabel, 'process start')

                        $o_String = ''
                        $pid = Run($Exepath, '', '', $STDIN_CHILD + $STDOUT_CHILD)

                    Case $idButton2
                        GUICtrlSetState($idButton1, $GUI_ENABLE)
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        GUICtrlSetData($idLabel, 'process stop')
                        __WM_COPYDATA_SendData(WinGetHandle($TITLE_RECEIVER), 'True')

                        sleep(500)
                        $o_String = StdoutRead($pid)
                        ConsoleWrite( $o_String & @CRLF )

                EndSwitch
        EndSwitch
    WEnd

    GUIDelete($hGUI)
EndFunc   ;==>gui1


;https://www.autoitscript.com/forum/topic/106895-enforce-single-instance-of-program-via-wm_copydata/?do=findComment&comment=754297
Func __WM_COPYDATA_SendData($hWnd, $sData)
    If Not IsHWnd($hWnd) Then Return 0
    if $sData = "" then $sData = " "
    Local $tCOPYDATA, $tMsg
    $tMsg = DllStructCreate("char[" & StringLen($sData) + 1 & "]")
    DllStructSetData($tMsg, 1, $sData)
    $tCOPYDATA = DllStructCreate("ulong_ptr;dword;ptr")
    DllStructSetData($tCOPYDATA, 2, StringLen($sData) + 1)
    DllStructSetData($tCOPYDATA, 3, DllStructGetPtr($tMsg))
    $Ret = DllCall("user32.dll", "lparam", "SendMessage", "hwnd", $hWnd, "int", $WM_COPYDATA, "wparam", 0, "lparam", DllStructGetPtr($tCOPYDATA))
    If (@error) Or ($Ret[0] = -1) Then Return 0
    Return 1
EndFunc   ;==>_SendData

Child

;~~~~ Child
#include <WindowsConstants.au3>

Global $ChildGui
Global $TITLE_RECEIVER = 'Test_Child_Window'

Global $sMsg_Rcvd
Global $bflag = False
__Example()


Func __Example()
    $ChildGui = GUICreate($TITLE_RECEIVER, 200, 200)
    GUIRegisterMsg($WM_COPYDATA, '_WM_COPYDATA')
    GUISetState(@SW_HIDE)
    
    Local $i = 0
    While 1
        If StringInStr($sMsg_Rcvd, "True") Then __Flag()
        If $bflag = True Then __Terminate()
        
        ConsoleWrite( $i & @CRLF )
        $i = $i + 1
        Sleep(250)
    WEnd
EndFunc   ;==>__Example

Func __Flag()
    ConsoleWrite( ' ' & $bflag & @CRLF )
    $bflag = True
    ConsoleWrite( ' ' & $bflag & @CRLF )
EndFunc   ;==> __Flag()

Func __Terminate()
    ConsoleWrite( ' The End ' & @CRLF )
    GUIDelete($ChildGui)    ;<<<<<<<<<<
    Exit
EndFunc   ;==> __Terminate()


Func _WM_COPYDATA($hWnd, $msgID, $wParam, $lParam)
    Local $tCOPYDATA = DllStructCreate("ulong_ptr;dword;ptr", $lParam)
    Local $tMsg = DllStructCreate("char[" & DllStructGetData($tCOPYDATA, 2) & "]", DllStructGetData($tCOPYDATA, 3))
    $sMsg_Rcvd = DllStructGetData($tMsg, 1)
    Return 0
EndFunc   ;==>_WM_COPYDATA

@KaFu & @argumentum if have time do check if any error in code.

Is there any technique to receive message without using hidden gui in child ..... Thanks.

Edited by jugador
Link to post
Share on other sites

Using @trancexx mailslot

parent

#include <GUIConstantsEx.au3>
#include <constants.au3>

#include "MailSlot.au3"

Global Const $sMailSlotName = "\\.\mailslot\RandomNameForThisTest"
Global $FName = 'Child.exe'
Global $Exepath = @ScriptDir & '\' & $FName
Global $pid

__gui1()

Func __gui1()
    Local $hGUI = GUICreate("Gui 1", 180, 150, 100, 100)
    Local $idButton1 = GUICtrlCreateButton("Start", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Stop", 10, 50, 80, 30)
    Local $idLabel = GUICtrlCreateLabel('', 10, 90, 80, 50 )
    Local $o_String

    GUICtrlSetState($idButton2, $GUI_DISABLE)
    GUISetState(@SW_SHOW, $hGUI)

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)
        Switch $aMsg[1]
            Case $hGUI
                Switch $aMsg[0]
                    Case $GUI_EVENT_CLOSE
                        ExitLoop

                    Case $idButton1
                        GUICtrlSetState($idButton1, $GUI_DISABLE)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                        GUICtrlSetData($idLabel, 'process start')

                        $o_String = ''
                        $pid = Run($Exepath, '', '', $STDIN_CHILD + $STDOUT_CHILD)

                    Case $idButton2
                        GUICtrlSetState($idButton1, $GUI_ENABLE)
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        GUICtrlSetData($idLabel, 'process stop')
                        _MailSlotWrite($sMailSlotName, 'True')
                        If @error Then ExitLoop

                        sleep(500)
                        $o_String = StdoutRead($pid)
                        ConsoleWrite( $o_String & @CRLF )

                EndSwitch
        EndSwitch
    WEnd

    GUIDelete($hGUI)
EndFunc   ;==>gui1

Child

;~~~~ Child1
#include "MailSlot.au3"

Global Const $sMailSlotName = "\\.\mailslot\RandomNameForThisTest"
Global $hMailSlot = _MailSlotCreate($sMailSlotName)
If @error Then
    MsgBox(48 + 262144, "MailSlot", "Failed to create new account!" & @CRLF & "Probably one using that 'address' already exists.")
    Exit
EndIf

Global $bflag = False
__Example()

Func __Example()
    Local $iCount
    Local $iSize
    Local $sData
    
    Local $i = 0
    While 1
        $iCount = _MailSlotGetMessageCount($hMailSlot)
        If $iCount > 0 Then 
            $iSize = _MailSlotCheckForNextMessage($hMailSlot)
            ConsoleWrite( "$iSize: "  & $iSize & @CRLF )
            $sData = _MailSlotRead($hMailSlot, $iSize, 1)
            ConsoleWrite( "$sData: "  & $sData & @CRLF )
        Endif
        
        If StringInStr($sData, "True") Then __Flag()
        If $bflag = True Then __Terminate()
        
        ConsoleWrite( $i & @CRLF )
        $i = $i + 1
        Sleep(250)
    WEnd
EndFunc   ;==>__Example

Func __Flag()
    ConsoleWrite( ' ' & $bflag & @CRLF )
    $bflag = True
    ConsoleWrite( ' ' & $bflag & @CRLF )
EndFunc   ;==> __Flag()

Func __Terminate()
    ConsoleWrite( ' The End ' & @CRLF )
    _CloseMailAccount($hMailSlot)
    Exit
EndFunc   ;==> __Terminate()

Func _CloseMailAccount(ByRef $hHandle)
    If _MailSlotClose($hHandle) Then
        $hHandle = 0
        ConsoleWrite( "Account succesfully closed." & @CRLF )
    Else
        ConsoleWrite( "Account could not be closed!" & @CRLF )
    EndIf
EndFunc   ;==>_CloseMailAccount

 

Link to post
Share on other sites
2 hours ago, jugador said:

Kudos for actually doing the work and trying different approaches on your own.  Rare.

As for your initial attempt, I think you were pretty close;  the main prob i saw was that the Child was not reading from the Console and the Parent was not reading all the time from the child, and that you had commented out the StdOutWrite.

See if this works for you, my changes are noted in the margin:

Parent

;~~~~ parent
#include <GUIConstantsEx.au3>
#include <constants.au3>

#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****

Global $FName = 'Child.exe'
Global $Exepath = @ScriptDir & '\' & $FName
Global $pid

__gui1()

Func __gui1()
    Local $hGUI = GUICreate("Gui 1", 180, 150, 100, 100)
    Local $idButton1 = GUICtrlCreateButton("Start", 10, 10, 80, 30)
    Local $idButton2 = GUICtrlCreateButton("Stop", 10, 50, 80, 30)
    Local $idLabel = GUICtrlCreateLabel('', 10, 90, 80, 50 )
    Local $o_String

    GUICtrlSetState($idButton2, $GUI_DISABLE)
    GUISetState(@SW_SHOW, $hGUI)

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)
        Switch $aMsg[1]
            Case $hGUI
                Switch $aMsg[0]
                    Case $GUI_EVENT_CLOSE
                        ExitLoop

                    Case $idButton1
                        GUICtrlSetState($idButton1, $GUI_DISABLE)
                        GUICtrlSetState($idButton2, $GUI_ENABLE)
                        GUICtrlSetData($idLabel, 'process start')

                        $o_String = ''
                        $pid = Run($Exepath, '', '', $STDIN_CHILD + $STDOUT_CHILD)
                        GUICtrlSetData($idLabel, $pid)

                    Case $idButton2
                        GUICtrlSetState($idButton1, $GUI_ENABLE)
                        GUICtrlSetState($idButton2, $GUI_DISABLE)
                        GUICtrlSetData($idLabel, 'process stop')

                        ;Run($Exepath & ' True')              ;Jocko Delete
                        StdinWrite($pid, 'True')              ;Jocko Add

                        ;If ProcessExists($pid) Then
                            ;ProcessClose($pid)
                        ;Endif

                        ;$o_String = StdoutRead($pid)         ;Jocko Delete
                        ;ConsoleWrite( $o_String & @CRLF )    ;Jocko Delete
                EndSwitch
        EndSwitch

        $o_String = StdoutRead($pid)                          ;Jocko Add
        If $o_String Then ConsoleWrite( $o_String & @CRLF )   ;Jocko Add

    WEnd
    GUIDelete($hGUI)
EndFunc

Child

;~~~~ Child
;~ Instead of using hotkey
;~ I want to pass parameter from parent program
HotKeySet("{ESC}", "__Flag")

Global $bflag = False
__Example()

;If ($CmdLine[0] = 0) Then __Example()
;If StringInStr($CmdLine[1], 'True') Then __Flag()  ;not closing the program properly

Func __Example()
    Local $i = 0
    While 1
        If $bflag = True Then __Terminate()
        ConsoleWrite( $i & @CRLF )
        $i = $i + 1

        Sleep(250)
        If ConsoleRead()='True' Then __Flag()  ;Jocko Add
    WEnd

EndFunc   ;==>__Example

Func __Flag()
    ConsoleWrite( ' ' & $bflag & @CRLF )
    $bflag = True
    ConsoleWrite( ' ' & $bflag & @CRLF )
EndFunc   ;==> __Flag()

Func __Terminate()
    ConsoleWrite( ' The End ' & @CRLF )
    Exit
EndFunc   ;==> __Terminate()

 

Code hard, but don’t hard code...

Link to post
Share on other sites
Quote

StdoutRead() reads from the console standard output stream of a child process
ConsoleRead() is normally used by console applications to read input from a parent process.

@JockoDundee now I see my mistake after reading ConsoleRead in help file. I was using StdoutRead to read input from a parent process.

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...