当前位置: 首页 > news >正文

记录一下 WPF进程 SendMessage 发送窗口消息进行进程间通信,存在进程权限无法接受消息的问题

前言

最近在接手一个前同事写的WPF项目,是使用.NetFramwork 开发的,使用的进程间通信没有使用我们之前封装的基于WebSocket的封装组件的,而是使用Win32的方式:发送端用的Windows Api:SendMessage ,接受端使用的是 钩子监听windows 的消息回传。

相信很多做桌面应用的,这种通信应该都是很常用,并且见怪不怪的。可是可能很多没有注意到进程权限的情况,这种通信存在有坑,并且这个坑还埋的挺深的。

遇到的问题

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

复现问题

一、创建一个WPF消息 发送端

<Window x:Class="FramworkSender.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:FramworkSender"mc:Ignorable="d"Title="FramworkSender" Height="450" Width="800"><Grid><Button Width="100" Height="100" Content="发送" Click="ButtonBase_OnClick"></Button></Grid>
namespace FramworkSender
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>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 消息 的接收端

<Window x:Class="FramworkReceieve.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:FramworkReceieve"mc:Ignorable="d"Title="FramworkReceieve" Height="450" Width="800"><Grid><StackPanel Orientation="Horizontal"><TextBlock Text="接收到的数据:"/><TextBlock Text="" x:Name="txtMessage"/></StackPanel><Button Height="100" Width="100" Content="清空" Click="ButtonBase_OnClick"></Button></Grid>
</Window>
    /// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>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 CopyDataif (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;}#endregionreturn IntPtr.Zero;}#region  RegisterWindows[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]private static extern uint RegisterWindowMessage(string lpString);#endregion#region CopyDatapublic const int WM_COPYDATA = 0x004A;// 定义 COPYDATASTRUCT 结构
        [StructLayout(LayoutKind.Sequential)]public struct COPYDATASTRUCT{public IntPtr dwData;public int cbData;public IntPtr lpData;}#endregionprotected override void OnClosed(EventArgs e){_hwndSource?.RemoveHook(WndProc);base.OnClosed(e);}private void ButtonBase_OnClick(object sender, RoutedEventArgs e){txtMessage.Text = "";}}

 

三、结果

1、俩个都是管理员权限的,是可以接受到数据的

image

 

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

image

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

image

 

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

image

 

 总结:

1、进程间通信,最好使用无权限限制的方案

2、使用ChangeWindowMessageFilterEx 进行权限过滤

 

http://www.hskmm.com/?act=detail&tid=29672

相关文章:

  • 正睿25noip十连测day5
  • kettle插件-dm数据库插件,解决kettle9.X版本无法连接数据库资源库问题
  • 2025年10月武汉防水公司TOP5权威推荐榜:专业施工与优质服务的行业
  • 2025开发区婚纱照公司最新权威推荐榜:创意拍摄与贴心服务的
  • 用户交互scanner方法学习及使用示例
  • 2025工业网线厂家最新权威推荐榜:稳定传输与耐用品质的首选
  • 完整教程:STM32H743-ARM例程11-PWM
  • 20231427田泽航实验一-4
  • 2025铝合金微弧氧化定制厂家权威推荐榜:品质卓越与技术创新
  • 20231427田泽航实验一-3
  • 信息安全设计/密码系统设计 实验1-1
  • 2025年10月拉伸器厂家最新权威推荐榜:高效稳定与卓越品质的行业首
  • 2025数粒机厂家最新权威推荐榜:精准高效与智能控制的行业首
  • Spring拦截器HandlerInterceptor与Filter方法执行顺序探究
  • 2025精加工车间恒温恒湿系统TOP5榜单:精准控温与高效节
  • 第四章作业
  • 2025数控滚齿机订制厂家权威推荐:高精度与高效能的首选品牌
  • 2025婚纱摄影工作室权威推荐榜:捕捉幸福瞬间的创意大师
  • 详细介绍:初学者小白复盘11之——指针(1)
  • 2025-10-12
  • hex、bin、axf文件的区别
  • 20232417 2025-2026-1 《网络与系统攻防技术》实验一实验报告
  • 2025黄金回收品牌TOP5权威榜单:值得信赖的高性价比厂家
  • [数据分析/BI] Microsoft Power BI 使用指南
  • 机器人技术在现实世界中的挑战与创新
  • Motorola和Inter的区别
  • ROS2之TF
  • 深入解析:2025年真实手机牧场CC攻击破防游戏盾?四维防御体系全面升级!
  • 代码源2025长训
  • 代码源国庆模拟赛