博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
64位进程和32位进程通信问题,接收端收不到 SendMessage发送的消息
阅读量:4309 次
发布时间:2019-06-06

本文共 5003 字,大约阅读时间需要 16 分钟。

 

最近在做一个项目的时候,采用了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 ///  89 /// 发送消息的方法 90 ///  91 ///  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 /// 114 /// 重写调用消息处理函数115 /// 116 /// message消息117 protected override void WndProc(ref System.Windows.Forms.Message m)118 {119 try120 {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);s136 break;137 }138 }139 catch (Exception ex)140 {141 log4netHelp.Error(ex.Message);142 }143 144 base.WndProc(ref m);145 }

 

转载于:https://www.cnblogs.com/sharestone/p/9373492.html

你可能感兴趣的文章
laravel连接sql server 2008
查看>>
Laravel 操作redis的各种数据类型
查看>>
Laravel框架学习笔记之任务调度(定时任务)
查看>>
laravel 定时任务秒级执行
查看>>
浅析 Laravel 官方文档推荐的 Nginx 配置
查看>>
Swagger在Laravel项目中的使用
查看>>
Laravel 的生命周期
查看>>
CentOS Docker 安装
查看>>
Nginx
查看>>
Navicat远程连接云主机数据库
查看>>
Nginx配置文件nginx.conf中文详解(总结)
查看>>
Mysql出现Table 'performance_schema.session_status' doesn't exist
查看>>
MySQL innert join、left join、right join等理解
查看>>
vivado模块封装ip/edf
查看>>
sdc时序约束
查看>>
Xilinx Jtag Access/svf文件/BSCANE2
查看>>
NoC片上网络
查看>>
开源SoC整理
查看>>
【2020-3-21】Mac安装Homebrew慢,解决办法
查看>>
influxdb 命令行输出时间为 yyyy-MM-dd HH:mm:ss(年月日时分秒)的方法
查看>>