找回密码
 加入
搜索
查看: 1697|回复: 23

[原创] 进程间的七种通信方式

[复制链接]
发表于 2022-5-20 16:33:26 | 显示全部楼层 |阅读模式
在日常应用中,有时候进程与进程之间需要共享数据,可能会经常用到,综合自己平常学到的一些知识及经验积累,放出与大家共同提高。

进程间的7种通信方式如下(转载与网络):

1.管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

2.命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

3.消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

4.共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

5.信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

6.套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

7.信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。



评分

参与人数 3金钱 +100 收起 理由
xyhqqaa + 30 学习了
anythinging + 40 赞一个!
nhnhwsnh + 30 很给力!

查看全部评分

 楼主| 发表于 2022-5-20 16:44:19 | 显示全部楼层
本帖最后由 tubaba 于 2022-5-20 16:46 编辑

先介绍第三种:消息队列MessageQueue


这里最常用的windows消息 就是WM_COPYDATA, 如果不了解这个消息,可以点击链接 WM_COPYDATA


至于这个消息怎么用,我想以一个例子来说明:


请保存为  WM_COPYDATA发送.au3

Global $hWndTarget
Global $WM_COPYDATA = 0x004A
If $cmdline[0] = 1 Then
$hWndTarget = HWnd($cmdline[1])
Else
        Exit MsgBox(0,1,'请先运行接收端')
EndIf
Global $My_Hwnd = GUICreate("WM_COPYDATA发送", 300, 600,  @DesktopWidth / 2 + 5, Default, Default, 0x00000008)
$ssss= GUICtrlCreateEdit('', 5,5,280,400)

$bbbb = GUICtrlCreateButton('send', 10, 450, 100, 30)

GUISetState()


While 1
        $msg = GUIGetMsg()
        Switch $msg
                Case -3
                        Exit
                Case $bbbb
                        SendData($hWndTarget, GUICtrlRead($ssss))
        EndSwitch
WEnd


Func SendData($hWndTarget, $sData)
                Local $msg = StringToBinary($sData, 4) 
                Local $MyData = DllStructCreate("byte[" & BinaryLen($msg) & "]")
                Local $COPYDATA = DllStructCreate("ptr;dword;ptr")
                DllStructSetData($MyData, 1, $msg)
                DllStructSetData($COPYDATA, 1, 0)
                DllStructSetData($COPYDATA, 2, DllStructGetSize($MyData))
                DllStructSetData($COPYDATA, 3, DllStructGetPtr($MyData))
                
                Local $aTmp = DllCall("user32.dll", "int", "SendMessageTimeout", "hwnd", $hWndTarget, "int", $WM_COPYDATA _ ; WM_COPYDATA
                                , "int", 0, "ptr", DllStructGetPtr($COPYDATA), "int", 0, "int", 1000, "long*", 0)
EndFunc   ;==>SendSciTE_Command



请保存为WM_COPYDATA接收.au3


Global $My_Hwnd = GUICreate("WM_COPYDATA接收", 300, 600, @DesktopWidth / 2 - 300, Default, Default, 0x00000008)
$ssss= GUICtrlCreateEdit('', 5,5,280,400)
GUIRegisterMsg(0x004A, "WM_COPYDATA")
GUISetState()
Run(StringFormat('"%s" "%s" "%s"',@AutoItExe,@ScriptDir & '\WM_COPYDATA发送.au3',String($My_Hwnd)))


Do
Until GUIGetMsg() = -3



Func WM_COPYDATA($hWnd, $Msg, $wParam, $lParam)
        #forceref $hWnd, $Msg, $wParam, $lParam
        Local $COPYDATA, $tMyData, $MyData
        $COPYDATA = DllStructCreate("ptr;dword;ptr", $lParam)
        $tMyData = DllStructCreate("byte[" & DllStructGetData($COPYDATA, 2) & "]", DllStructGetData($COPYDATA, 3))
        $MyData = BinaryToString(DllStructGetData($tMyData, 1), 4)
        GUICtrlSetData($ssss, $MyData)
        Return 
EndFunc   ;==>WM_COPYDATA





点评

太感谢了!  发表于 2022-5-20 17:37
给力  发表于 2022-5-20 16:53

评分

