Sign in to follow this  
Followers 0
Grosminet

IPC & _WinAPI_ReadProcessMemory issue

2 posts in this topic

Hi,

I'm blocked on a strange issue concerning the use of '_WinAPI_ReadProcessMemory' to retrieve one 'String' between 2 cooperating applications based on the IPC method using a private 'Windows Message' handler (thanks to '_WinAPI_RegisterWindowMessage').

Let's me explain what happens:

1) - From a small GUI 'ipc-sender' application, the user can type any string (like 'abcde') and click a 'Send Data' button to exchange this info with another small 'ipc-receiver' application. the coding is done in such way ( '_DumpStruct()' method) that a trace of the data sent is dumped in an edit viewer inside the GUI: see the 'ipc-sender' script source below -->

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=ipc_sender.exe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <GUIConstantsEx.au3>
#include <SendMessage.au3>
#include <MsgBoxConstants.au3>
#include <WinAPI.au3>
#include <WinAPISys.au3>
#include <ProcessConstants.au3>
#include <FontConstants.au3>
#include <GuiEdit.au3>
#include <ScrollBarsConstants.au3>
#include <Array.au3>

; Author : Grosminet

    Global Const $WM_IPC_PRIVATE_Grosminet = _WinAPI_RegisterWindowMessage('ipc_sender_to_receiver')
    Global Const $sAPP_me = "ipc_sender"
    Global Const $sAPP_other = "ipc_receiver"

    Global $guiw = 1000, $guih = 300, $guix = (@desktopwidth - $guiw - 50), $guiy = $guih + 150, $sp = 10, $x = $sp, $y = $sp, $w, $hbut = 28, $h
    Global $hParentGUI, $hSendBut, $hlocalPID, $hSendEdit, $hRecEdit
    Global $debug = true, $info, $PIDAppMe, $hOtherProcess
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    $hParentGui = GUICreate($sAPP_me, $guiw, $guih, $guix, $guiy)
    $w = ($guiw - 3*$sp) / 4
    $h = ($guih - 3* $sp) / 2
    $hSendBut = GUICtrlCreateButton("Send data", $x, $y, $w, $hbut)
    $y += $hbut + $sp
    $hlocalPID = GUIctrlCreateLabel("PID=", $x, $y, $w, $h)
    $x += $w + $sp
    $y = $sp
    $hSendEdit = GUIctrlCreateEdit("abcde", $x, $y, 3* $w, $h)
    $x = $sp
    $y += $h + $sp
    $hRecEdit = GUIctrlCreateEdit("", $x, $y, 4* $w, $h)
    GUICtrlSetFont(-1, 9, $FW_NORMAL, Default, "Courier New")
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    GUISetState(@SW_SHOW, $hParentGui)
    GUICtrlSetData($hlocalPID, "PID= " & @AutoItPID)
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    ; Get the RECEIVER application 'process handle'
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Opt("WinTitleMatchMode", 1)
    $hOtherProcess = WinGetHandle($sAPP_other)
    if @error then
        MsgBox($MB_SYSTEMMODAL, "ERROR", "Unable to retrieve handle of " & $sAPP_other & ", error= " & @error)
        exit
    endif
    $info = " Receiver application --> " & $sAPP_other & " - Handle= " & $hOtherProcess & @crlf
    _ShowInfo($info)
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                _myExit()
            Case $hSendBut
                _SendDATA_to_X()
        EndSwitch
    WEnd
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _SendDATA_to_X()
        Local $sValue_To_Send = GUICtrlRead($hSendEdit)
        Local $iStringSize = StringLen($sValue_To_Send) + 1
        local $TagInfoStruct = "struct;wchar buf[" & $iStringSize & "];endstruct"
        Local $tValue_To_Send = DllStructCreate($TagInfoStruct)
        DllStructSetData($tValue_To_Send, "buf", $sValue_To_Send)
        ;
        Local $pValue_To_Send = DllStructGetPtr($tValue_To_Send)
        Local $iSizeStruct = DllStructGetSize($tValue_To_Send)
        $info = '_SendDATA_to_X(): Pointer to text= ' & $pValue_To_Send & " - Size of text= " & $iStringSize  & " - Size of structure= " & $iSizeStruct & @CRLF
        _ShowInfo($info)
        $info = _DumpStruct($pValue_To_Send, $iSizeStruct)
        _ShowInfo($info)
        ;
        local $ret = _WinAPI_PostMessage($hOtherProcess, $WM_IPC_PRIVATE_Grosminet, $pValue_To_Send, $iSizeStruct)
        If not $ret Then
            MsgBox($MB_SYSTEMMODAL, "ERROR", "_SendDATA_to_X(): " & $sAPP_me & " --> _WinAPI_PostMessage error= " &  _WinAPI_GetLastError())
        else
            Local $sData_Sent = StringLeft(DllStructGetData($tValue_To_Send, "buf"), $iStringSize)
            $info = '................: --> Data sent = ' & $sData_Sent & @CRLF
            _ShowInfo($info)
        endif
        $pValue_To_Send = 0
        $tValue_To_Send = 0
    EndFunc   ;==>_SendDATA_to_X
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _ShowInfo($msg)
        if $debug then ConsoleWrite($msg)
        GUICtrlSetData($hRecEdit, GUICtrlRead($hRecEdit) & $msg)
        Local $iEnd = StringLen(GUICtrlRead($hRecEdit))
        _GUICtrlEdit_SetSel($hRecEdit, $iEnd, $iEnd)
        _GUICtrlEdit_Scroll($hRecEdit, $SB_SCROLLCARET)
    Endfunc ; _ShowInfo
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _myExit()
        GUIDelete()
        exit
    Endfunc ; _myExit
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _DumpStruct($p_STRUCT, $iSizeStruct)
        ; $iSizeStruct = the size of the struct in bytes (DllStructGetSize)
        
        Local $TagStructDump = "struct;align;byte[" & $iSizeStruct & "];endstruct"

        Local $t_Struct = DllStructCreate($TagStructDump, $p_STRUCT)
        Local $i
        Local $structInfo = ""
        _ConsoleWriteInfo($structInfo, "Structure size: " & $iSizeStruct & " byte(s):" & @crlf)
        for $i = 0 to $iSizeStruct - 1
            _ConsoleWriteInfo($structInfo, hex(DllStructGetData($t_Struct, 1, $i), 2) & " ")
            if (Mod($i+1, 8) = 0) then
                _ConsoleWriteInfo($structInfo, @CRLF)
            Endif
        Next
        _ConsoleWriteInfo($structInfo, @CRLF)
        return $structInfo
    EndFunc ; _DumpStruct
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _ConsoleWriteInfo(ByRef $msg, $txt)
        $msg &= $txt
    EndFunc ; _ConsoleWriteInfo

