利用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 255) As Byte
27     Dim a As String, i 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     Call CopyMemory(buf(1), ByVal a$, Len(a$))
34     cds.dwData = 3
35     cds.cbData = Len(a$) + 1
36     cds.lpData = VarPtr(buf(1))
37     i = SendMessage(ThWnd, WM_COPYDATA, Me.hwnd, cds)
38 End Sub
39   
40 Private Sub Form_Load()
41      This gives you visibility that the target app is running
42      and you are pointing to the correct hWnd
43     Me.Caption = Hex$(FindWindow(vbNullString, "Target"))
44 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 255) 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 }

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。