进程间的七种通信方式
在日常应用中,有时候进程与进程之间需要共享数据,可能会经常用到,综合自己平常学到的一些知识及经验积累,放出与大家共同提高。进程间的7种通信方式如下(转载与网络):
1.管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
2.命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
3.消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
4.共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。
5.信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
6.套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。
7.信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
本帖最后由 tubaba 于 2022-5-20 16:46 编辑
先介绍第三种:消息队列MessageQueue
这里最常用的windows消息 就是WM_COPYDATA, 如果不了解这个消息,可以点击链接 WM_COPYDATA
至于这个消息怎么用,我想以一个例子来说明:
请保存为WM_COPYDATA发送.au3
Global $hWndTarget
Global $WM_COPYDATA = 0x004A
If $cmdline = 1 Then
$hWndTarget = HWnd($cmdline)
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
本帖最后由 tubaba 于 2022-5-20 17:12 编辑
在两个不同的应用程序之间可能需要传递数据,利用邮槽(mailslot)可以达成目标,一个程序(客户端)向邮槽写数据,另一个程序(服务端)负责接收数据。
邮槽定义:邮槽(Mailslot)也称为邮件槽,是Windows 提供的进程间通信的手段,
其提供的是基于不可靠的,邮件槽只支持单向数据传输,也就是服务器只能接收数据,而客户端只能发送数据,
何为服务端?创建邮槽的那一端就是服务端。
还有需要提及的一点是,客户端在使用邮槽发送数据的时候只有当数据的长度 < 425 字节时,才可以被广播给多个服务器,如果消息的长度 > 425 字节的话,那么在这种情形下,邮槽是不支持广播通信的。
这是我看到的邮槽的简要说明吧。
邮槽的使用过程
服务端: 客户端:
首先创建邮槽CreateMailslot 打开油槽CreateFile
读取数据 ReadFile 写入数据WriteFile
只有这四个函数。也很容易理解。 客户端写入数据 服务端读取数据。
其实Mailslot方法在AutoIt3Wrapper.au3中可以找到使用方法,有兴趣的话可以自行研究,查找函数 _MailSlotCreate,_ReadMessage,_MailSlotWrite
下面介绍的是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"
$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 <> 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
Global $Pointer1 = $CmdLine
Global $Pointer2 = $CmdLine
Global $Pointer3 = $CmdLine
; $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")
If $Char <> "" Then
Write_Memory($PID, $Pointer3, "", "char var4") ; 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 =
If @Error Then
SetError(2)
Return 0
EndIf
Local $av_OpenProcess = DllCall($ah_Handle, 'int', 'OpenProcess', 'int', $iv_DesiredAccess, 'int', $if_InheritHandle, 'int', $iv_Pid)
If @Error Then
DllClose($ah_Handle)
SetError(3)
Return 0
EndIf
$ah_Handle = $av_OpenProcess
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'.
; 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') 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, 'int', 'ReadProcessMemory', 'int', $ah_Handle, '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'.
; 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') 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, 'int', 'WriteProcessMemory', 'int', $ah_Handle, '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, 'int', 'CloseHandle', 'int', $ah_Handle)
If Not @Error Then
DllClose($ah_Handle)
Return 1
Else
DllClose($ah_Handle)
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 = NULL (not used)
; $av_Offset = Offset for pointer 1 (all offsets must be in Decimal)
; $av_Offset = 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, $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 + $av_Offset[$i])
DllCall($ah_Handle, 'int', 'ReadProcessMemory', 'int', $ah_Handle, 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
If @Error Then
SetError(7)
Return 0
EndIf
$iv_Data = DllStructGetData($v_Buffer, 1)
ElseIf $i = 0 Then
DllCall($ah_Handle, 'int', 'ReadProcessMemory', 'int', $ah_Handle, 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
If @Error Then
SetError(7)
Return 0
EndIf
$iv_Data = DllStructGetData($v_Buffer, 1)
Else
$iv_Address = '0x' & hex($iv_Data + $av_Offset[$i])
DllCall($ah_Handle, 'int', 'ReadProcessMemory', 'int', $ah_Handle, 'int', $iv_Address, 'ptr', DllStructGetPtr($v_Buffer), 'int', DllStructGetSize($v_Buffer), 'int', '')
If @Error Then
SetError(7)
Return 0
EndIf
$iv_Data = DllStructGetData($v_Buffer, 1)
EndIf
Next
$iv_Data = $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 = NULL (not used, doesn't matter what's entered)
; $av_Offset = Offset for pointer 1 (all offsets must be in Decimal)
; $av_Offset = 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, 'int', 'WriteProcessMemory', 'int', $ah_Handle, '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, 'int', 'ReadProcessMemory', 'int', $ah_Handle, '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, 'int', 'ReadProcessMemory', 'int', $ah_Handle, '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
大佬这些资料,太宝贵啦,感谢大度分享。 本帖最后由 smooth 于 2022-5-20 23:03 编辑
tubaba 发表于 2022-5-20 16:44
先介绍第三种:消息队列MessageQueue
在两个独立的文件之间可以传递,但如果是在一个AU3文件里面的由_CoProc()函数开启的子进程,怎么样把消息函数组装到开启子进程的函数中呢?因为接收方需要注册消息函数,子进程由于没有GUI,所以搞了没搞成功。 命名管道
可以参考这篇:https://blog.csdn.net/sinat_31608641/article/details/106868309 学习了,感谢分享! 感谢提供这么全面的教程 smooth 发表于 2022-5-20 18:50
在两个独立的文件之间可以传递,但如果是在一个AU3文件里面的由_CoProc()函数开启的子进程,怎么样把消息 ...
看_coprocsend函数 子进程可以guicreate窗口,这个窗口并不需要显示 本帖最后由 smooth 于 2022-5-21 23:04 编辑
tubaba 发表于 2022-5-21 21:44
子进程可以guicreate窗口,这个窗口并不需要显示
大佬,我之前只会用_CoProcSend把子进程的信息发送给母进程,我现在试着用_CoProcSend向子进程发送消息,测试发现可以。
但是奇怪的是,我发送3个变量,中间用|分割,子进程接收后,分割出来,为什么第3个变量本来是个True,却只收到的一个T呢?
如果我增加一个参数,则第3个传送又是完整的,第4个则又不完整,咋回事呢?如果是放在函数_CoProc里作为参数传递,则没有问题。
本帖最后由 smooth 于 2022-5-23 08:13 编辑
tubaba 发表于 2022-5-21 21:44
子进程可以guicreate窗口,这个窗口并不需要显示
用你的方法,搞成了,把子进程的窗口句柄,传递给母进程,然后就可以用你的方法发送消息了。
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 Then Return SetError(3, 0, False) ; SendMessageTimeout Failed
If $aTmp <> 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 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 Then Return SetError(3, 0, False) ; SendMessageTimeout Failed
If $aTmp <> 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 Then Return SetError(4, 0, False)
Return True
EndFunc ;==>_CoProcSend
另外,coproc这个UDF确实很强大,稍微改造了一番,我用它完成了一个终端管理软件,甚至用创建的子进程再去创建另一子进程,运行的结果跳过父进程直接发送给祖进程。曲线实现了多任务并发,任务间完全独立的基本功能。
真棒,双手鼓掌
页:
[1]
2