64位進程和32位進程通信問題,接收端收不到 SendMessage發送的消息


 

最近在做一個項目的時候,采用了win32的SendMessage方法來發送數據,本來都沒問題,后來增加了一個項目,必須采用的目標平台是x64的,沒想到居然沒辦法通信了。

網上找了很久解決方案,整整嘗試了一個周,終於解決了,居然是因為一個小小的參數類型引發的血案,所以記錄下來,希望后面的同學別再跟我一樣犯這樣的錯誤啦!

 

參照以下3篇文章

https://blog.csdn.net/zaijzhgh/article/details/52171577

https://blog.csdn.net/xiaofeizai1116/article/details/54315895

https://www.cnblogs.com/mr-yoatl/p/7523835.html

原來是定義發送跟接收的結構體的一個類型定義的又問題,就是文中紅色注釋前面那句,之前定義的是int,現在改為IntPtr,就可以在32位和64位之間通信了

 

  1 public class Win32API
  2 {
  3 public const int WM_COPYDATA = 0X004A;//消息類型
  4 private const int WH_CALLWNDPROC = 4;    //鈎子類型(監視SendMessage消息的傳遞)  
  5 public const int USER = 0X61;
  6 //以上為C#端發送,值得注意的就是:    
  7 //1>C#的結構體定義時要設置內存布局為順序布局(即[StructLayout(LayoutKind.Sequential)])。    
  8 //2>如果結構體有字符串,記得要設置其大小(即[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)])。    
  9 //3>如果是C#端發送到C++端,記得把要發送的COPYDATASTRUCT 對象開辟一段“非托管內存”,然后賦值發送,因為C#內存機制為自動回收(就是系統幫你托  
 10 //管了,你不必擔心內存泄漏問題),這樣若果你不開辟直接發送的話,出了這個函數作用域,局部內存就會被回收,也就發送不到C++端了(你可以理解
 11 //為C++的局部變量的意思),因此要用Marshal.AllocHGlobal一份,賦值在發送,發送完記得釋放掉
 12 //C#端鈎子截獲的消息的結構(對應WH_CALLWNDPROC)  
 13 //mbd 這個結構我找了好久,什么鈎子對應什么結構  
 14 //網上只有監聽鼠標啊,鍵盤啥的鈎子結構,很少有監聽SendMessage消息的鈎子結構,為此度娘了一番,msdn了一番,  
 15 //找到鈎子回調的原型函數ShellPro,然后幾經周折發現CWPSTRUCT這個結構,看着有點兒眼熟,發現是上面那篇博客有提到過,  
 16 //於是再看了看,尼瑪有點怪,於是在msdn該結構類型,加上[StructLayout(LayoutKind.Sequential)],    
 17 //轉換C#類型,調試,然后終於是ok了
 18 //這里COPYDATASTRUCT對應C++的COPYDATASTRUCT,只不過是把它轉為C#結構體  
 19 //注意結構體上面要加上[StructLayout(LayoutKind.Sequential)],表示結構體為順序布局
 20 //啟用非托管代碼 
 21 [StructLayout(LayoutKind.Sequential)]
 22 public struct COPYDATASTRUCT
 23 {
 24 public IntPtr  dwData; //可以是任意值 ,必須是IntPtr類型,否則32位跟64位無法通信
 25 public int cbData; //長度  //指定lpData內存區域的字節數
 26 [MarshalAs(UnmanagedType.LPStr)]
 27 public string lpData; //發送給目錄窗口所在進程的數據
 28 
 29 }
 30 
 31 [DllImport("User32.dll")]
 32 public static extern int SendMessage(
 33 IntPtr hWnd, // handle to destination window 
 34 int Msg, // message 
 35 IntPtr wParam, // first message parameter 
 36 ref COPYDATASTRUCT pcd // second message parameter 
 37 );
 38 
 39 [DllImport("User32.dll", EntryPoint = "FindWindow")]
 40 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);//查找主目標窗體的運行句柄
 41 
 42 [DllImport("Kernel32.dll", EntryPoint = "GetConsoleWindow")]
 43 public static extern IntPtr GetConsoleWindow();
 44 
 45 private static class NativeMethods
 46 {
 47 internal const uint GW_OWNER = 4;
 48 
 49 internal delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
 50 
 51 [DllImport("User32.dll", CharSet = CharSet.Auto)]
 52 internal static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);
 53 
 54 [DllImport("User32.dll", CharSet = CharSet.Auto)]
 55 internal static extern int GetWindowThreadProcessId(IntPtr hWnd, out IntPtr lpdwProcessId);
 56 
 57 [DllImport("User32.dll", CharSet = CharSet.Auto)]
 58 internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
 59 
 60 [DllImport("User32.dll", CharSet = CharSet.Auto)]
 61 internal static extern bool IsWindowVisible(IntPtr hWnd);
 62 }
 63 
 64 public static IntPtr GetMainWindowHandle(int processId)
 65 {
 66 IntPtr MainWindowHandle = IntPtr.Zero;
 67 
 68 NativeMethods.EnumWindows(new NativeMethods.EnumWindowsProc((hWnd, lParam) =>
 69 {
 70 IntPtr PID;
 71 NativeMethods.GetWindowThreadProcessId(hWnd, out PID);
 72 
 73 if (PID == lParam &&
 74 //NativeMethods.IsWindowVisible(hWnd) &&
 75 NativeMethods.GetWindow(hWnd, NativeMethods.GW_OWNER) == IntPtr.Zero)
 76 {
 77 MainWindowHandle = hWnd;
 78 return false;
 79 }
 80 
 81 return true;
 82 
 83 }), new IntPtr(processId));
 84 
 85 return MainWindowHandle;
 86 }
 87 
 88 /// <summary>
 89 /// 發送消息的方法
 90 /// </summary>
 91 /// <param name="message"></param>
 92 public static void SendMsg(string deviceName,string message)
 93 {
 94 string msg = deviceName + "^" + message;
 95 IntPtr maindHwnd = Win32API.FindWindow(null, "DDD窗體名稱"); //獲得主程序的句柄
 96 IntPtr hwndSendWindow = Process.GetCurrentProcess().Handle; //自己的進程句柄
 97 Win32API.COPYDATASTRUCT copydata = new Win32API.COPYDATASTRUCT();
 98 copydata.cbData = Encoding.Default.GetBytes(msg).Length+1; //長度 注意不要用strText.Length; 
 99 copydata.lpData = msg;//內容 
100 Win32API.SendMessage(maindHwnd, Win32API.WM_COPYDATA, hwndSendWindow, ref copydata);
101 }
102 
103 }
104 
105 
106 
107 
108 
109 
110 
111 接收消息的方法
112 
113 /// <summary>
114 /// 重寫調用消息處理函數
115 /// </summary>
116 /// <param name="m">message消息</param>
117 protected override void WndProc(ref System.Windows.Forms.Message m)
118 {
119 try
120 {
121 switch (m.Msg)
122 {
123 case Win32API.WM_COPYDATA:
124 Win32API.COPYDATASTRUCT myStr = new Win32API.COPYDATASTRUCT();
125 Type myType = myStr.GetType();
126 myStr = (Win32API.COPYDATASTRUCT)m.GetLParam(myType); //m中獲取LParam參數以myType類型的方式,讓后轉換問結構體。
127 string lpData = myStr.lpData;
128 var lpArr = lpData.Split('^'); //接收子驅動發送的消息,解析消息,lpArr[0]表示驅動名稱,lpArr[1],表示接收的消息內容
129 if (lpArr.Length > 1)
130 {
131 WriteMsg(lpArr[0], lpData.Substring(lpData.IndexOf("^") + 1)); //將消息顯示在右側消息框中
132 }
133 break;
134 default:
135 // base.WndProc(ref m);s
136 break;
137 }
138 }
139 catch (Exception ex)
140 {
141 log4netHelp.Error(ex.Message);
142 }
143 
144 base.WndProc(ref m);
145 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM