• 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 }
  • 相关阅读:
    jstl <c:url>标签
    4.12快速分类
    2.递归回溯求子集和数问题
    计算圆面积
    openal在vs2010中的配置
    结构体数组排序
    检测信号的有无
    matlab中mat文件简单存/取
    m文件转换c代码
    安装fftw到window(vs2010)及使用fftw库函数实现4096点fft变换计算
  • 原文地址:https://www.cnblogs.com/sharestone/p/9373492.html
Copyright © 2020-2023  润新知