参与人数 2威望 +2 金钱 +60 贡献 +2 收起 理由
smooth + 60 很给力!
绿色风 + 2 + 2 此 4a 消息是常用操作

查看全部评分

 楼主| 发表于 2022-5-20 17:02:13 | 显示全部楼层
本帖最后由 tubaba 于 2022-5-20 17:12 编辑


在两个不同的应用程序之间可能需要传递数据,利用邮槽(mailslot)可以达成目标,一个程序(客户端)向邮槽写数据,另一个程序(服务端)负责接收数据。


邮槽定义:邮槽(Mailslot)也称为邮件槽,是Windows 提供的进程间通信的手段,

其提供的是基于不可靠的,邮件槽只支持单向数据传输,也就是服务器只能接收数据,而客户端只能发送数据,

何为服务端?创建邮槽的那一端就是服务端。
还有需要提及的一点是,客户端在使用邮槽发送数据的时候只有当数据的长度 < 425 字节时,才可以被广播给多个服务器,如果消息的长度 > 425 字节的话,那么在这种情形下,邮槽是不支持广播通信的。
这是我看到的邮槽的简要说明吧。



邮槽的使用过程
服务端:                                        客户端:
首先创建邮槽CreateMailslot               打开油槽CreateFile
读取数据 ReadFile                           写入数据WriteFile

只有这四个函数。也很容易理解。 客户端写入数据 服务端读取数据。

其实Mailslot方法在AutoIt3Wrapper.au3中可以找到使用方法,有兴趣的话可以自行研究,查找函数 _MailSlotCreate,_ReadMessage,_MailSlotWrite








 楼主| 发表于 2022-5-20 17:10:35 | 显示全部楼层
下面介绍的是4.共享存储SharedMemory


同样,以一个例子说明,先说明一下,这个例子是国外网站照搬过来,我自己也没有用这种方法写过程序,发出来给大家共同学习。以下为机器翻译,懒得整理翻译了,凑活看吧
有两个脚本:
1.示例_Sharing_Memory_Var.au3是调用应用程序(我称之为母应用程序)
2.Sharing_Memory_Client.au3是客户端应用程序
母应用程序正在为要在应用程序之间共享的不同变量创建结构(当然可能超过2个)
一旦定义和分配了结构,子应用程序将由母应用程序启动,其命令行参数包含母应用程序的PID和指向共享变量的指针地址。
在本例中,对话是双向的:
-母应用程序根据子应用程序的要求更改背景颜色。
-子应用程序GUI将根据母亲的请求移动位置。
-两个GUI都会通过按下停止按钮(我退出,你退出…)强制关闭另一个应用程序
-母应用程序将发送输入字段中输入的任何文本(按enter键确认)
-母应用程序可以向子应用程序发送两个命令“color”和“quit”。颜色将强制更改两个GUI的颜色,对于母应用程序来说,退出将是自杀。
先决条件:
-除非更改调用应用程序中的名称,否则不要更改子应用程序的名称
该脚本使用Nomad memory UDF,我将其包含在脚本中,因此您不必搜索它。
请编译后运行测试效果

以下保存为 Example_Sharing_Memory_Var.au3


#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.0.0
 Author:         GreenCan

 Script Function: Example_Sharing_Memory_Var.au3
 
    Example of sharing variables between applications
    
    This script will start another application 'Sharing_Memory_Client.au3' 
    
    It will pass it's PID and 3 pointers to the variables to be shared
    It will communicate with that application by changing the content of the variables:
    
    The child application can also change the content (background color) and can force the shutdown of this application
    
#ce ----------------------------------------------------------------------------

#include <GUIConstantsEx.au3>

; initial values for backround color and corner position
Global $BackgroundColor = 0x01398E ; initial value
Global $CornerPosition = 1, $add = True ; corner variables
; set GUI
$Gui = GUICreate("Calling Application", 300, 200, 100, 100)

GuiCtrlCreateLabel("Example of sharing variables across applications", 5, 10,290,20)
GUICtrlSetFont (-1, 10) 
GUICtrlSetColor ( -1, 0xFFFFFF)
$LabelColor = GuiCtrlCreateLabel("Color: " & $BackgroundColor, 5, 35,290,40)
GUICtrlSetColor ( $LabelColor, 0xFFFFFF)
GUICtrlSetFont (-1, 10) 

