Jump to content

Need help with IPC Broadcast


Go to solution Solved by this-is-me,

Recommended Posts

Hey guys. It's been a very long time since I've been here, and I need a little help.

I am trying to make an IPC between a main script and multiple children scripts. I would like the main script to gather information, and broadcast that information in string form to the children scripts. I prefer that the children scripts be able to have a main loop that is not always checking for messages, but that children scripts can receive messages in an event-based manner. This would exclude using mailslots and UDP, with which I am familiar, since using them would require each child to have a loop that checks for messages. I will not need this information to go across a network, just between scripts on the same computer.

I read about one person who said he used RegisterWindowMessage and PostMessage to do this >here. Unfortunately, he did not provide any example code, and a search for something of the kind is unfruitful.

Would one of you be kind enough to post example code of sending/retrieving strings with a broadcast?
Thanks.

Who else would I be?
Link to comment
Share on other sites

>This might be what you're looking for.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

I'm sorry to say that the WM_COPYDATA idea won't work for me in its current form (based on the example provided) since it can't allow multiple "clients". WM_COPYDATA (as far as I understand) requires a single window to send the message to. Therefore, I can't have multiple clients.

Who else would I be?
Link to comment
Share on other sites

  • Moderators

this-is-me,

This post came up when I searched for RegisterWindowMessage and seems pretty clear on how to use it to me. ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

this-is-me,

This post came up when I searched for RegisterWindowMessage and seems pretty clear on how to use it to me. ;)

M23

Melba23, Thanks a lot for your information. After piecing together the code in the post you mentioned, converting it to HWND_BROADCAST and fixing NomadMemory.au3 for Windows 7 x64 using >this information, I was able to get it working with no problems!

I will hope to post some cleaned-up code here later so that others can see what to do. When I do, I will mark my own example code as solved, even though the credit goes to you, martin and cooleko.

Who else would I be?
Link to comment
Share on other sites

I currently use stdin/out streams to manage multiple processes.

If partially functions as you want.

The primary process tells it's data to all sub-processes.

And each sub process can respond to the main process.

However each sub-process must have it's own function to check for new data and process it. (my script uses headers/footers to sort data into commands and send them between processes)

There's currently no limit tot he amount of data that can be sent and it's very fast.

It could probably even be modified to work on event, but I wouldn't go through the work of doing this.

If you are interested I will make an example using streams and headers, showing 1 main process communicating with 2 child processes. 

Link to comment
Share on other sites

I'm sorry to say that the WM_COPYDATA idea won't work for me in its current form (based on the example provided) since it can't allow multiple "clients". WM_COPYDATA (as far as I understand) requires a single window to send the message to. Therefore, I can't have multiple clients.

Yes and no, if you want you can manage multiple clients a little bit like TCP (each client will have a unique identifier).

Br, FireFox.

Link to comment
Share on other sites

  • Solution

Now, bear in mind that this code does EXACTLY what I wanted, which is to have a one-way communication mechanism between a master script and multiple children scripts. To that end, these scripts have been modified as necessary. It can be modified to perform two-way communication, but I will leave that to the reader.

First, we have NomadMemory.au3, modified for compatibility with the latest version of AutoIt and 64-bit compatibility as described >here.

NomadMemory.au3

#include-once
#include <SecurityConstants.au3>
#region _Memory
;==================================================================================
; AutoIt Version:   3.1.127 (beta)
; Language:   English
; Platform:   All Windows
; Author:         Nomad
; Requirements:  These functions will only work with beta.
;==================================================================================
; Credits:  wOuter - These functions are based on his original _Mem() functions.
;         But they are easier to comprehend and more reliable.  These
;         functions are in no way a direct copy of his functions.  His
;         functions only provided a foundation from which these evolved.
;==================================================================================
;
; Functions:
;
;==================================================================================
; Function:   _MemoryOpen($iv_Pid[, $iv_DesiredAccess[, $iv_InheritHandle]])
; Description:    Opens a process and enables all possible access rights to the
;               process.  The Process ID of the process is used to specify which
;               process to open.  You must call this function before calling
;               _MemoryClose(), _MemoryRead(), or _MemoryWrite().
; Parameter(s):  $iv_Pid - The Process ID of the program you want to open.
;               $iv_DesiredAccess - (optional) Set to 0x1F0FFF by default, which
;                              enables all possible access rights to the
;                              process specified by the Process ID.
;               $iv_InheritHandle - (optional) If this value is TRUE, all processes
;                              created by this process will inherit the access
;                              handle.  Set to 1 (TRUE) by default.  Set to 0
;                              if you want it FALSE.
; Requirement(s):   None.
; Return Value(s):  On Success - Returns an array containing the Dll handle and an
;                         open handle to the specified process.
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $iv_Pid.
;                      2 = Failed to open Kernel32.dll.
;                      3 = Failed to open the specified process.
; Author(s):        Nomad
; Note(s):
;==================================================================================
Func _MemoryOpen($iv_Pid, $iv_DesiredAccess = 0x1F0FFF, $iv_InheritHandle = 1)

    If Not ProcessExists($iv_Pid) Then
        SetError(1)
        Return 0
    EndIf

    Local $ah_Handle[2] = [DllOpen('kernel32.dll')]

    If @Error Then
        SetError(2)
        Return 0
    EndIf

    Local $av_OpenProcess = DllCall($ah_Handle[0], 'int', 'OpenProcess', 'int', $iv_DesiredAccess, 'int', $iv_InheritHandle, 'int', $iv_Pid)

    If @Error Then
        DllClose($ah_Handle[0])
        SetError(3)
        Return 0
    EndIf

    $ah_Handle[1] = $av_OpenProcess[0]

    Return $ah_Handle

EndFunc

;==================================================================================
; Function:   _MemoryRead($iv_Address, $ah_Handle[, $sv_Type])
; Description:    Reads the value located in the memory address specified.
; Parameter(s):  $iv_Address - The memory address you want to read from. It must
;                          be in hex format (0x00000000).
;               $ah_Handle - An array containing the Dll handle and the handle
;                         of the open process as returned by _MemoryOpen().
;               $sv_Type - (optional) The "Type" of value you intend to read.
;                        This is set to 'dword'(32bit(4byte) signed integer)
;                        by default.  See the help file for DllStructCreate
;                        for all types.  An example: If you want to read a
;                        word that is 15 characters in length, you would use
;                        'char[16]' since a 'char' is 8 bits (1 byte) in size.
; Return Value(s):  On Success - Returns the value located at the specified address.
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $ah_Handle.
;                      2 = $sv_Type was not a string.
;                      3 = $sv_Type is an unknown data type.
;                      4 = Failed to allocate the memory needed for the DllStructure.
;                      5 = Error allocating memory for $sv_Type.
;                      6 = Failed to read from the specified process.
; Author(s):        Nomad
; Note(s):      Values returned are in Decimal format, unless specified as a
;               'char' type, then they are returned in ASCII format.  Also note
;               that size ('char[size]') for all 'char' types should be 1
;               greater than the actual size.
;==================================================================================
Func _MemoryRead($iv_Address, $ah_Handle, $sv_Type = 'dword')

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf

    Local $v_Buffer = DllStructCreate($sv_Type)

    If @Error Then
        SetError(@Error + 1)
        Return 0
    EndIf

    DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')

    If Not @Error Then
        Local $v_Value = DllStructGetData($v_Buffer, 1)
        Return $v_Value
    Else
        SetError(6)
        Return 0
    EndIf