2) - From a small GUI 'ipc-receiver' application, the user can check the values of data received thanks to the same '_DumpStruct()' method: --> see the 'ipc-receiver' script :

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=ipc_receiver.exe
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#include <Array.au3>
#include <GUIConstantsEx.au3>
#include <SendMessage.au3>
#include <MsgBoxConstants.au3>
#include <WinAPI.au3>
#include <WinAPISys.au3>
#include <ProcessConstants.au3>
#include <FontConstants.au3>
#include <GuiEdit.au3>
#include <ScrollBarsConstants.au3>
#include <WinAPIDiag.au3>

; Author : Grosminet

    Global Const $WM_IPC_PRIVATE_Grosminet = _WinAPI_RegisterWindowMessage('ipc_sender_to_receiver')
    Global Const $sAPP_me = "ipc_receiver"
    Global Const $sAPP_other = "ipc_sender"
    Global Const $sSenderEXE = @scriptdir & "\" & $sAPP_other & ".exe"

    Global $guiw = 1000, $guih = 300, $guix = (@desktopwidth - $guiw - 50), $guiy = 100, $sp = 10, $x = $sp, $y = $sp, $w, $hbut = 28, $h
    Global $hParentGUI, $hlocalPID, $hRecEdit
    Global $debug = true, $info, $hProcessOther, $PIDAppMe, $PIDAppOther, $iRead, $aret
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    $hParentGui = GUICreate($sAPP_me, $guiw, $guih, $guix, $guiy)
    $w = ($guiw - 2*$sp)
    $hlocalPID = GUIctrlCreateLabel("PID=", $x, $y, $w, $hbut)
    $y += $hbut + $sp
    $h = ($guih - $y - $sp)
    $hRecEdit = GUIctrlCreateEdit("", $x, $y, $w, $h)
    GUICtrlSetFont(-1, 9, $FW_NORMAL, Default, "Courier New")
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    GUIRegisterMsg($WM_IPC_PRIVATE_Grosminet, 'WM_FROM_APP')
    GUISetState(@SW_SHOW, $hParentGui)
    GUICtrlSetData($hlocalPID, "PID= " & @AutoItPID)
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    ; Get the SENDER application 'pid'
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    $PIDAppOther = ShellExecute($sSenderEXE)
    if $PIDAppOther = -1 then
        MsgBox($MB_SYSTEMMODAL, "ERROR", "Unable to start " & $sAPP_other & " --> error= " & @error)
        exit
    Endif
    sleep(500)
    $info = "Ready to receive ! Please send a text ..." & @CRLF
    _ShowInfo($info)
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    ; Get the SENDER application 'process handle'
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    $hProcessOther = _WinAPI_OpenProcess($PROCESS_VM_READ, False, $PIDAppOther)
    if @error Then
        $info = "_WinAPI_OpenProcess() error: " & @error & @crlf
        _ShowInfo($info)
        exit
    endif
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                _myExit()
        EndSwitch
    WEnd
; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func WM_FROM_APP($hWnd, $iMsg, $wParam, $lParam)
        $info = "..... METHOD 1: _WinAPI_CreateBuffer ....." & @crlf
        _ShowInfo($info)
        _Method_1($wParam, $lParam)
        ;
        $info = "..... METHOD 2: DllStructCreate .........." & @crlf
        _ShowInfo($info)
        _Method_2($wParam, $lParam)
    EndFunc   ;==>WM_FROM_APP
; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _Method_1($wParam, $lParam)
        Local $iStrucSize_SENT = Int($lParam)
        Local $pBuffer = _WinAPI_CreateBuffer($iStrucSize_SENT)
        $aret = _WinAPI_ReadProcessMemory($hProcessOther, $wParam, $pBuffer, $iStrucSize_SENT, $iRead)
        ;
        $info = _DumpStruct($pBuffer, $iStrucSize_SENT)
        _ShowInfo($info)
        _ShowInfo(_WinAPI_GetString($pBuffer) & @crlf & "--------------------------------" & @crlf)
        _WinAPI_FreeMemory($pBuffer)
    EndFunc ; _Method_1
; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _Method_2($wParam, $lParam)
        Local $iStrucSize_SENT = Int($lParam)
        local $TagInfoStruct = "struct;align;byte buf[" & $iStrucSize_SENT & "];endstruct"
        Local $tbuffer = DllStructCreate($TagInfoStruct)
        Local $iSizeStruct = DllStructGetSize($tbuffer)
        Local $pBuffer = DllStructGetPtr($tbuffer)
        $aret = _WinAPI_ReadProcessMemory($hProcessOther, $wParam, $pBuffer, $iStrucSize_SENT, $iRead)
        ;
        $info = _DumpStruct($pBuffer, $iStrucSize_SENT)
        _ShowInfo($info)
        _ShowInfo(_WinAPI_GetString($pBuffer) & @crlf & "--------------------------------" & @crlf)
        $pBuffer = 0
    EndFunc ; _Method_2
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _ShowInfo($msg)
        if $debug then ConsoleWrite($msg)
        GUICtrlSetData($hRecEdit, GUICtrlRead($hRecEdit) & $msg)
        Local $iEnd = StringLen(GUICtrlRead($hRecEdit))
        _GUICtrlEdit_SetSel($hRecEdit, $iEnd, $iEnd)
        _GUICtrlEdit_Scroll($hRecEdit, $SB_SCROLLCARET)
    Endfunc ; _ShowInfo
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _myExit()
        _WinAPI_CloseHandle($hProcessOther)
        ProcessClose($PIDAppOther)
        GUIDelete()
        exit
    Endfunc ; _myExit
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _DumpStruct($p_STRUCT, $iSizeStruct)
        ; $iSizeStruct = the size of the struct in bytes (DllStructGetSize)
        
        Local $TagStructDump = "struct;align;byte[" & $iSizeStruct & "];endstruct"

        Local $t_Struct = DllStructCreate($TagStructDump, $p_STRUCT)
        Local $i
        Local $structInfo = ""
        _ConsoleWriteInfo($structInfo, "Structure size: " & $iSizeStruct & " byte(s):" & @crlf)
        for $i = 0 to $iSizeStruct - 1
            _ConsoleWriteInfo($structInfo, hex(DllStructGetData($t_Struct, 1, $i), 2) & " ")
            if (Mod($i+1, 8) = 0) then
                _ConsoleWriteInfo($structInfo, @CRLF)
            Endif
        Next
        _ConsoleWriteInfo($structInfo, @CRLF)
        return $structInfo
    EndFunc ; _DumpStruct
    ; ooooooooooooooooooooooooooooooooooooooooooooooooooooooo
    Func _ConsoleWriteInfo(ByRef $msg, $txt)
        $msg &= $txt
    EndFunc ; _ConsoleWriteInfo

The ISSUE : systematically, the 3 first bytes received are 'corrupted' !!! ???

NOTE: You must repeat several times sending the same string to check that  bytes sent" and "bytes received"  are equal EXCEPT the 3 first ones !

I'm quite sure that my code is somewhere wrong ! BUT I'm not able to discover myself WHERE ! I have tried to use 2 methods to read and save the external memory bytes (using the '_WinAPI_CreateBuffer' function, and the 'DllStructCreate' function) --> BOTH give me back the same issue.

--> So I suspect that my understanding of the '_WinAPI_ReadProcessMemory' function is maybe wrong and I do not correctly call this API.