$LastMessage = GuiCtrlCreateLabel("Type something and press enter", 5, 80,290,60)
GUICtrlSetColor ( -1, 0xFFFFFF)
GUICtrlSetFont (-1, 10) 
$Input = GUICtrlCreateInput("", 5, 140, 290, 21)
GUICtrlSetTip ( -1 , "You can type anything but only 2 commands will be understood by the client:" & @CR & " Type 'Color' to force a color change" & @CR & " Type 'Quit' to force the client to quit" )

Local $ok = GUICtrlCreateButton("Stop", 5, 170, 70,22 )
Local $Corner = GUICtrlCreateButton("Change Corner", 195, 170, 100,22 )

;   Create the structure
$struct = "int color;int position;char var[128]"
$Structure=DllStructCreate($struct) 
if @error Then
    MsgBox(0,"","Error in DllStructCreate " & @error);
    exit
endif
DllStructSetData($Structure,"color",$BackgroundColor) ; sets the value of color at $BackgroundColor
DllStructSetData($Structure,"position",$CornerPosition) ; sets the value of corner position 

; get the pointers
$Pointer1 = DllStructGetPtr($Structure,"color") ; Returns the pointer to the color
$Pointer2 = DllStructGetPtr($Structure,"position") ; Returns the pointer to the position
$Pointer3 = DllStructGetPtr($Structure,"var") ; Returns the pointer to the position

ConsoleWrite(@AutoItPID & @CR & $Pointer1 & @CR & $Pointer2 & @CR & $Pointer3 & @CR )

;  Start the client application with 4 parameters:
;   the PID of the calling program (this example)
;   the 3 pointers of the shared variables 