EndFunc

Func _NewMemRead($Addr1, $Proc1, $type1)
   If $type1 = "int" Then ;I only used int, if you use uint or any other integer representation, add them in here
      Return (Dec(Hex(StringRegExpReplace(_MemoryRead($Addr1, $Proc1, $type1), "00000000", "", 1))))
   Else
      Return _MemoryRead($Addr1, $Proc1, $type1)
   EndIf
EndFunc   ;==>_NewMemRead

;==================================================================================
; Function:   _MemoryWrite($iv_Address, $ah_Handle, $v_Data[, $sv_Type])
; Description:    Writes data to the specified memory address.
; Parameter(s):  $iv_Address - The memory address which you want to write to.
;                          It must be in hex format (0x00000000).
;               $ah_Handle - An array containing the Dll handle and the handle
;                         of the open process as returned by _MemoryOpen().
;               $v_Data - The data to be written.
;               $sv_Type - (optional) The "Type" of value you intend to write.
;                        This is set to 'dword'(32bit(4byte) signed integer)
;                        by default.  See the help file for DllStructCreate
;                        for all types.  An example: If you want to write a
;                        word that is 15 characters in length, you would use
;                        'char[16]' since a 'char' is 8 bits (1 byte) in size.
; Return Value(s):  On Success - Returns 1
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $ah_Handle.
;                      2 = $sv_Type was not a string.
;                      3 = $sv_Type is an unknown data type.
;                      4 = Failed to allocate the memory needed for the DllStructure.
;                      5 = Error allocating memory for $sv_Type.
;                      6 = $v_Data is not in the proper format to be used with the
;                         "Type" selected for $sv_Type, or it is out of range.
;                      7 = Failed to write to the specified process.
; Author(s):        Nomad
; Note(s):      Values sent must be in Decimal format, unless specified as a
;               'char' type, then they must be in ASCII format.  Also note
;               that size ('char[size]') for all 'char' types should be 1
;               greater than the actual size.
;==================================================================================
Func _MemoryWrite($iv_Address, $ah_Handle, $v_Data, $sv_Type = 'dword')

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf

    Local $v_Buffer = DllStructCreate($sv_Type)

    If @Error Then
        SetError(@Error + 1)
        Return 0
    Else
        DllStructSetData($v_Buffer, 1, $v_Data)
        If @Error Then
            SetError(6)
            Return 0
        EndIf
    EndIf

    DllCall($ah_Handle[0], 'int', 'WriteProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')

    If Not @Error Then
        Return 1
    Else
        SetError(7)
        Return 0
    EndIf

EndFunc

;==================================================================================
; Function:   _MemoryClose($ah_Handle)
; Description:    Closes the process handle opened by using _MemoryOpen().
; Parameter(s):  $ah_Handle - An array containing the Dll handle and the handle
;                         of the open process as returned by _MemoryOpen().
; Return Value(s):  On Success - Returns 1
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $ah_Handle.
;                      2 = Unable to close the process handle.
; Author(s):        Nomad
; Note(s):
;==================================================================================
Func _MemoryClose($ah_Handle)

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf

    DllCall($ah_Handle[0], 'int', 'CloseHandle', 'int', $ah_Handle[1])
    If Not @Error Then
        DllClose($ah_Handle[0])
        Return 1
    Else
        DllClose($ah_Handle[0])
        SetError(2)
        Return 0
    EndIf

EndFunc

