找回密码
 立即注册
首页 业界区 业界 记录一下 WPF进程 SendMessage 发送窗口消息进行进程间 ...

记录一下 WPF进程 SendMessage 发送窗口消息进行进程间通信

桂册 9 小时前
前言

最近在接手一个同事写的WPF项目,是使用.NetFramwork 开发的,使用的进程间通信没有使用我们之前封装的基于WebSocket的封装组件的,而是使用Win32的方式:发送端用的Windows Api:SendMessage ,接受端使用的是 钩子监听windows 的消息回传。
相信很多做桌面应用的,这种通信应该都是很常用,并且见怪不怪的。可是可能很多没有注意到进程权限的情况,这种通信存在有坑,并且这个坑还埋的挺深的。
遇到的问题

由于该WPF的项目的启动方式存在很多方式,如果桌面点击的方式(普通权限的),右键管理员启动的方式(管理员权限的),开机自启的方式(System权限降权的方式,普通权限),OTA之后启动(管理员权限),这样就会出现该进程窗口可能启动后的权限是不可预见的,并且用户是可以随意的变更用户权限去启动。然而,在一次测试中,做了升级后,启用了该应用,其他跟它通信的进程就无法跟该进程通信的。很诡异,只要是OTA之后,其他进程就无法通信,开机之后(普通权限)就可以通信。观察了日志,又没有报什么异常。
复现问题

一、创建一个WPF消息 发送端
  1. [/code] [code]namespace FramworkSender { ///  /// MainWindow.xaml 的交互逻辑 ///  public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { } private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { // 获取接收窗口的句柄 IntPtr hwnd = FindWindow(null, "FramworkReceieve"); if (hwnd == IntPtr.Zero) { MessageBox.Show("找不到窗口"); } else { SendMessageString(hwnd, "123"); } } #region RegisterWindow [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); private uint _customMessageId; #endregion #region CopyData [DllImport("user32.dll")] public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); public const int WM_COPYDATA = 0x004A; // 定义 COPYDATASTRUCT 结构 [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } public static void SendMessageString(IntPtr hWnd, string message) { if (string.IsNullOrEmpty(message)) return; byte[] messageBytes = Encoding.Unicode.GetBytes(message + '\0'); COPYDATASTRUCT cds = new COPYDATASTRUCT(); cds.dwData = IntPtr.Zero; cds.cbData = messageBytes.Length; cds.lpData = Marshal.AllocHGlobal(cds.cbData); Marshal.Copy(messageBytes, 0, cds.lpData, cds.cbData); try { var result = SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds); } finally { //释放分配的内存,即使发生异常也不会泄漏资源 Marshal.FreeHGlobal(cds.lpData); } } #endregion } }
复制代码
 
二、创建一个WPF 消息 的接收端
复制代码
  1. ///  /// MainWindow.xaml 的交互逻辑 ///  public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; } private uint _customMessageId; private HwndSource _hwndSource; private void MainWindow_Loaded(object sender, RoutedEventArgs e) { _customMessageId = RegisterWindowMessage("MyApp"); // 获取窗口句柄并添加消息钩子 _hwndSource = PresentationSource.FromVisual(this) as HwndSource; _hwndSource?.AddHook(WndProc); } [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string content; private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { #region CopyData if (msg == WM_COPYDATA) { COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT)); string receivedMessage = Marshal.PtrToStringUni(cds.lpData); this.Dispatcher.Invoke(() => { txtMessage.Text = receivedMessage; }); handled = true; } #endregion return IntPtr.Zero; } #region RegisterWindows [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] private static extern uint RegisterWindowMessage(string lpString); #endregion #region CopyData public const int WM_COPYDATA = 0x004A; // 定义 COPYDATASTRUCT 结构 [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } #endregion protected override void OnClosed(EventArgs e) { _hwndSource?.RemoveHook(WndProc); base.OnClosed(e); } private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { txtMessage.Text = ""; } }
复制代码
 
三、结果
1、俩个都是管理员权限的,是可以接受到数据的
1.png

 
2、俩个进程都是普通权限的,是可以接受到数据
2.png

 3、发送端是管理员权限,接收端是 普通权限,是可以接受到数据
3.png

 
4、发送端是普通权限,接收端是 管理员权限,是接受不到数据
4.png

 
 总结:

1、进程间通信,最好使用无权限限制的方案
2、使用ChangeWindowMessageFilterEx 进行权限过滤
 

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册