利用COPYDATASTRUCT传递命令行参数给驻留内存的进程(SendMessage应用)
我们知道Window进程之间通过API的SendMessage方法传递消息。但是方法参数lParam是Long型,那么如果传递一个字符串(譬如命令行参数)应该怎么办呢,甚至一个对象、结构呢。VB的发送接收需要通过传递指针实现(换言之是字符串的内存地址),下面总结VB方式、C#方式各自如何实现消息的发送与接收;各自是可以互换的,譬如C#发送的消息,VB窗口可以收到;相反亦可以。当然同种语言之间更加没问题了。
VB发送端 Form1.frm:
1 Option Explicit 2 3 Private Type COPYDATASTRUCT 4 dwData As Long 5 cbData As Long 6 lpData As Long 7 End Type 8 9 Private Const WM_COPYDATA = &H4A 10 11 Private Declare Function FindWindow Lib "user32" Alias _ 12 "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName _ 13 As String) As Long 14 15 Private Declare Function SendMessage Lib "user32" Alias _ 16 "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal _ 17 wParam As Long, lParam As Any) As Long 18 19 'Copies a block of memory from one location to another. 20 Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ 21 (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long) 22 23 Private Sub Command1_Click() 24 Dim cds As COPYDATASTRUCT 25 Dim ThWnd As Long 26 Dim buf(1 To 1024) As Byte 27 Dim a As String, i As Long, lLen As Long 28 29 ' Get the hWnd of the target application 30 ThWnd = FindWindow(vbNullString, "Target") 31 a$ = "It Works on " & Format(Now, "yyyy-MM-dd HH:mm:ss") & " !" 32 ' Copy the string into a byte array, converting it to ASCII 33 lLen = LenB(StrConv(a, vbFromUnicode)) 34 Call CopyMemory(buf(1), ByVal a, lLen) 35 cds.dwData = 3 36 cds.cbData = lLen + 1 37 cds.lpData = VarPtr(buf(1)) 38 i = SendMessage(ThWnd, WM_COPYDATA, Me.hwnd, cds) 39 End Sub 40 41 Private Sub Form_Load() 42 ' This gives you visibility that the target app is running 43 ' and you are pointing to the correct hWnd 44 Me.Caption = Hex$(FindWindow(vbNullString, "Target")) 45 End Sub
VB接收端
1。MsgHook.bas:
1 Option Explicit 2 3 Type COPYDATASTRUCT 4 dwData As Long 5 cbData As Long 6 lpData As Long 7 End Type 8 9 Public Const GWL_WNDPROC = (-4) 10 Public Const WM_COPYDATA = &H4A 11 Global lpPrevWndProc As Long 12 Global gHW As Long 13 14 'Copies a block of memory from one location to another. 15 Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ 16 (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long) 17 18 Declare Function CallWindowProc Lib "user32" Alias _ 19 "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As _ 20 Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As _ 21 Long) As Long 22 23 Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ 24 (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As _ 25 Long) As Long 26 27 Public Sub Hook() 28 lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, _ 29 AddressOf WindowProc) 30 Debug.Print lpPrevWndProc 31 End Sub 32 33 Public Sub Unhook() 34 Dim temp As Long 35 temp = SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc) 36 End Sub 37 38 Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, _ 39 ByVal wParam As Long, ByVal lParam As Long) As Long 40 If uMsg = WM_COPYDATA Then 41 Call mySub(lParam) 42 End If 43 WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam) 44 End Function 45 46 Sub mySub(lParam As Long) 47 Dim cds As COPYDATASTRUCT 48 Dim buf(1 To 1024) As Byte 49 Dim a As String 50 51 Call CopyMemory(cds, ByVal lParam, Len(cds)) 52 53 Select Case cds.dwData 54 Case 1 55 Debug.Print "got a 1" 56 Case 2 57 Debug.Print "got a 2" 58 Case 3 59 Call CopyMemory(buf(1), ByVal cds.lpData, cds.cbData) 60 a$ = StrConv(buf, vbUnicode) 61 a$ = Left$(a$, InStr(1, a$, Chr$(0)) - 1) 62 Form1.Label1.Caption = a$ 63 End Select 64 End Sub
2。Target.frm:
1 Option Explicit 2 3 Private Sub Form_Load() 4 gHW = Me.hwnd 5 Hook 6 Me.Caption = "Target" 7 Me.Show 8 Label1.Caption = Hex$(gHW) 9 End Sub 10 11 Private Sub Form_Unload(Cancel As Integer) 12 Unhook 13 End Sub
C#的发送端:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Data; 8 using System.Windows.Documents; 9 using System.Windows.Input; 10 using System.Windows.Media; 11 using System.Windows.Media.Imaging; 12 using System.Windows.Navigation; 13 using System.Windows.Shapes; 14 using System.Runtime.InteropServices; 15 16 namespace CSMsgSender 17 { 18 /// <summary> 19 /// MainWindow.xaml 的交互逻辑 20 /// </summary> 21 public partial class MainWindow : Window 22 { 23 public MainWindow() 24 { 25 InitializeComponent(); 26 } 27 28 private void button1_Click(object sender, RoutedEventArgs e) 29 { 30 int hwnd = FindWindow(null, "Target"); 31 if (hwnd != 0) 32 { 33 string str = "It Works on " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " !"; 34 byte[] arr = System.Text.Encoding.Default.GetBytes(str); 35 int len = arr.Length; 36 COPYDATASTRUCT cdata; 37 cdata.dwData = 3; 38 cdata.lpData = str; 39 cdata.cbData = len + 1; 40 SendMessage(hwnd, WM_COPYDATA, 10, ref cdata); 41 } 42 } 43 44 [DllImport("User32.dll")] 45 public static extern int SendMessage(int hwnd, int msg, int wParam, ref COPYDATASTRUCT lParam); 46 [DllImport("User32.dll")] 47 public static extern int FindWindow(string lpClassName, string lpWindowName); 48 49 private const int WM_COPYDATA = 0x004A; 50 public struct COPYDATASTRUCT 51 { 52 public int dwData; 53 public int cbData; 54 [MarshalAs(UnmanagedType.LPStr)] 55 public string lpData; 56 } 57 } 58 }
C#接收端:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.Runtime.InteropServices; 10 11 namespace CSMsgReceiver 12 { 13 public partial class Form1 : Form 14 { 15 public Form1() 16 { 17 InitializeComponent(); 18 this.Text = "Target"; 19 } 20 21 protected override void DefWndProc(ref Message m) 22 { 23 switch (m.Msg) 24 { 25 case WM_COPYDATA: 26 COPYDATASTRUCT cdata = new COPYDATASTRUCT(); 27 Type mytype = cdata.GetType(); 28 cdata = (COPYDATASTRUCT)m.GetLParam(mytype); 29 this.textBox1.Text = cdata.lpData; 30 break; 31 default: 32 base.DefWndProc(ref m); 33 break; 34 } 35 } 36 37 //WM_COPYDATA消息的主要目的是允许在进程间传递只读数据。 38 private const int WM_COPYDATA = 0x004A; 39 40 //Windows在通过WM_COPYDATA消息传递期间,不提供继承同步方式。 41 //其中,WM_COPYDATA对应的十六进制数为0x004A 42 public struct COPYDATASTRUCT 43 { 44 public int dwData; 45 public int cbData; 46 [MarshalAs(UnmanagedType.LPStr)] 47 public string lpData; 48 } 49 } 50 }