;==================================================================================
; Function:   SetPrivilege( $privilege, $bEnable )
; Description:    Enables (or disables) the $privilege on the current process
;                   (Probably) requires administrator privileges to run
;
; Author(s):        Larry (from autoitscript.com's Forum)
; Notes(s):
; http://www.autoitscript.com/forum/index.ph...st&p=223999
;==================================================================================

Func SetPrivilege( $privilege, $bEnable )
    ;Const $TOKEN_ADJUST_PRIVILEGES = 0x0020
    ;Const $TOKEN_QUERY = 0x0008
    ;Const $SE_PRIVILEGE_ENABLED = 0x0002
    Local $hToken, $SP_auxret, $SP_ret, $hCurrProcess, $nTokens, $nTokenIndex, $priv
    $nTokens = 1
    $LUID = DLLStructCreate("dword;int")
    If IsArray($privilege) Then    $nTokens = UBound($privilege)
    $TOKEN_PRIVILEGES = DLLStructCreate("dword;dword[" & (3 * $nTokens) & "]")
    $NEWTOKEN_PRIVILEGES = DLLStructCreate("dword;dword[" & (3 * $nTokens) & "]")
    $hCurrProcess = DLLCall("kernel32.dll","hwnd","GetCurrentProcess")
    $SP_auxret = DLLCall("advapi32.dll","int","OpenProcessToken","hwnd",$hCurrProcess[0],   _
            "int",BitOR($TOKEN_ADJUST_PRIVILEGES,$TOKEN_QUERY),"int*",0)
    If $SP_auxret[0] Then
        $hToken = $SP_auxret[3]
        DLLStructSetData($TOKEN_PRIVILEGES,1,1)
        $nTokenIndex = 1
        While $nTokenIndex <= $nTokens
            If IsArray($privilege) Then
                $priv = $privilege[$nTokenIndex-1]
            Else
                $priv = $privilege
            EndIf
            $ret = DLLCall("advapi32.dll","int","LookupPrivilegeValue","str","","str",$priv,   _
                    "ptr",DLLStructGetPtr($LUID))
            If $ret[0] Then
                If $bEnable Then
                    DLLStructSetData($TOKEN_PRIVILEGES,2,$SE_PRIVILEGE_ENABLED,(3 * $nTokenIndex))
                Else
                    DLLStructSetData($TOKEN_PRIVILEGES,2,0,(3 * $nTokenIndex))
                EndIf
                DLLStructSetData($TOKEN_PRIVILEGES,2,DllStructGetData($LUID,1),(3 * ($nTokenIndex-1)) + 1)
                DLLStructSetData($TOKEN_PRIVILEGES,2,DllStructGetData($LUID,2),(3 * ($nTokenIndex-1)) + 2)
                DLLStructSetData($LUID,1,0)
                DLLStructSetData($LUID,2,0)
            EndIf
            $nTokenIndex += 1
        WEnd
        $ret = DLLCall("advapi32.dll","int","AdjustTokenPrivileges","hwnd",$hToken,"int",0,   _
                "ptr",DllStructGetPtr($TOKEN_PRIVILEGES),"int",DllStructGetSize($NEWTOKEN_PRIVILEGES),   _
                "ptr",DllStructGetPtr($NEWTOKEN_PRIVILEGES),"int*",0)
        $f = DLLCall("kernel32.dll","int","GetLastError")
    EndIf
    $NEWTOKEN_PRIVILEGES=0
    $TOKEN_PRIVILEGES=0
    $LUID=0
    If $SP_auxret[0] = 0 Then Return 0
    $SP_auxret = DLLCall("kernel32.dll","int","CloseHandle","hwnd",$hToken)
    If Not $ret[0] And Not $SP_auxret[0] Then Return 0
    return $ret[0]
EndFunc   ;==>SetPrivilege

;=================================================================================================
; Function:   _MemoryPointerRead ($iv_Address, $ah_Handle, $av_Offset[, $sv_Type])
; Description:    Reads a chain of pointers and returns an array containing the destination
;               address and the data at the address.
; Parameter(s):  $iv_Address - The static memory address you want to start at. It must be in
;                          hex format (0x00000000).
;               $ah_Handle - An array containing the Dll handle and the handle of the open
;                         process as returned by _MemoryOpen().
;               $av_Offset - An array of offsets for the pointers.  Each pointer must have an
;                         offset.  If there is no offset for a pointer, enter 0 for that
;                         array dimension.
;               $sv_Type - (optional) The "Type" of data you intend to read at the destination
;                         address.  This is set to 'dword'(32bit(4byte) signed integer) by
;                         default.  See the help file for DllStructCreate for all types.
; Requirement(s):   The $ah_Handle returned from _MemoryOpen.
; Return Value(s):  On Success - Returns an array containing the destination address and the value
;                         located at the address.
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = $av_Offset is not an array.
;                      2 = Invalid $ah_Handle.
;                      3 = $sv_Type is not a string.
;                      4 = $sv_Type is an unknown data type.
;                      5 = Failed to allocate the memory needed for the DllStructure.
;                      6 = Error allocating memory for $sv_Type.
;                      7 = Failed to read from the specified process.
; Author(s):        Nomad
; Note(s):      Values returned are in Decimal format, unless a 'char' type is selected.
;               Set $av_Offset like this:
;               $av_Offset[0] = NULL (not used)
;               $av_Offset[1] = Offset for pointer 1 (all offsets must be in Decimal)
;               $av_Offset[2] = Offset for pointer 2
;               etc...
;               (The number of array dimensions determines the number of pointers)
;=================================================================================================
Func _MemoryPointerRead($iv_Address, $ah_Handle, $av_Offset, $sv_Type = 'dword')

    If IsArray($av_Offset) Then
        If IsArray($ah_Handle) Then
            Local $iv_PointerCount = UBound($av_Offset) - 1
        Else
            SetError(2)
            Return 0
        EndIf
    Else
        SetError(1)
        Return 0
    EndIf

    Local $iv_Data[2], $i
    Local $v_Buffer = DllStructCreate('dword')

    For $i = 0 To $iv_PointerCount

        If $i = $iv_PointerCount Then
            $v_Buffer = DllStructCreate($sv_Type)
            If @error Then
                SetError(@error + 2)
                Return 0
            EndIf

            $iv_Address = '0x' & Hex($iv_Data[1] + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @error Then
                SetError(7)
                Return 0
            EndIf

            $iv_Data[1] = DllStructGetData($v_Buffer, 1)

        ElseIf $i = 0 Then
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @error Then
                SetError(7)
                Return 0
            EndIf

            $iv_Data[1] = DllStructGetData($v_Buffer, 1)

        Else
            $iv_Address = '0x' & Hex($iv_Data[1] + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @error Then
                SetError(7)
                Return 0
            EndIf

            $iv_Data[1] = DllStructGetData($v_Buffer, 1)

        EndIf

    Next

    $iv_Data[0] = $iv_Address

    Return $iv_Data

EndFunc   ;==>_MemoryPointerRead



;=================================================================================================
; Function:         _MemoryPointerWrite ($iv_Address, $ah_Handle, $av_Offset, $v_Data[, $sv_Type])
; Description:      Reads a chain of pointers and writes the data to the destination address.
; Parameter(s):     $iv_Address - The static memory address you want to start at. It must be in
;                                 hex format (0x00000000).
;                   $ah_Handle - An array containing the Dll handle and the handle of the open
;                                process as returned by _MemoryOpen().
;                   $av_Offset - An array of offsets for the pointers.  Each pointer must have an
;                                offset.  If there is no offset for a pointer, enter 0 for that
;                                array dimension.
;                   $v_Data - The data to be written.
;                   $sv_Type - (optional) The "Type" of data you intend to write at the destination
;                                address.  This is set to 'dword'(32bit(4byte) signed integer) by
;                                default.  See the help file for DllStructCreate for all types.
; Requirement(s):   The $ah_Handle returned from _MemoryOpen.
; Return Value(s):  On Success - Returns the destination address.
;                   On Failure - Returns 0.
;                   @Error - 0 = No error.
;                            1 = $av_Offset is not an array.
;                            2 = Invalid $ah_Handle.
;                            3 = Failed to read from the specified process.
;                            4 = $sv_Type is not a string.
;                            5 = $sv_Type is an unknown data type.
;                            6 = Failed to allocate the memory needed for the DllStructure.
;                            7 = Error allocating memory for $sv_Type.
;                            8 = $v_Data is not in the proper format to be used with the
;                                "Type" selected for $sv_Type, or it is out of range.
;                            9 = Failed to write to the specified process.
; Author(s):        Nomad
; Note(s):          Data written is in Decimal format, unless a 'char' type is selected.
;                   Set $av_Offset like this:
;                   $av_Offset[0] = NULL (not used, doesn't matter what's entered)
;                   $av_Offset[1] = Offset for pointer 1 (all offsets must be in Decimal)
;                   $av_Offset[2] = Offset for pointer 2
;                   etc...
;                   (The number of array dimensions determines the number of pointers)
;=================================================================================================

Func _MemoryPointerWrite ($iv_Address, $ah_Handle, $av_Offset, $v_Data, $sv_Type = 'dword')

    If IsArray($av_Offset) Then
        If IsArray($ah_Handle) Then
            Local $iv_PointerCount = UBound($av_Offset) - 1
        Else
            SetError(2)
            Return 0
        EndIf
    Else
        SetError(1)
        Return 0
    EndIf

    Local $iv_StructData, $i
    Local $v_Buffer = DllStructCreate('dword')

    For $i = 0 to $iv_PointerCount
        If $i = $iv_PointerCount Then
            $v_Buffer = DllStructCreate($sv_Type)
            If @Error Then
                SetError(@Error + 3)
                Return 0
            EndIf

            DllStructSetData($v_Buffer, 1, $v_Data)
            If @Error Then
                SetError(8)
                Return 0
            EndIf

            $iv_Address = '0x' & hex($iv_StructData + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'WriteProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @Error Then
                SetError(9)
                Return 0
            Else
                Return $iv_Address
            EndIf
        ElseIf $i = 0 Then
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @Error Then
                SetError(3)
                Return 0
            EndIf

            $iv_StructData = DllStructGetData($v_Buffer, 1)

        Else
            $iv_Address = '0x' & hex($iv_StructData + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @Error Then
                SetError(3)
                Return 0
            EndIf

            $iv_StructData = DllStructGetData($v_Buffer, 1)

        EndIf
    Next

EndFunc


;===================================================================================================

; Function........:  _MemoryGetBaseAddress($ah_Handle, $iHD)
;
; Description.....:  Reads the 'Allocation Base' from the open process.
;
; Parameter(s)....:  $ah_Handle - An array containing the Dll handle and the handle of the open
;                               process as returned by _MemoryOpen().
;                    $iHD - Return type:
;                       |0 = Hex (Default)
;                       |1 = Dec
;
; Requirement(s)..:  A valid process ID.
;
; Return Value(s).:  On Success - Returns the 'allocation Base' address and sets @Error to 0.
;                    On Failure - Returns 0 and sets @Error to:
;                  |1 = Invalid $ah_Handle.
;                  |2 = Failed to find correct allocation address.
;                  |3 = Failed to read from the specified process.
;
; Author(s).......:  Nomad. Szhlopp.
; URL.............:  http://www.autoitscript.com/forum/index.php?showtopic=78834
; Note(s).........:  Go to Www.CheatEngine.org for the latest version of CheatEngine.
;===================================================================================================

Func _MemoryGetBaseAddress($ah_Handle, $iHexDec = 0)

    Local $iv_Address = 0x00100000
    Local $v_Buffer = DllStructCreate('dword;dword;dword;dword;dword;dword;dword')
    Local $vData
    Local $vType

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf


    DllCall($ah_Handle[0], 'int', 'VirtualQueryEx', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer))

    If Not @Error Then

        $vData = Hex(DllStructGetData($v_Buffer, 2))
        $vType = Hex(DllStructGetData($v_Buffer, 3))

        While $vType <> "00000080"
            DllCall($ah_Handle[0], 'int', 'VirtualQueryEx', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer))
            $vData = Hex(DllStructGetData($v_Buffer, 2))
            $vType = Hex(DllStructGetData($v_Buffer, 3))
            If Hex($iv_Address) = "01000000" Then ExitLoop
            $iv_Address += 65536

        WEnd

        If $vType = "00000080" Then
            SetError(0)
            If $iHexDec = 1 Then
                Return Dec($vData)
            Else
                Return $vData
            EndIf

        Else
            SetError(2)
            Return 0
        EndIf

    Else
        SetError(3)
        Return 0
    EndIf

EndFunc   ;==>_MemoryGetBaseAddress
#EndRegion

Second, we have a little UDF I put together for my purposes.

IPCLib.au3

#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <APISysConstants.au3>
#include <NomadMemory.au3>

Global $IPC_MNum, $IPC_Func

Func IPC_Register($ipcname = Default, $type = "Server", $function = "")
    If $ipcname = Default Then $ipcname = "IPC_Default_Name"
    If $type = "Client" Then GUICreate("") ;We have to have a "top-level" window for HWND_BROADCAST to work.
    $IPC_MNum = _WinAPI_RegisterWindowMessage($ipcname)
    Switch $type
        Case "Server"
            IPC_Notify()
            AdlibRegister("IPC_Notify", 3000) ;Register with children every 3 seconds
        Case "Client"
            $IPC_Func = $function
            GUIRegisterMsg($IPC_MNum, "IPC_GetInfo")
    EndSwitch
EndFunc

Func IPC_Broadcast($sOut)
    ;put the string in a struct
    Local Static $IPC_Temp = DllStructCreate('char[' & StringLen($sOut) + 1 & ']')
    DllStructSetData($IPC_Temp, 1, $sOut)

    ;create another struct for the address of the first struct and the length of the string
    Local Static $IPC_MsgStruct = DllStructCreate("int;int")
    DllStructSetData($IPC_MsgStruct, 1, DllStructGetPtr($IPC_Temp))
    DllStructSetData($IPC_MsgStruct, 2, StringLen($sOut) + 1)

    _WinAPI_PostMessage($HWND_BROADCAST, $IPC_MNum, 2, DllStructGetPtr($IPC_MsgStruct))
EndFunc   ;==>IPC_Broadcast

Func IPC_Notify()
    _WinAPI_PostMessage($HWND_BROADCAST, $IPC_MNum, 1, @AutoItPID)
EndFunc

Func IPC_GetInfo($hWnd, $MsgID, $Wparam, $LParam)
    Local $DataAdd, $DataLen, $Data, $hMem
    Local Static $IPC_PID
    Switch $Wparam
        Case 1 ;we're being told the PID
            $IPC_PID = Number($LParam)
        Case 2 ;$LParam is the address of the struct
            If $IPC_PID = "" Then Return
            $hMem = _MemoryOpen($IPC_PID)
            ;$LParam is the address of the struct
            $DataAdd = _NewMemRead($LParam, $hMem, "int")
            $DataLen = _NewMemRead(IPC_AddrCalc($LParam, 4), $hMem, "int")
            $Data = _NewMemRead(IPC_AddrCalc($DataAdd, 0), $hMem, "char[" & $DataLen & "]")
            $IPC_Func($Data)
    EndSwitch
EndFunc   ;==>IPC_GetInfo

Func IPC_AddrCalc($StartAddr, $Offset)
    Return '0x' & Hex(Number($StartAddr) + $Offset, 8)
EndFunc   ;==>IPC_AddrCalc 

And, finally we have example scripts. First is Receive.au3. Run this one first. You may have as many copies of this script running as necessary.

Receive.au3

#include <IPCLib.au3>
IPC_Register(Default, "Client", Alert) ;Register as a client, sending received messages to the alert function

While 1
    Sleep(1000)
WEnd

Func Alert($str)
    MsgBox(0,"",$str)
EndFunc

And Finally, the "Server" or sending part. In practice, you can IPC_Broadcast($Messages) as often as you like, and all the children scripts will respond as necessary.

Send.au3

#include <IPCLib.au3>
IPC_Register() ;Register as a Server, AKA Sender.
IPC_Broadcast("Hello to another script")
While 1
    Sleep(1000)
WEnd

Credits for all this goes to martin, cooleko, Nomad and Melba23.

I have simply modified the scripts for my usages. I did, however, notice and fix a bug along the way. The IPC_Broadcast function was a modified version of martin's SendString function. In his function, the dll structures were local to the function, and therefore temporary. As soon as SendString exited, the structures were destroyed. This is fine with SendMessage, since this function appears to wait until the message is received. However, when used with PostMessage and HWND_BROADCAST (which does not appear to wait), the function destroyed the dll structures before the children scripts were able to access them. Therefore, I simply made those structures Global. Thanks to JohnOne, I have modified the script to use Local Static for the Dll Structures, which allows those structures to remain in memory until the function is called again.

Edited by this-is-me
Who else would I be?
Link to comment
Share on other sites

Now, bear in mind that this code does EXACTLY what I wanted, which is to have a one-way communication mechanism between a master script and multiple children scripts. To that end, these scripts have been modified as necessary. It can be modified to perform two-way communication, but I will leave that to the reader.

First, we have NomadMemory.au3, modified for compatibility with the latest version of AutoIt and 64-bit compatibility as described >here.

NomadMemory.au3

#include-once
#include <SecurityConstants.au3>
#region _Memory
;==================================================================================
; AutoIt Version:   3.1.127 (beta)
; Language:   English
; Platform:   All Windows
; Author:         Nomad
; Requirements:  These functions will only work with beta.
;==================================================================================
; Credits:  wOuter - These functions are based on his original _Mem() functions.
;         But they are easier to comprehend and more reliable.  These
;         functions are in no way a direct copy of his functions.  His
;         functions only provided a foundation from which these evolved.
;==================================================================================
;
; Functions:
;
;==================================================================================
; Function:   _MemoryOpen($iv_Pid[, $iv_DesiredAccess[, $iv_InheritHandle]])
; Description:    Opens a process and enables all possible access rights to the
;               process.  The Process ID of the process is used to specify which
;               process to open.  You must call this function before calling
;               _MemoryClose(), _MemoryRead(), or _MemoryWrite().
; Parameter(s):  $iv_Pid - The Process ID of the program you want to open.
;               $iv_DesiredAccess - (optional) Set to 0x1F0FFF by default, which
;                              enables all possible access rights to the
;                              process specified by the Process ID.
;               $iv_InheritHandle - (optional) If this value is TRUE, all processes
;                              created by this process will inherit the access
;                              handle.  Set to 1 (TRUE) by default.  Set to 0
;                              if you want it FALSE.
; Requirement(s):   None.
; Return Value(s):  On Success - Returns an array containing the Dll handle and an
;                         open handle to the specified process.
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $iv_Pid.
;                      2 = Failed to open Kernel32.dll.
;                      3 = Failed to open the specified process.
; Author(s):        Nomad
; Note(s):
;==================================================================================
Func _MemoryOpen($iv_Pid, $iv_DesiredAccess = 0x1F0FFF, $iv_InheritHandle = 1)

    If Not ProcessExists($iv_Pid) Then
        SetError(1)
        Return 0
    EndIf

    Local $ah_Handle[2] = [DllOpen('kernel32.dll')]

    If @Error Then
        SetError(2)
        Return 0
    EndIf

    Local $av_OpenProcess = DllCall($ah_Handle[0], 'int', 'OpenProcess', 'int', $iv_DesiredAccess, 'int', $iv_InheritHandle, 'int', $iv_Pid)

    If @Error Then
        DllClose($ah_Handle[0])
        SetError(3)
        Return 0
    EndIf

    $ah_Handle[1] = $av_OpenProcess[0]

    Return $ah_Handle

EndFunc

;==================================================================================
; Function:   _MemoryRead($iv_Address, $ah_Handle[, $sv_Type])
; Description:    Reads the value located in the memory address specified.
; Parameter(s):  $iv_Address - The memory address you want to read from. It must
;                          be in hex format (0x00000000).
;               $ah_Handle - An array containing the Dll handle and the handle
;                         of the open process as returned by _MemoryOpen().
;               $sv_Type - (optional) The "Type" of value you intend to read.
;                        This is set to 'dword'(32bit(4byte) signed integer)
;                        by default.  See the help file for DllStructCreate
;                        for all types.  An example: If you want to read a
;                        word that is 15 characters in length, you would use
;                        'char[16]' since a 'char' is 8 bits (1 byte) in size.
; Return Value(s):  On Success - Returns the value located at the specified address.
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $ah_Handle.
;                      2 = $sv_Type was not a string.
;                      3 = $sv_Type is an unknown data type.
;                      4 = Failed to allocate the memory needed for the DllStructure.
;                      5 = Error allocating memory for $sv_Type.
;                      6 = Failed to read from the specified process.
; Author(s):        Nomad
; Note(s):      Values returned are in Decimal format, unless specified as a
;               'char' type, then they are returned in ASCII format.  Also note
;               that size ('char[size]') for all 'char' types should be 1
;               greater than the actual size.
;==================================================================================
Func _MemoryRead($iv_Address, $ah_Handle, $sv_Type = 'dword')

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf

    Local $v_Buffer = DllStructCreate($sv_Type)

    If @Error Then
        SetError(@Error + 1)
        Return 0
    EndIf

    DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')

    If Not @Error Then
        Local $v_Value = DllStructGetData($v_Buffer, 1)
        Return $v_Value
    Else
        SetError(6)
        Return 0
    EndIf

EndFunc

Func _NewMemRead($Addr1, $Proc1, $type1)
   If $type1 = "int" Then ;I only used int, if you use uint or any other integer representation, add them in here
      Return (Dec(Hex(StringRegExpReplace(_MemoryRead($Addr1, $Proc1, $type1), "00000000", "", 1))))
   Else
      Return _MemoryRead($Addr1, $Proc1, $type1)
   EndIf
EndFunc   ;==>_NewMemRead

;==================================================================================
; Function:   _MemoryWrite($iv_Address, $ah_Handle, $v_Data[, $sv_Type])
; Description:    Writes data to the specified memory address.
; Parameter(s):  $iv_Address - The memory address which you want to write to.
;                          It must be in hex format (0x00000000).
;               $ah_Handle - An array containing the Dll handle and the handle
;                         of the open process as returned by _MemoryOpen().
;               $v_Data - The data to be written.
;               $sv_Type - (optional) The "Type" of value you intend to write.
;                        This is set to 'dword'(32bit(4byte) signed integer)
;                        by default.  See the help file for DllStructCreate
;                        for all types.  An example: If you want to write a
;                        word that is 15 characters in length, you would use
;                        'char[16]' since a 'char' is 8 bits (1 byte) in size.
; Return Value(s):  On Success - Returns 1
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $ah_Handle.
;                      2 = $sv_Type was not a string.
;                      3 = $sv_Type is an unknown data type.
;                      4 = Failed to allocate the memory needed for the DllStructure.
;                      5 = Error allocating memory for $sv_Type.
;                      6 = $v_Data is not in the proper format to be used with the
;                         "Type" selected for $sv_Type, or it is out of range.
;                      7 = Failed to write to the specified process.
; Author(s):        Nomad
; Note(s):      Values sent must be in Decimal format, unless specified as a
;               'char' type, then they must be in ASCII format.  Also note
;               that size ('char[size]') for all 'char' types should be 1
;               greater than the actual size.
;==================================================================================
Func _MemoryWrite($iv_Address, $ah_Handle, $v_Data, $sv_Type = 'dword')

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf

    Local $v_Buffer = DllStructCreate($sv_Type)

    If @Error Then
        SetError(@Error + 1)
        Return 0
    Else
        DllStructSetData($v_Buffer, 1, $v_Data)
        If @Error Then
            SetError(6)
            Return 0
        EndIf
    EndIf

    DllCall($ah_Handle[0], 'int', 'WriteProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')

    If Not @Error Then
        Return 1
    Else
        SetError(7)
        Return 0
    EndIf

EndFunc

;==================================================================================
; Function:   _MemoryClose($ah_Handle)
; Description:    Closes the process handle opened by using _MemoryOpen().
; Parameter(s):  $ah_Handle - An array containing the Dll handle and the handle
;                         of the open process as returned by _MemoryOpen().
; Return Value(s):  On Success - Returns 1
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = Invalid $ah_Handle.
;                      2 = Unable to close the process handle.
; Author(s):        Nomad
; Note(s):
;==================================================================================
Func _MemoryClose($ah_Handle)

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf

    DllCall($ah_Handle[0], 'int', 'CloseHandle', 'int', $ah_Handle[1])
    If Not @Error Then
        DllClose($ah_Handle[0])
        Return 1
    Else
        DllClose($ah_Handle[0])
        SetError(2)
        Return 0
    EndIf

EndFunc

;==================================================================================
; Function:   SetPrivilege( $privilege, $bEnable )
; Description:    Enables (or disables) the $privilege on the current process
;                   (Probably) requires administrator privileges to run
;
; Author(s):        Larry (from autoitscript.com's Forum)
; Notes(s):
; http://www.autoitscript.com/forum/index.ph...st&p=223999
;==================================================================================

Func SetPrivilege( $privilege, $bEnable )
    ;Const $TOKEN_ADJUST_PRIVILEGES = 0x0020
    ;Const $TOKEN_QUERY = 0x0008
    ;Const $SE_PRIVILEGE_ENABLED = 0x0002
    Local $hToken, $SP_auxret, $SP_ret, $hCurrProcess, $nTokens, $nTokenIndex, $priv
    $nTokens = 1
    $LUID = DLLStructCreate("dword;int")
    If IsArray($privilege) Then    $nTokens = UBound($privilege)
    $TOKEN_PRIVILEGES = DLLStructCreate("dword;dword[" & (3 * $nTokens) & "]")
    $NEWTOKEN_PRIVILEGES = DLLStructCreate("dword;dword[" & (3 * $nTokens) & "]")
    $hCurrProcess = DLLCall("kernel32.dll","hwnd","GetCurrentProcess")
    $SP_auxret = DLLCall("advapi32.dll","int","OpenProcessToken","hwnd",$hCurrProcess[0],   _
            "int",BitOR($TOKEN_ADJUST_PRIVILEGES,$TOKEN_QUERY),"int*",0)
    If $SP_auxret[0] Then
        $hToken = $SP_auxret[3]
        DLLStructSetData($TOKEN_PRIVILEGES,1,1)
        $nTokenIndex = 1
        While $nTokenIndex <= $nTokens
            If IsArray($privilege) Then
                $priv = $privilege[$nTokenIndex-1]
            Else
                $priv = $privilege
            EndIf
            $ret = DLLCall("advapi32.dll","int","LookupPrivilegeValue","str","","str",$priv,   _
                    "ptr",DLLStructGetPtr($LUID))
            If $ret[0] Then
                If $bEnable Then
                    DLLStructSetData($TOKEN_PRIVILEGES,2,$SE_PRIVILEGE_ENABLED,(3 * $nTokenIndex))
                Else
                    DLLStructSetData($TOKEN_PRIVILEGES,2,0,(3 * $nTokenIndex))
                EndIf
                DLLStructSetData($TOKEN_PRIVILEGES,2,DllStructGetData($LUID,1),(3 * ($nTokenIndex-1)) + 1)
                DLLStructSetData($TOKEN_PRIVILEGES,2,DllStructGetData($LUID,2),(3 * ($nTokenIndex-1)) + 2)
                DLLStructSetData($LUID,1,0)
                DLLStructSetData($LUID,2,0)
            EndIf
            $nTokenIndex += 1
        WEnd
        $ret = DLLCall("advapi32.dll","int","AdjustTokenPrivileges","hwnd",$hToken,"int",0,   _
                "ptr",DllStructGetPtr($TOKEN_PRIVILEGES),"int",DllStructGetSize($NEWTOKEN_PRIVILEGES),   _
                "ptr",DllStructGetPtr($NEWTOKEN_PRIVILEGES),"int*",0)
        $f = DLLCall("kernel32.dll","int","GetLastError")
    EndIf
    $NEWTOKEN_PRIVILEGES=0
    $TOKEN_PRIVILEGES=0
    $LUID=0
    If $SP_auxret[0] = 0 Then Return 0
    $SP_auxret = DLLCall("kernel32.dll","int","CloseHandle","hwnd",$hToken)
    If Not $ret[0] And Not $SP_auxret[0] Then Return 0
    return $ret[0]
EndFunc   ;==>SetPrivilege

;=================================================================================================
; Function:   _MemoryPointerRead ($iv_Address, $ah_Handle, $av_Offset[, $sv_Type])
; Description:    Reads a chain of pointers and returns an array containing the destination
;               address and the data at the address.
; Parameter(s):  $iv_Address - The static memory address you want to start at. It must be in
;                          hex format (0x00000000).
;               $ah_Handle - An array containing the Dll handle and the handle of the open
;                         process as returned by _MemoryOpen().
;               $av_Offset - An array of offsets for the pointers.  Each pointer must have an
;                         offset.  If there is no offset for a pointer, enter 0 for that
;                         array dimension.
;               $sv_Type - (optional) The "Type" of data you intend to read at the destination
;                         address.  This is set to 'dword'(32bit(4byte) signed integer) by
;                         default.  See the help file for DllStructCreate for all types.
; Requirement(s):   The $ah_Handle returned from _MemoryOpen.
; Return Value(s):  On Success - Returns an array containing the destination address and the value
;                         located at the address.
;               On Failure - Returns 0
;               @Error - 0 = No error.
;                      1 = $av_Offset is not an array.
;                      2 = Invalid $ah_Handle.
;                      3 = $sv_Type is not a string.
;                      4 = $sv_Type is an unknown data type.
;                      5 = Failed to allocate the memory needed for the DllStructure.
;                      6 = Error allocating memory for $sv_Type.
;                      7 = Failed to read from the specified process.
; Author(s):        Nomad
; Note(s):      Values returned are in Decimal format, unless a 'char' type is selected.
;               Set $av_Offset like this:
;               $av_Offset[0] = NULL (not used)
;               $av_Offset[1] = Offset for pointer 1 (all offsets must be in Decimal)
;               $av_Offset[2] = Offset for pointer 2
;               etc...
;               (The number of array dimensions determines the number of pointers)
;=================================================================================================
Func _MemoryPointerRead($iv_Address, $ah_Handle, $av_Offset, $sv_Type = 'dword')

    If IsArray($av_Offset) Then
        If IsArray($ah_Handle) Then
            Local $iv_PointerCount = UBound($av_Offset) - 1
        Else
            SetError(2)
            Return 0
        EndIf
    Else
        SetError(1)
        Return 0
    EndIf

    Local $iv_Data[2], $i
    Local $v_Buffer = DllStructCreate('dword')

    For $i = 0 To $iv_PointerCount

        If $i = $iv_PointerCount Then
            $v_Buffer = DllStructCreate($sv_Type)
            If @error Then
                SetError(@error + 2)
                Return 0
            EndIf

            $iv_Address = '0x' & Hex($iv_Data[1] + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @error Then
                SetError(7)
                Return 0
            EndIf

            $iv_Data[1] = DllStructGetData($v_Buffer, 1)

        ElseIf $i = 0 Then
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @error Then
                SetError(7)
                Return 0
            EndIf

            $iv_Data[1] = DllStructGetData($v_Buffer, 1)

        Else
            $iv_Address = '0x' & Hex($iv_Data[1] + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @error Then
                SetError(7)
                Return 0
            EndIf

            $iv_Data[1] = DllStructGetData($v_Buffer, 1)

        EndIf

    Next

    $iv_Data[0] = $iv_Address

    Return $iv_Data

EndFunc   ;==>_MemoryPointerRead



;=================================================================================================
; Function:         _MemoryPointerWrite ($iv_Address, $ah_Handle, $av_Offset, $v_Data[, $sv_Type])
; Description:      Reads a chain of pointers and writes the data to the destination address.
; Parameter(s):     $iv_Address - The static memory address you want to start at. It must be in
;                                 hex format (0x00000000).
;                   $ah_Handle - An array containing the Dll handle and the handle of the open
;                                process as returned by _MemoryOpen().
;                   $av_Offset - An array of offsets for the pointers.  Each pointer must have an
;                                offset.  If there is no offset for a pointer, enter 0 for that
;                                array dimension.
;                   $v_Data - The data to be written.
;                   $sv_Type - (optional) The "Type" of data you intend to write at the destination
;                                address.  This is set to 'dword'(32bit(4byte) signed integer) by
;                                default.  See the help file for DllStructCreate for all types.
; Requirement(s):   The $ah_Handle returned from _MemoryOpen.
; Return Value(s):  On Success - Returns the destination address.
;                   On Failure - Returns 0.
;                   @Error - 0 = No error.
;                            1 = $av_Offset is not an array.
;                            2 = Invalid $ah_Handle.
;                            3 = Failed to read from the specified process.
;                            4 = $sv_Type is not a string.
;                            5 = $sv_Type is an unknown data type.
;                            6 = Failed to allocate the memory needed for the DllStructure.
;                            7 = Error allocating memory for $sv_Type.
;                            8 = $v_Data is not in the proper format to be used with the
;                                "Type" selected for $sv_Type, or it is out of range.
;                            9 = Failed to write to the specified process.
; Author(s):        Nomad
; Note(s):          Data written is in Decimal format, unless a 'char' type is selected.
;                   Set $av_Offset like this:
;                   $av_Offset[0] = NULL (not used, doesn't matter what's entered)
;                   $av_Offset[1] = Offset for pointer 1 (all offsets must be in Decimal)
;                   $av_Offset[2] = Offset for pointer 2
;                   etc...
;                   (The number of array dimensions determines the number of pointers)
;=================================================================================================

Func _MemoryPointerWrite ($iv_Address, $ah_Handle, $av_Offset, $v_Data, $sv_Type = 'dword')

    If IsArray($av_Offset) Then
        If IsArray($ah_Handle) Then
            Local $iv_PointerCount = UBound($av_Offset) - 1
        Else
            SetError(2)
            Return 0
        EndIf
    Else
        SetError(1)
        Return 0
    EndIf

    Local $iv_StructData, $i
    Local $v_Buffer = DllStructCreate('dword')

    For $i = 0 to $iv_PointerCount
        If $i = $iv_PointerCount Then
            $v_Buffer = DllStructCreate($sv_Type)
            If @Error Then
                SetError(@Error + 3)
                Return 0
            EndIf

            DllStructSetData($v_Buffer, 1, $v_Data)
            If @Error Then
                SetError(8)
                Return 0
            EndIf

            $iv_Address = '0x' & hex($iv_StructData + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'WriteProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @Error Then
                SetError(9)
                Return 0
            Else
                Return $iv_Address
            EndIf
        ElseIf $i = 0 Then
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @Error Then
                SetError(3)
                Return 0
            EndIf

            $iv_StructData = DllStructGetData($v_Buffer, 1)

        Else
            $iv_Address = '0x' & hex($iv_StructData + $av_Offset[$i])
            DllCall($ah_Handle[0], 'int', 'ReadProcessMemory', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
            If @Error Then
                SetError(3)
                Return 0
            EndIf

            $iv_StructData = DllStructGetData($v_Buffer, 1)

        EndIf
    Next

EndFunc


;===================================================================================================

; Function........:  _MemoryGetBaseAddress($ah_Handle, $iHD)
;
; Description.....:  Reads the 'Allocation Base' from the open process.
;
; Parameter(s)....:  $ah_Handle - An array containing the Dll handle and the handle of the open
;                               process as returned by _MemoryOpen().
;                    $iHD - Return type:
;                       |0 = Hex (Default)
;                       |1 = Dec
;
; Requirement(s)..:  A valid process ID.
;
; Return Value(s).:  On Success - Returns the 'allocation Base' address and sets @Error to 0.
;                    On Failure - Returns 0 and sets @Error to:
;                  |1 = Invalid $ah_Handle.
;                  |2 = Failed to find correct allocation address.
;                  |3 = Failed to read from the specified process.
;
; Author(s).......:  Nomad. Szhlopp.
; URL.............:  http://www.autoitscript.com/forum/index.php?showtopic=78834
; Note(s).........:  Go to Www.CheatEngine.org for the latest version of CheatEngine.
;===================================================================================================

Func _MemoryGetBaseAddress($ah_Handle, $iHexDec = 0)

    Local $iv_Address = 0x00100000
    Local $v_Buffer = DllStructCreate('dword;dword;dword;dword;dword;dword;dword')
    Local $vData
    Local $vType

    If Not IsArray($ah_Handle) Then
        SetError(1)
        Return 0
    EndIf


    DllCall($ah_Handle[0], 'int', 'VirtualQueryEx', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer))

    If Not @Error Then

        $vData = Hex(DllStructGetData($v_Buffer, 2))
        $vType = Hex(DllStructGetData($v_Buffer, 3))

        While $vType <> "00000080"
            DllCall($ah_Handle[0], 'int', 'VirtualQueryEx', 'int', $ah_Handle[1], 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer))
            $vData = Hex(DllStructGetData($v_Buffer, 2))
            $vType = Hex(DllStructGetData($v_Buffer, 3))
            If Hex($iv_Address) = "01000000" Then ExitLoop
            $iv_Address += 65536

        WEnd

        If $vType = "00000080" Then
            SetError(0)
            If $iHexDec = 1 Then
                Return Dec($vData)
            Else
                Return $vData
            EndIf

        Else
            SetError(2)
            Return 0
        EndIf

    Else
        SetError(3)
        Return 0
    EndIf

EndFunc   ;==>_MemoryGetBaseAddress
#EndRegion

Second, we have a little UDF I put together for my purposes.

IPCLib.au3

#include <WinAPI.au3>
#include <WindowsConstants.au3>
#include <APISysConstants.au3>
#include <NomadMemory.au3>

Global $IPC_MNum, $IPC_PID, $IPC_Func, $IPC_Temp, $IPC_MsgStruct

Func IPC_Register($ipcname = Default, $type = "Server", $function = "")
    If $ipcname = Default Then $ipcname = "IPC_Default_Name"
    If $type = "Client" Then GUICreate("") ;We have to have a "top-level" window for HWND_BROADCAST to work.
    $IPC_MNum = _WinAPI_RegisterWindowMessage($ipcname)
    Switch $type
        Case "Server"
            IPC_Notify()
            AdlibRegister("IPC_Notify", 3000) ;Register with children every 3 seconds
        Case "Client"
            $IPC_Func = $function
            GUIRegisterMsg($IPC_MNum, "IPC_GetInfo")
    EndSwitch
EndFunc

Func IPC_Broadcast($sOut)
    ;put the string in a struct
    $IPC_Temp = DllStructCreate('char[' & StringLen($sOut) + 1 & ']')
    DllStructSetData($IPC_Temp, 1, $sOut)

    ;create another struct for the address of the first struct and the length of the string
    $IPC_MsgStruct = DllStructCreate("int;int")
    DllStructSetData($IPC_MsgStruct, 1, DllStructGetPtr($IPC_Temp))
    DllStructSetData($IPC_MsgStruct, 2, StringLen($sOut) + 1)

    _WinAPI_PostMessage($HWND_BROADCAST, $IPC_MNum, 2, DllStructGetPtr($IPC_MsgStruct))
EndFunc   ;==>IPC_Broadcast

Func IPC_Notify()
    _WinAPI_PostMessage($HWND_BROADCAST, $IPC_MNum, 1, @AutoItPID)
EndFunc

Func IPC_GetInfo($hWnd, $MsgID, $Wparam, $LParam)
    Local $DataAdd, $DataLen, $Data, $hMem
    Switch $Wparam
        Case 1 ;we're being told the PID
            $IPC_PID = Number($LParam)
        Case 2 ;$LParam is the address of the struct
            $hMem = _MemoryOpen($IPC_PID)
            ;$LParam is the address of the struct
            $DataAdd = _NewMemRead($LParam, $hMem, "int")
            $DataLen = _NewMemRead(IPC_AddrCalc($LParam, 4), $hMem, "int")
            $Data = _NewMemRead(IPC_AddrCalc($DataAdd, 0), $hMem, "char[" & $DataLen & "]")
            $IPC_Func($Data)
    EndSwitch
EndFunc   ;==>IPC_GetInfo

Func IPC_AddrCalc($StartAddr, $Offset)
    Return '0x' & Hex(Number($StartAddr) + $Offset, 8)
EndFunc   ;==>IPC_AddrCalc

And, finally we have example scripts. First is Receive.au3. Run this one first. You may have as many copies of this script running as necessary.

Receive.au3

#include <IPCLib.au3>
IPC_Register(Default, "Client", Alert) ;Register as a client, sending received messages to the alert function

While 1
    Sleep(1000)
WEnd

Func Alert($str)
    MsgBox(0,"",$str)
EndFunc

And Finally, the "Server" or sending part. In practice, you can IPC_Broadcast($Messages) as often as you like, and all the children scripts will respond as necessary.

Send.au3

#include <IPCLib.au3>
IPC_Register() ;Register as a Server, AKA Sender.
IPC_Broadcast("Hello to another script")
While 1
    Sleep(1000)
WEnd

Credits for all this goes to martin, cooleko, Nomad and Melba23.

I have simply modified the scripts for my usages. I did, however, notice and fix a bug along the way. The IPC_Broadcast function was a modified version of martin's SendString function. In his function, the dll structures were local to the function, and therefore temporary. As soon as SendString exited, the structures were destroyed. This is fine with SendMessage, since this function appears to wait until the message is received. However, when used with PostMessage and HWND_BROADCAST (which does not appear to wait), the function destroyed the dll structures before the children scripts were able to access them. Therefore, I simply made those structures Global.

Looks promising, though is IPC_Broadcast() used by the clients to communicate back to the server as well?

Edit: on further inspection the answer to this appears to be no. But I assume a server can also be registered as a client and each client as a server? This would let them communicate both ways without any conflict, right?

Edited by nullschritt
Link to comment
Share on other sites

You could probably declare your structs as local static instead of global if you pleased.

Thank you for this. I was unaware of such a keyword. I have been away from AutoIt for quite a while. I have modified IPCLib.au3 accordingly.

Looks promising, though is IPC_Broadcast() used by the clients to communicate back to the server as well?

Edit: on further inspection the answer to this appears to be no. But I assume a server can also be registered as a client and each client as a server? This would let them communicate both ways without any conflict, right?

I am assuming, based on the simplicity of the code, that you are correct. However, since this has been modified to be a broadcast script instead of a direct script-to-script communication method, it might be interesting to have all scripts involved register as the same server name. Then any message sent by any script would not only be seen by the script itself, but also by every other copy. I can't yet imagine an instance where each script should share information to ALL others, but I am sure someone else out there would. The only problem might be that each script that becomes a server registers with clients by sending its own PID. Based on the fact that the PID of the server is sent to the clients, each client would need to register as a server with a different $ipcname. If you used the same $ipcname as another script, then only the last registered server with that name could send messages. The client acts like a mail handler. The server simply says to every client "you've got mail". Then the client reads the message from the server. With two servers having the same name, only the last registered would be able to send messages.

Edited by this-is-me
Who else would I be?
Link to comment
Share on other sites

@this-is-me

Can I register more than one client in a process if they have a different name?

For example the following configuration:

Main Script -> Server as SRV1 -> Client as SRV2

SRV2 -> Server as SRV2 -> Client as SRV1 -> Client as SRV4

SRV3 -> Server as SRV3 -> Client as SRV1

SRV4 -> Server as SRV4 -> Client as SRV1

Edited by nullschritt
Link to comment
Share on other sites

@this-is-me

Can I register more than one client in a process if they have a different name?

For example the following configuration:

Main Script -> Server as SRV1 -> Client as SRV2

SRV2 -> Server as SRV2 -> Client as SRV1 -> Client as SRV4

SRV3 -> Server as SRV3 -> Client as SRV1

SRV4 -> Server as SRV4 -> Client as SRV1

Forget everything I have previously said about what this script can do outside its original purpose. I was completely wrong. After running a couple of testing scripts, I have verifed that this script will only do one thing, for which I originally designed it. It is a single server, multiple clients script. A single script cannot register as multiple servers. or register to get messages as clients with multiple names. Either case causes immediate issues. Since the script performs the function for which I originally intended to use it, I am no longer interested in modifying it or testing it for other purposes. If you are interested in doing so, please do. I think it would be nice if scripts could communicate using a broadcast method for two-way communication. However, due to the mail-type messages, that will not be possible with the script in its current form. Nothing in the current script can cope with multiple servers at all.

Who else would I be?
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...