??? Is it correct if I say, [according the MSDN 's ReadProcessMemory explanation or the #include <WinAPI.au3> library code of this function] :

- the base address of memory to be read is the pointer received from my private WM handler --> i.e. $wParam (regarding my script receiver code)

- the buffer pointer where to save bytes read (starting from $wParam) is the pointer created using '_WinAPI_CreateBuffer' or 'DllStructCreate + DllStructGetPtr' functions

- the number of bytes to be read is the information provided by the $lParam variable (regarding my script receiver code)

- AND of course, the external memory base-address will only be readable if the 'ipc-sender' application handler is correctly declared ($hProcessOther = _WinAPI_OpenProcess($PROCESS_VM_READ, False, $PIDAppOther)).

There is probably other methods to share strings between cooperating applications, and surely more simple and elegant ones, BUT I'm focusing on these scripts where in fact the types of data to share are not limited to the 'String' type, but could concern any kind of structure.

Any advice or help to explain me what happens would be welcome.

Great Thanks in advance for your time passed to help me...

Alain.

These are my environment characteristics:

AutoIT : 3.3.14.2

OS: Windows 7 Home Premium Service Pack 1 / 7601

 

 

ipc_receiver.au3

ipc_sender.au3

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

Hi,

No reply  ??? ...

Well, I have found this post : brainstorming-ipc-string-exchange, where "GUINNESS" indicates : ' Well I personally think WM_COPYDATA is an elegant solution ...'

So I will follow this advice and post later the corresponding results: ... first trials seems OK ...

I still be curious about the issue described previously !

Alain.

Here are the final scripts:

receiver.au3

sender.au3

Edited by Grosminet
Adding last results.

Share this post


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
Sign in to follow this  
Followers 0

  • Similar Content

    • dubi
      Interprocess communcation breaks down with StdinWrite and StdoutRead
      By dubi
      Hi,


       
      Background: i have a number of instances of the same application that I want to automate in parallel.

      Unfortunately, I cannot completely automate these instances in the background. So, from time to time these instances need to have the focus so that I can interact with the controls via “send” directly.

      Each of the application instances is controlled by a au3 complied script. Each script (called with a parameter) manages the automation of the respective application-instance. Each of the (complied) script (instances) is called by a (central) front end with a gui. The front end controls if the “focus” is available to do the “send” and “mouseclick” modifications. The central front end either allows a child to have the focus or prevents it to get the focus (in which case the child will wait and checks again). The code for the front end is included. Apologies for the lengthy explanation.


      #RequireAdmin #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include <EditConstants.au3> #include <GUIEdit.au3> #include <ScrollBarConstants.au3> #include <Array.au3> Global Const $APF_ALLOWMULTILINE = 1 Global Const $APF_RIGHTALIGN = 6 Global Const $APF_RIGHTALIGNCOL = 2 Global Const $APF_RIGHTALIGNDATA = 4 Global Const $APF_PRINTROWNUM = 8 Global Const $APF_DEFAULT = $APF_PRINTROWNUM Global $PID[9], $FocusAvailable = True, $previousEditMsg Global $PID_waiting[0][2], $logfile $logfile = "D:\MultiInstance\Logfiles\FrontEnd.txt" If FileExists($logfile) Then FileDelete($logfile) #Region ### START Koda GUI section ### Form= $hGui_1 = GUICreate("Instanzenmanager", 493, 1226, 1807, 93) $grpInst1 = GUICtrlCreateGroup(" 1 ", 8, 8, 233, 121) $btnPause01 = GUICtrlCreateCheckbox("Pause", 16, 64, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop01 = GUICtrlCreateCheckbox("Stop", 16, 96, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin01 = GUICtrlCreateCheckbox("Minimize", 72, 64, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh01 = GUICtrlCreateCheckbox("Restore", 144, 64, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart01 = GUICtrlCreateCheckbox("Start", 16, 32, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateGroup("", -99, -99, 1, 1) $grpInst3 = GUICtrlCreateGroup(" 3 ", 8, 136, 233, 121) $btnPause03 = GUICtrlCreateCheckbox("Pause", 16, 192, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop03 = GUICtrlCreateCheckbox("Stop", 16, 224, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin03 = GUICtrlCreateCheckbox("Minimize", 72, 192, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh03 = GUICtrlCreateCheckbox("Restore", 144, 192, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart03 = GUICtrlCreateCheckbox("Start", 16, 160, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateGroup("", -99, -99, 1, 1) $grpInst2 = GUICtrlCreateGroup(" 2 ", 248, 8, 233, 121) $btnPause02 = GUICtrlCreateCheckbox("Pause", 256, 64, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop02 = GUICtrlCreateCheckbox("Stop", 256, 96, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin02 = GUICtrlCreateCheckbox("Minimize", 312, 64, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh02 = GUICtrlCreateCheckbox("Restore", 384, 64, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart02 = GUICtrlCreateCheckbox("Start", 256, 32, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) GUICtrlCreateGroup("", -99, -99, 1, 1) $grpInst4 = GUICtrlCreateGroup(" 4 ", 248, 136, 233, 121) $btnPause04 = GUICtrlCreateCheckbox("Pause", 256, 192, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $tbnStop04 = GUICtrlCreateCheckbox("Stop", 256, 224, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnMin04 = GUICtrlCreateCheckbox("Minimize", 312, 192, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnWdh04 = GUICtrlCreateCheckbox("Restore", 384, 192, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStart04 = GUICtrlCreateCheckbox("Start", 256, 160, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUICtrlSetBkColor(-1, 0x00FF00) $Edit1 = GUICtrlCreateEdit("", 8, 720, 473, 497) $btnPauseAll = GUICtrlCreateCheckbox("Pause all", 8, 656, 474, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) $btnStopAll = GUICtrlCreateCheckbox("Stop all", 7, 688, 474, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE)) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 CheckGuiMsg() FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & "CheckGuiMsg" & @CRLF) CheckClientMessages() FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & "CheckClientMessages" & @CRLF) WEnd Func CheckGuiMsg() $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $btnStart01 AddTextToEdit("Starting Instance 1") $PID[0] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 1", @ScriptDir, Default, 3) Case $btnStart02 AddTextToEdit("Starting Instance 2") $PID[1] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 2", @ScriptDir, Default, 3) Case $btnStart03 AddTextToEdit("Starting Instance 3") $PID[2] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 3", @ScriptDir, Default, 3) Case $btnStart04 AddTextToEdit("Starting Instance 4") $PID[3] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 4", @ScriptDir, Default, 3) Case $btnPause01 AddTextToEdit("Send Pause to Instance 1") StdinWrite($PID[0], "Pause") Case $btnPause02 StdinWrite($PID[1], "Pause") Case $btnPause03 StdinWrite($PID[2], "Pause") Case $btnPause04 StdinWrite($PID[3], "Pause") Case $tbnStop01 StdinWrite($PID[0], "Stop") Case $tbnStop02 StdinWrite($PID[1], "Stop") Case $tbnStop03 StdinWrite($PID[2], "Stop") Case $tbnStop04 StdinWrite($PID[3], "Stop") Case $btnPauseAll AddTextToEdit(@CRLF & "************Pause All not yet implemented**************" & @CRLF) Case $btnStopAll AddTextToEdit(@CRLF & "************Stop All not yet implemented***************" & @CRLF) EndSwitch EndFunc ;==>CheckGuiMsg Func CheckClientMessages() For $i = 0 To 3 FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & $i & @CRLF) Local $a = TimerInit() $p = $PID[$i] $streamRead = StdoutRead($p) If $streamRead <> "" Then Switch $streamRead Case StringInStr($streamRead, "Focus Needed") > 0 If $FocusAvailable Then $FocusAvailable = False StdinWrite($p, "Focus Granted") Else EndIf Case StringInStr($streamRead, "Release Focus") > 0 StdinWrite($p, "Release Focus Received") $FocusAvailable = True Case Else EndSwitch EndIf FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & $i & " " & round(TimerDiff($a),2) & @CRLF) Next EndFunc ;==>CheckClientMessages Func AddTextToEdit($text) If $previousEditMsg <> $text Then $previousEditMsg = $text GUICtrlSetData($Edit1, GUICtrlRead($Edit1) & @YEAR & "." & @MON & "." & @MDAY & " - " & @HOUR & ":" & @MIN & ":" & @SEC & "> " & $text & @CRLF) _GUICtrlEdit_Scroll($Edit1, $SB_SCROLLCARET) EndIf EndFunc ;==>AddTextToEdit



      My issue now is that the mechanism with with StdoutRead and StdinWrite is not efficient at all. The more instances I start the slower it gets. This is not just a bit slower (like a fraction of a second), but to the degree that the front end is not responding at all any longer (with 3 instances handling).

      So my questions are:

      1.       Is there a flaw in my implementation with StdoutRead and StdinWrite? (note that all works fine with 1 and also (slower) with 2 instances running) but actually breaks down with 3 instances running.

      2.       Can I optimize the currently used implementation so that I can control 30+ instances?

      3.       What other implementation do you see suitable for this approach?

      a.       I have already tried it with communication through files but observed that this is not sufficiently reliable with multiple instances.

      b.       Is Named Pipes a more performant approach (I am a bit scared of the effort to learn and implement this)

      c.       Any other method?


       
      Many thanks in advance

      -dubi





    • RTFC
      Pool - Post Office for Organised Labour
      By RTFC
      Pool provides multiple AutoIt processes with an infrastructure for exchanging messages, data, and remote-control instructions, on a single machine or on a local area network. It is modelled partly on HTCondor, but also incorporates user-defined messages (UDM), LANchat, mails, data Container shipping management, and remote power control and remote execution. That last feature means one process can send lines of AutoIt script to another process, and run it there (including batch control and synchronisation). Consider it my take on inter-process communication (IPC).
       
      Pool incorporates many contributions (a few are included in the bundle, other tiny snippets are part of the main script), from other forum members without whom this project simply would never even have been conceivable. In particular, I hereby want to acknowledge the excellent work of Zatorg, wraithdu, W0uter, Ward, ValeryVal, spudw2k, trancexx, This-is-Me, Nomad, Nine, Manadar, LazyCat, Lakes, Kip, Kealper, Jos, Greencan, FredAI, evilertoaster, dragan, Chimp, and AdamUL. Some codes merely helped to clarify my novice understanding of various IPC issues, others have been gratefully integrated. Three contributors need special mention: Kip & Zatorg for event-driven TCP, and trancexx for MailSlot; together these form the backbone of everything else. The only reason I still dare to publish this under my own name is because I did add over ten thousand lines of code myself. Nevertheless, Pool may serve as a showcase for how various members' example scripts can be combined into a comprehensive environment. Many, many thanks to everyone involved!
       
      Pool is designed to be simple to use. Only a few functions are public, and of those, you really only need to study these four control UDFs:
      _Pool_Send_Command(): Pool's Command & Control Centre (see list of commands below)
      _Pool_Send_UserDefinedMsg(): define your own outgoing msgs
      _Pool_Receive_UserDefinedMsg(): process your own incoming msgs
      _Pool_Send_ExeQcall(): send one or more AutoIt instructions to target's Exe-Queue (ExeQ)
       
      and these ones for data transfers:
      _Pool_Container_Create(): associate shipping Container with data
      _Pool_Container_Destroy(): release Container memory and all associated Sharing relations
      _Pool_Container_CreateShare(): associate destination with Container
      _Pool_Container_DestroyShare(): dissolve sharing association for destination
       
      To get an idea of what _Pool_Send_Command() can do, here's the list of commands:
       
       

       
      Pool is big. It has got many dozens of fixed and dynamic user-defined settings to create specific applications with (see #Region Globals). Please take the time to read the extensive Remarks section at the top of the main script (Pool.au3), including the warnings and limitations. Furthermore, I've provided two example environments in the subdir Examples in the bundle: CLNtest (messages and remote execution) and CLNmaster + CLNslave (data Container shipping). If you run these on a single machine, you'll need to start PostOffice_Solo; on multiple machines, one should start first with PostOffice_Server, the rest with PostOffice_Client, once the Server is initialised. See the readme.txt in the Examples subdir for additional help. Another example (multi-processing a la Condor) is shipped with release 2.4+ of Eigen4AutoIt.
      Since this is an Example script, you can find a number of interesting design ideas in Pool:
       
       
       
       Pool.v0.7.7z Pool bundle, second beta release, version 0.7
        IMPORTANT CAVEAT 
      This is an experimental beta release. Some parts of Pool have never been tested, others only in the simplest possible setting (the largest network I ever tested comprised one desktop and three laptops (one with busted radio) on a crappy Wifi router; I've never tested it on a cabled network). The (W)LAN part still has many issues and may not be able to handle more than a few machines. There's no callstack error handler. Event-driven TCP remains glitchy, and some of my MailSlots keep malfunctioning. I also lack access to Windows 8.* test environments.
      In addition, many issues you may encounter will be due to specific timings/event sequencing (which makes it hard to debug) and/or your specific infrastructure. That means that, most likely, I cannot recreate your Pool bugs (even with your scripts), so I cannot fix them either. Therefore, I will not be offering bug support for users at this point; there's still far too much I need to fix in my own environment to worry about yours, I'm sorry (also, I've been working on this for four months flat, and need a break from it). However, I am of course open to suggestions, remarks, criticism, and kind words (preferably the latter ).
      Finally, I will be exceptionally busy with work for the foreseeable future, so it may take me more time than in the past to respond to your posts.
      Have fun playing in the Pool.
    • Ward
      Guess the setup up string of DLLStruct
      By Ward
      I am trying to serialize all the autoit variable by >msgpack, so that I can used it in ZeroRPC (language-agnostic remote procedure call over internet). Int, string, binary are easy, but DllStruct is not. Before variable serialization become build-in function (I hope so), I have to find out my own way.
       
      Here is my attempt to guess the setup string. I am not sure did I deal with all the align and struct/endstruct correctly, please let me know if there is any bug. The output may not be the same with the original string, it is not bug.
       
       
      Test() Func Test() Local $Struct $Struct = DllStructCreate("align 2;byte;ptr[2]") ConsoleWrite(DLLStructAnalyze($Struct) & @LF) ; Output: byte;align 2;ptr[2] $Struct = DllStructCreate("int;struct;struct;uint64;uint;byte[5];endstruct;byte;endstruct;byte") ConsoleWrite(DLLStructAnalyze($Struct) & @LF) ; Output: int;struct;struct;uint64;uint;byte[5];endstruct;byte;endstruct;byte $Struct = DllStructCreate("int;uint64;struct;struct;uint;byte[5];endstruct;byte;endstruct;byte") ConsoleWrite(DLLStructAnalyze($Struct) & @LF) ; Output: int;uint64;struct;struct;uint;byte[5];endstruct;byte;endstruct;byte EndFunc  



    • mLipok
      IPC and ScriptControl
      By mLipok
      I looked at ScriptControl.
      I wonder if using this, can I do IPC solution in AutoIt. I also wonder whether some extent, ScirptControl can be compared to the use of LUA.  
      Below is what I have read so far.
      http://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx
      http://support.microsoft.com/kb/184739/EN-US
      http://msdn.microsoft.com/en-us/library/aa227413(v=vs.60).aspx
      http://www.microsoft.com/en-us/download/details.aspx?id=1949
      '?do=embed' frameborder='0' data-embedContent>>
      '?do=embed' frameborder='0' data-embedContent>>
      '?do=embed' frameborder='0' data-embedContent>>
       
      btw.
      Please, share with other interesting links that according to you is worth reading on the subject (links not directly related to the AutoIt).
    • timmy2
      Need help using WM_CopyData to pass values
      By timmy2
      The following is a script from Eukalyptus that plays an audio file and displays an FFT Visualization. Let's call it the "Child".
      My goal is to be able to close it AND to send volume-level change commands from a Parent program (script farther below). I'm trying to use WM_CopyData for IPC but it's not working for me. Part of my problem is I'm unsure about what's needed to initialize WM_CopyData in the Parent program -- if this is even necessary.  I realize I could use the MailSlot UDF for this but would like to give WM_CopyData a go first, based on Guinness's recommendation. Once I get WM_CopyData working I might even try to use it to close the Child program.
      Other issues I'm unsure about are:
      1. can I send decimal values via WM_CopyData_Send() ?  (BASS_SetVolume() needs values between 0 and 1)
      2. at the receiving end in the Child am I using the proper variable type and format for BASS_SetVolume()?
       
      "Child" (must be compiled and named "FFT-Viz-WM_CopyData" so Parent can run it)
      #AutoIt3Wrapper_UseX64=n #include "Bass.au3" #include "BassExt.au3" #include <GDIPlus.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> #include 'WM_COPYDATA.au3' Opt("MustDeclareVars", 1) _WM_COPYDATA_SetID('MyUniqueID') ; set ID for WM_CopyData Global $sFile = FileOpenDialog("Open...", "..\audiofiles", "playable formats (*.MP3;*.MP2;*.MP1;*.OGG;*.WAV;*.AIFF;*.AIF)") If @error Or Not FileExists($sFile) Then Exit Global $iWidth = 522 Global $iHeight = 170 Global $hGui = GUICreate("FFT", $iWidth, $iHeight, -1, -1, BitOR($WS_SYSMENU, $WS_POPUP)) GUISetOnEvent($GUI_EVENT_CLOSE, "_EXIT") _GDIPlus_Startup() Global $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGui) Global $hBmp_Buffer = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Global $hGfx_Buffer = _GDIPlus_ImageGetGraphicsContext($hBmp_Buffer) _GDIPlus_GraphicsSetSmoothingMode($hGfx_Buffer, 2) Global $hBrush = _CreateFFTBrush(5, 5, $iWidth - 10, $iHeight - 10) GUIRegisterMsg($WM_PAINT, "WM_PAINT") GUISetState() _BASS_Startup() _BASS_EXT_Startup() _BASS_Init(0, -1, 44100, 0, "") Global $hStream = _BASS_StreamCreateFile(False, $sFile, 0, 0, $BASS_SAMPLE_FLOAT) Global $aFFT = _BASS_EXT_CreateFFT(128, 5, 5, $iWidth - 10, $iHeight - 10, 1, True) _BASS_ChannelPlay($hStream, True) Local $iControlID = _WM_COPYDATA_Start($hGui) ; Start the communication process. Global $iTimer = TimerInit() While _BASS_ChannelIsActive($hStream) If TimerDiff($iTimer) > 20 Then Switch GuiGetMsg() Case -3 ; allows Parent program to use WinClose to close this program. ExitLoop Case $iControlID ; if the Parent program sends a volume change value via WM_CopyData Local $volumelevel = _WM_COPYDATA_GetData() _BASS_SetVolume($volumelevel) Beep(1000, 100) ; for testing purposes to see if this Case ever gets triggered EndSwitch $iTimer = TimerInit() _GDIPlus_GraphicsClear($hGfx_Buffer, 0xFF110022) _BASS_EXT_ChannelGetFFT($hStream, $aFFT, 2) If Not @error Then DllCall($ghGDIPDll, "int", "GdipFillPolygon", "handle", $hGfx_Buffer, "handle", $hBrush, "ptr", $aFFT[0], "int", $aFFT[1], "int", "FillModeAlternate") _GDIPlus_GraphicsDrawImage($hGraphics, $hBmp_Buffer, 0, 0) EndIf WEnd _Exit() Func _CreateFFTBrush($iX, $iY, $iWidth, $iHeight) Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight) Local $hContext = _GDIPlus_ImageGetGraphicsContext($hBitmap) Local $hBrush_FFT = _GDIPlus_LineBrushCreate(0, 0, 0, $iHeight, 0, 0, 3) Local $aColors[5][2] = [[4]] $aColors[1][0] = 0xFFFF0000 $aColors[1][1] = 0 $aColors[2][0] = 0xFFFFAA00 $aColors[2][1] = 0.25 $aColors[3][0] = 0xFF00AAFF $aColors[3][1] = 0.5 $aColors[4][0] = 0xFF00AAFF $aColors[4][1] = 1 _GDIPlus_LineBrushSetPresetBlend($hBrush_FFT, $aColors) Local $hBrush_LED = _GDIPlus_LineBrushCreate(0, 0, 0, 4, 0xAA000000, 0x00000000, 0) _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iWidth, $iHeight, $hBrush_FFT) _GDIPlus_GraphicsFillRect($hContext, 0, 0, $iWidth, $iHeight, $hBrush_LED) _GDIPlus_BrushDispose($hBrush_LED) _GDIPlus_BrushDispose($hBrush_FFT) _GDIPlus_GraphicsDispose($hContext) Local $hBrush = _GDIPlus_TextureCreate($hBitmap) _GDIPlus_BitmapDispose($hBitmap) DllCall($ghGDIPDll, "uint", "GdipTranslateTextureTransform", "hwnd", $hBrush, "float", $iX, "float", $iY, "int", 0) Return $hBrush EndFunc ;==>_CreateFFTBrush Func WM_PAINT($hWnd, $uMsgm, $wParam, $lParam) _GDIPlus_GraphicsDrawImage($hGraphics, $hBmp_Buffer, 0, 0) Return $GUI_RUNDEFMSG EndFunc ;==>WM_PAINT ; #FUNCTION# ==================================================================================================================== ; Author ........: Authenticity ; Modified.......: UEZ ; =============================================================================================================================== Func _GDIPlus_BitmapCreateFromScan0($iWidth, $iHeight, $iPixelFormat = $GDIP_PXF32ARGB, $iStride = 0, $pScan0 = 0) Local $aResult = DllCall($ghGDIPDll, "uint", "GdipCreateBitmapFromScan0", "int", $iWidth, "int", $iHeight, "int", $iStride, "int", $iPixelFormat, "ptr", $pScan0, "handle*", 0) If @error Then Return SetError(@error, @extended, 0) If $aResult[0] Then Return SetError(10, $aResult[0], 0) Return $aResult[6] EndFunc ;==>_GDIPlus_BitmapCreateFromScan0 ; #FUNCTION# ==================================================================================================================== ; Author ........: Authenticity ; Modified.......: UEZ ; =============================================================================================================================== Func _GDIPlus_LineBrushCreate($nX1, $nY1, $nX2, $nY2, $iARGBClr1, $iARGBClr2, $iWrapMode = 0) Local $tPointF1, $tPointF2, $aResult $tPointF1 = DllStructCreate("float;float") $tPointF2 = DllStructCreate("float;float") DllStructSetData($tPointF1, 1, $nX1) DllStructSetData($tPointF1, 2, $nY1) DllStructSetData($tPointF2, 1, $nX2) DllStructSetData($tPointF2, 2, $nY2) $aResult = DllCall($ghGDIPDll, "int", "GdipCreateLineBrush", "struct*", $tPointF1, "struct*", $tPointF2, "uint", $iARGBClr1, "uint", $iARGBClr2, "int", $iWrapMode, "handle*", 0) If @error Then Return SetError(@error, @extended, 0) If $aResult[0] Then Return SetError(10, $aResult[0], 0) Return $aResult[6] EndFunc ;==>_GDIPlus_LineBrushCreate ; #FUNCTION# ==================================================================================================================== ; Author ........: Authenticity ; Modified.......: UEZ ; =============================================================================================================================== Func _GDIPlus_LineBrushSetPresetBlend($hLineGradientBrush, $aInterpolations) Local $iI, $iCount, $tColors, $tPositions, $aResult $iCount = $aInterpolations[0][0] $tColors = DllStructCreate("uint[" & $iCount & "]") $tPositions = DllStructCreate("float[" & $iCount & "]") For $iI = 1 To $iCount DllStructSetData($tColors, 1, $aInterpolations[$iI][0], $iI) DllStructSetData($tPositions, 1, $aInterpolations[$iI][1], $iI) Next $aResult = DllCall($ghGDIPDll, "int", "GdipSetLinePresetBlend", "handle", $hLineGradientBrush, "struct*", $tColors, "struct*", $tPositions, "int", $iCount) If @error Then Return SetError(@error, @extended, False) If $aResult[0] Then Return SetError(10, $aResult[0], False) Return True EndFunc ;==>_GDIPlus_LineBrushSetPresetBlend ; #FUNCTION# ==================================================================================================================== ; Author ........: Authenticity ; Modified.......: UEZ ; =============================================================================================================================== Func _GDIPlus_TextureCreate($hImage, $iWrapMode = 0) Local $aResult = DllCall($ghGDIPDll, "int", "GdipCreateTexture", "handle", $hImage, "int", $iWrapMode, "handle*", 0) If @error Then Return SetError(@error, @extended, 0) If $aResult[0] Then Return SetError(10, $aResult[0], 0) Return $aResult[3] EndFunc ;==>_GDIPlus_TextureCreate Func _Exit() _BASS_StreamFree($hStream) _BASS_Free() _WM_COPYDATA_Shutdown() _GDIPlus_BrushDispose($hBrush) _GDIPlus_GraphicsDispose($hGfx_Buffer) _GDIPlus_BitmapDispose($hBmp_Buffer) _GDIPlus_GraphicsDispose($hGraphics) _GDIPlus_Shutdown() Exit EndFunc ;==>_Exit And here's the Parent program, which you can run from SciTE.
      #include "ExtMsgBox.au3" #Include <WinAPIEx.au3> #include 'WM_COPYDATA.au3' ;_WM_COPYDATA_SetID('MyUniqueIDC') ; NOT SURE IF I NEED THIS ;Local $iControlID = _WM_COPYDATA_Start(Default) ; Start the communication process. NOT SURE IF I NEED THIS $wPID = run ("FFT-Viz-WM_CopyData.exe") sleep(2000) _ExtMsgBox(0,0,"","press enter to reduce volume",0,1,1) _WM_COPYDATA_Send(.2) ;can WM_CopyData send values like this or must they be strings? _ExtMsgBox(0,0,"","press enter to raise volume",0,1,1) _WM_COPYDATA_Send(1) _ExtMsgBox(0,0,"","press enter to exit",0,1,1) $aData = _WinAPI_EnumProcessWindows ($wPID) ConsoleWrite($aData[1][0] & @LF) Sleep(2000) $result = WinClose($aData[1][0]) ConsoleWrite ("winclose issued! Result = " & $result & @LF) sleep (2000) ;_WM_COPYDATA_Shutdown() ;NOT SURE IF I NEED THIS Exit