If FileExists(@ScriptDir & "\" & "Sharing_Memory_Client.exe") = 1 Then
    $return = Run("Sharing_Memory_Client.exe " & @AutoItPID & " " & $Pointer1 & " " & $Pointer2 & " " & $Pointer3,  @ScriptDir) 
Else
    If FileExists(@ScriptDir & "\" & "Sharing_Memory_Client.au3") = 1 Then
       $ToRun = @AutoItExe & ' /AutoIt3ExecuteScript "' & @ScriptDir & 'Sharing_Memory_Client.au3"' & ' "' & @AutoItPID &'" "' & $Pointer1 & '" "' & $Pointer2 & '" "' & $Pointer3 & '"'
        Run($ToRun) 
    Else
        MsgBox(48, "Error" , "'Sharing_Memory_Client.au3' not found" & @CR & "Both applications should be in the same folder.")
        Exit
    EndIf
EndIf

$OldValue = 0
GUISetState()

While 1
    
    $msg = GUIGetMsg()
    Select
        
    Case $msg = $Input
        GUICtrlSetData ($LastMessage,  "Sent: " & GUICtrlRead($Input))
        ; set the string into the memory
        DllStructSetData($Structure,"var", GUICtrlRead($Input))
        GUICtrlSetData ( $Input, "")
        
    Case $msg = $GUI_EVENT_CLOSE 
        DllStructSetData($Structure,"color",0) ; exit value for child application
        ;Exit
    Case $msg = $ok
        DllStructSetData($Structure,"color",0) ; exit value for child application
        ;Exit   
    Case $msg = $Corner
        ; change position 1, 2 and 3
        
        If $CornerPosition = 3 Then 
            $add = False
        ElseIf $CornerPosition = 1 Then
            $add = True
        EndIf
        If $add = True Then
            $CornerPosition += 1
        Else
            $CornerPosition -= 1
        EndIf
        DllStructSetData($Structure,"position",$CornerPosition) ; exit value for child application
    EndSelect   
    
    $NewValue = DllStructGetData($Structure,"color") ; Pick up the value from the shared memory
    $NewPosition = DllStructGetData($Structure,"position") ; Pick up the value from the shared memory
    
;ConsoleWrite(Hex($NewValue) & " " & $NewPosition & @CR)

    If $NewValue = -1 Then ; Shutdown request from child
        GUICtrlSetData ( $LabelColor,"Exit value: " & $NewValue & @CR & "Child application requests Shutdown")
        Beep(3000,150)
        sleep(3000)
        Exit
    EndIf

    If $OldValue <> $NewValue Then ; change color
        $BackgroundColor = $NewValue
        GUISetBkColor( $BackgroundColor, $Gui)
        GUICtrlSetData ( $LabelColor, "Color: 0x" & Hex($BackgroundColor) )
        $OldValue = $NewValue
    EndIf
        
WEnd




以下保存为 Sharing_Memory_Client.au3


#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.0.0
 Author:         GreenCan

 Script Function: Sharing_Memory_Client.au3
 
    Child application started by Example_Sharing_Memory_Var.au3
    
 Pre-requisite:
    1. Do NOT change the name of the script as it is started by Example_Sharing_Memory_Var.au3
    
 This is the child application that is started by the mother application
 The child receives the PID and the pointers so it can access the variables 
    
 Credits: Thanks to following contributors
    - This source includes Memory UDF library by Nomad
    
#ce ----------------------------------------------------------------------------

; #include "memory2.au3" 
#include <GUIConstantsEx.au3>

If $CmdLine[0] <> 4 Then Exit ; require PID, pointer1 and pointer2
    
; set GUI
$GuiWidth = 300
$GuiHeight = 300
$Gui = GUICreate("Child Application", $GuiWidth, $GuiHeight, @DesktopWidth - $GuiWidth - 100, @DesktopHeight - $GuiHeight - 100)


Global $PID = $CmdLine[1] 
Global $Pointer1 = $CmdLine[2] 
Global $Pointer2 = $CmdLine[3] 
Global $Pointer3 = $CmdLine[4] 

; $Pointer1 = initial value of color passed by the mother application
; the child application (this script) will also use $Pointer1 to communicate that it's stops (by setting $Pointer1 to -1 )
$Color = Read_Memory($PID, $Pointer1) 
; $Pointer2 = initial value of corner position passed by the mother application
$Position = Read_Memory($PID, $Pointer2) 
; initial value of passed char String
$Char = ""

GuiCtrlCreateLabel("Child application" , 5, 5,$GuiWidth - 10,20)
GUICtrlSetColor ( -1, 0xFFFFFF)
GUICtrlSetFont (-1, 10) 
Local $LabelColor = GuiCtrlCreateLabel("The Application will stop when the mother application Quits", 5, 30,$GuiWidth - 10,50)
GUICtrlSetColor ( $LabelColor, 0xFFFFFF)
GUICtrlSetFont (-1, 10) 
Local $GUIEdit=GUICtrlCreateEdit ( "" , 5, $GuiHeight - 235, $GuiWidth - 10, 195)

Local $Stop = GUICtrlCreateButton("Stop", ($GuiWidth/2) - 35, $GuiHeight -30, 70,22 )

GUISetState()
; show the pointers
GUICtrlSetData ( $GUIEdit, "Pointer address 1: " & $Pointer1 & @CRLF & "            address 2: " & $Pointer2 & @CRLF & "            address 3: " & $Pointer3 & @CRLF , "append")

Color()

While 1
    
    $msg = GUIGetMsg()
    If $msg = $Stop Then
        Write_Memory($PID, $Pointer1, -1) ; communicate the exit value to the mother application
        Exit        
    EndIf           
    
    ; if the mother application is closed, the the value will be set to -1 and the child will close too
    $exitValue =  Read_Memory($PID, $Pointer1, "int")
    If $exitValue = 0 Then 
        Quit()
    Else
        ; the mother application requests the child application to change corner if the value of $Pointer2 changes
        $newPosition =  Read_Memory($PID, $Pointer2)
        If $Position <> $newPosition Then
            GUICtrlSetData ( $GUIEdit, "Request from mother to change corner to: " & $newPosition & @CRLF  , "append" )             
            $Position = $newPosition
            If $Position = 1 Then ; Right Lower corner
                WinMove($Gui, "", @DesktopWidth - $GuiWidth - 100, @DesktopHeight - $GuiHeight - 100) 
            ElseIf $Position = 2 Then ; Left Lower corner
                WinMove($Gui, "", 100, @DesktopHeight - $GuiHeight - 100) 
            ElseIf $Position = 3 Then ; Right Upper corner
                WinMove($Gui, "", @DesktopWidth - $GuiWidth - 100, 100) 
            EndIf
        EndIf
        
        ; the mother application sents a character string
        $Char = Read_Memory($PID, $Pointer3, "char var4[128]") 
        If $Char <> "" Then
            Write_Memory($PID, $Pointer3, "", "char var4[128]") ; empty value in memory
            If StringUpper(StringStripWS ($Char,3)) = "QUIT" Then 
                GUICtrlSetData ( $GUIEdit, "Received command" & ": " & $Char  & @CRLF  , "append" )
                Quit()
            ElseIf StringUpper(StringStripWS ($Char,3)) = "COLOR" Then 
                GUICtrlSetData ( $GUIEdit, "Received command" & ": " & $Char  & @CRLF  , "append" )
                Color()
            Else
                GUICtrlSetData ( $GUIEdit, "Received" & ": " & $Char  & @CRLF  , "append" )
                ;TrayTip("text", $Char, 5)
            EndIf
        EndIf
        
        ; change background color and sent to the mother application 
        $randomizer = Random(1,600,1)
        If $randomizer = 1 Then Color()
    EndIf

WEnd
#FUNCTION# ==============================================================
Func Color()
    $Color = Random(1,30000000,1) ; new background color
    GUISetBkColor( $Color, $Gui)
    Write_Memory($PID, $Pointer1, $Color, "int") ; set the new value to be returned to the mother application
    GUICtrlSetData ( $GUIEdit, "Sent Color Change: 0x" & Hex($Color) & @CRLF  , "append" )  
EndFunc ;==>Color
#FUNCTION# ==============================================================
Func Quit()
    GUICtrlSetData ( $GUIEdit, "Mother application requests Shutdown" & @CRLF & @CRLF & "Shutdown within 3 seconds", "append")
    Beep(4000,150)
    sleep(3000)  ; wait 3 secs before closing
    ; You ask me to quit but you Quit too...
    Write_Memory($PID, $Pointer1, -1) ; communicate the exit value to the mother application
    Exit
EndFunc ;==>Quit
#FUNCTION# ==============================================================
Func Write_Memory($_PID, $_Pointer, $_Value, $_VarType = "int")
    ; This function will replace a value in memory, allocated to the calling application 
    Local $DllHandle = _MemoryOpen($_PID) ; Open the memory allocated by the PID from the calling application
    Local $Data = _MemoryWrite($_Pointer, $DllHandle, $_Value, $_VarType) ; Write the new value at the Pointer address 
    $error = @Error ; just check if any error writing the memory
    If $error > 1 Then beep(1000,1000) ; just ring the bell if unable to write
    _MemoryClose($DllHandle) ; Close the Handle
EndFunc ;==>Write_Memory
#FUNCTION# ==============================================================
Func Read_Memory($_PID, $_Pointer, $_VarType = "int")
    ; This function will read a value in memory, allocated by the calling application ToolbarAG.exe
    Local $DllHandle = _MemoryOpen($_PID) ; Open the memory allocated by the PID from the calling application 
    Local $Data = _MemoryRead($_Pointer, $DllHandle , $_VarType) ; read value passed by the mother application
    $error = @Error ; just check if any error reading the memory
    _MemoryClose($DllHandle) ; Close the Handle
    If $error > 1 Then
        Return ""
    Else
        Return $Data
    EndIf   
EndFunc ;==>Read_Memory
#FUNCTION# ==============================================================

#include-once
#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.
;               $if_InheritHandle - (optional) If this value is TRUE, all processes created by
;                              this process will inherit the access handle.  Set to TRUE
;                              (1) by default.  Set to 0 if you want it to be FALSE.
; Requirement(s):   A valid process ID.
; 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, $if_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', $if_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]'.
; Requirement(s):   The $ah_Handle returned from _MemoryOpen.
; 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

;=================================================================================================
; 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 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]'.
; Requirement(s):   The $ah_Handle returned from _MemoryOpen.
; 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().
; Requirement(s):   The $ah_Handle returned from _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:   _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

;=================================================================================================
; 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
#endregion


发表于 2022-5-20 17:20:28 | 显示全部楼层
大佬这些资料,太宝贵啦,感谢大度分享。
发表于 2022-5-20 18:50:14 | 显示全部楼层
本帖最后由 smooth 于 2022-5-20 23:03 编辑
tubaba 发表于 2022-5-20 16:44
先介绍第三种:消息队列MessageQueue

在两个独立的文件之间可以传递,但如果是在一个AU3文件里面的由_CoProc()函数开启的子进程,怎么样把消息函数组装到开启子进程的函数中呢?因为接收方需要注册消息函数,子进程由于没有GUI,所以搞了没搞成功。
发表于 2022-5-20 20:18:53 | 显示全部楼层
发表于 2022-5-20 20:26:21 | 显示全部楼层
学习了,感谢分享!
发表于 2022-5-20 22:42:15 | 显示全部楼层
感谢提供这么全面的教程
 楼主| 发表于 2022-5-21 21:40:50 | 显示全部楼层
smooth 发表于 2022-5-20 18:50
在两个独立的文件之间可以传递,但如果是在一个AU3文件里面的由_CoProc()函数开启的子进程,怎么样把消息 ...

看_coprocsend函数
 楼主| 发表于 2022-5-21 21:44:32 | 显示全部楼层
子进程可以guicreate窗口,这个窗口并不需要显示
发表于 2022-5-21 22:51:56 | 显示全部楼层
本帖最后由 smooth 于 2022-5-21 23:04 编辑
tubaba 发表于 2022-5-21 21:44
子进程可以guicreate窗口,这个窗口并不需要显示

大佬,我之前只会用_CoProcSend把子进程的信息发送给母进程,我现在试着用_CoProcSend向子进程发送消息,测试发现可以。
但是奇怪的是,我发送3个变量,中间用|分割,子进程接收后,分割出来,为什么第3个变量本来是个True,却只收到的一个T呢?
如果我增加一个参数,则第3个传送又是完整的,第4个则又不完整,咋回事呢?如果是放在函数_CoProc里作为参数传递,则没有问题。


发表于 2022-5-22 19:00:41 | 显示全部楼层
本帖最后由 smooth 于 2022-5-23 08:13 编辑
tubaba 发表于 2022-5-21 21:44
子进程可以guicreate窗口,这个窗口并不需要显示

用你的方法,搞成了,把子进程的窗口句柄,传递给母进程,然后就可以用你的方法发送消息了。

 楼主| 发表于 2022-5-23 09:48:56 | 显示全部楼层
smooth 发表于 2022-5-21 22:51
大佬,我之前只会用_CoProcSend把子进程的信息发送给母进程,我现在试着用_CoProcSend向子进程发送消息, ...

在用前辈研发的UDF函数时,可以仔细查看UDF的写法思路,这样才会提高自己的编程水平,如果你仔细研究coproc函数的执行流程,本质上coprocsend使用的是wm_copydata消息



咱们再来说为什么传递的值会不完整的问题,仔细看_CoProcSend函数构造,其中有一行$MyData = DllStructCreate("char[" & StringLen($vParameter) + 1 & "]"),char这个结构在单字节字符不会有问题,比如英文字母,但是,若有双字节字符的存在,这个结构就会有问题。因为结构放不下完整的双字节字符。这个问题我在论坛上有讨论过,有兴趣可以去查,这里不展开说为什么会丢失。

好,现在知道了原因,来改造这个函数
原函数


Func _CoProcSend($vProcess, $vParameter, $iTimeout = 500, $fAbortIfHung = True)
Local $iPid, $hWndTarget, $MyData, $aTmp, $COPYDATA, $iFuFlags
$iPid = ProcessExists($vProcess)
If Not $iPid Then Return SetError(1, 0, False) ; Process not Found
$hWndTarget = _ProcessGetWinList($vProcess, "", 16 + 2)
If @error Or (Not $hWndTarget) Then Return SetError(2, 0, False) ; Window not found
$MyData = DllStructCreate("char[" & StringLen($vParameter) + 1 & "]")
$COPYDATA = DllStructCreate("ptr;dword;ptr")
DllStructSetData($MyData, 1, $vParameter)
DllStructSetData($COPYDATA, 1, 1)
DllStructSetData($COPYDATA, 2, DllStructGetSize($MyData))
DllStructSetData($COPYDATA, 3, DllStructGetPtr($MyData))
If $fAbortIfHung Then
$iFuFlags = 0x2 ; SMTO_ABORTIFHUNG
Else
$iFuFlags = 0x0 ; SMTO_NORMAL
EndIf
$aTmp = DllCall("user32.dll", "int", "SendMessageTimeout", "hwnd", $hWndTarget, "int", 0x4A _; WM_COPYDATA
, "int", 0, "ptr", DllStructGetPtr($COPYDATA), "int", $iFuFlags, "int", $iTimeout, "long*", 0)
If @error Then Return SetError(3, 0, False) ; SendMessageTimeout Failed
If Not $aTmp[0] Then Return SetError(3, 0, False) ; SendMessageTimeout Failed
If $aTmp[7] <> 256 Then Return SetError(3, 0, False)
$aTmp = DllCall("user32.dll", "int", "PostMessage", "hwnd", $hWndTarget, "int", 0x400 + 0x64, "int", 0, "int", 0)
If @error Then Return SetError(4, 0, False)
If Not $aTmp[0] Then Return SetError(4, 0, False)
Return True
EndFunc ;==>_CoProcSend



修改以后


Func _CoProcSend($vProcess, $vParameter, $iTimeout = 500, $fuFlags = 0)
        Local Const $SMTO_NORMAL = 0x0000, $SMTO_BLOCK=0x0001 , $SMTO_ABORTIFHUNG =0x0002,$SMTO_NOTIMEOUTIFNOTHUNG = 0x0008
        Local $iPid, $hWndTarget, $MyData, $aTmp, $COPYDATA, $iFuFlags
        $iPid = ProcessExists($vProcess)
        If Not $iPid Then Return SetError(1, 0, False) ; Process not Found
        $hWndTarget = _ProcessGetWinList($vProcess, "", 16 + 2)
        If @error Or (Not $hWndTarget) Then Return SetError(2, 0, False) ; Window not found
        $vParameter = StringToBinary($vParameter,4)
        $MyData = DllStructCreate("byte[" & BinaryLen($vParameter) & "]")
        $COPYDATA = DllStructCreate("ptr;dword;ptr")
        DllStructSetData($MyData, 1, $vParameter)
        DllStructSetData($COPYDATA, 1, 0)
        DllStructSetData($COPYDATA, 2, DllStructGetSize($MyData))
        DllStructSetData($COPYDATA, 3, DllStructGetPtr($MyData))
        Switch $fuFlags
                Case 0
                $iFuFlags = $SMTO_NORMAL
                Case 1
                $iFuFlags = $SMTO_BLOCK                        
                Case 2
                $iFuFlags = $SMTO_ABORTIFHUNG                        
                Case 3
                $iFuFlags = $SMTO_NOTIMEOUTIFNOTHUNG
                Case Else
                        Return SetError(5, 0, False)
        EndSwitch
        $aTmp = DllCall("user32.dll", "int", "SendMessageTimeout", "hwnd", $hWndTarget, "int", 0x4A _; WM_COPYDATA
                        , "int", 0, "ptr", DllStructGetPtr($COPYDATA), "int", $iFuFlags, "int", $iTimeout, "long*", 0)
        If @error Then Return SetError(3, 0, False) ; SendMessageTimeout Failed
        If Not $aTmp[0] Then Return SetError(3, 0, False) ; SendMessageTimeout Failed
        If $aTmp[7] <> 256 Then Return SetError(3, 0, False)
        $aTmp = DllCall("user32.dll", "int", "PostMessage", "hwnd", $hWndTarget, "int", 0x400 + 0x64, "int", 0, "int", 0)
        If @error Then Return SetError(4, 0, False)
        If Not $aTmp[0] Then Return SetError(4, 0, False)
        Return True
EndFunc   ;==>_CoProcSend



另外,coproc这个UDF确实很强大,稍微改造了一番,我用它完成了一个终端管理软件,甚至用创建的子进程再去创建另一子进程,运行的结果跳过父进程直接发送给祖进程。曲线实现了多任务并发,任务间完全独立的基本功能。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2022-5-23 09:56:26 来自手机 | 显示全部楼层
真棒,双手鼓掌
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-3-29 22:22 , Processed in 0.088655 second(s), 23 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表