記錄一下 WPF進(jìn)程 SendMessage 發(fā)送窗口消息進(jìn)行進(jìn)程間通信,存在進(jìn)程權(quán)限無法接受消息的問題
當(dāng)前位置:點晴教程→知識管理交流
→『 技術(shù)文檔交流 』
前言最近在接手一個同事寫的WPF項目,是使用.NetFramwork 開發(fā)的,使用的進(jìn)程間通信沒有使用我們之前封裝的基于WebSocket的封裝組件的,而是使用Win32的方式:發(fā)送端用的Windows Api:SendMessage ,接受端使用的是 鉤子監(jiān)聽windows 的消息回傳。 相信很多做桌面應(yīng)用的,這種通信應(yīng)該都是很常用,并且見怪不怪的??墒强赡芎芏鄾]有注意到進(jìn)程權(quán)限的情況,這種通信存在有坑,并且這個坑還埋的挺深的。 遇到的問題由于該WPF的項目的啟動方式存在很多方式,如果桌面點擊的方式(普通權(quán)限的),右鍵管理員啟動的方式(管理員權(quán)限的),開機(jī)自啟的方式(System權(quán)限降權(quán)的方式,普通權(quán)限),OTA之后啟動(管理員權(quán)限),這樣就會出現(xiàn)該進(jìn)程窗口可能啟動后的權(quán)限是不可預(yù)見的,并且用戶是可以隨意的變更用戶權(quán)限去啟動。然而,在一次測試中,做了升級后,啟用了該應(yīng)用,其他跟它通信的進(jìn)程就無法跟該進(jìn)程通信的。很詭異,只要是OTA之后,其他進(jìn)程就無法通信,開機(jī)之后(普通權(quán)限)就可以通信。觀察了日志,又沒有報什么異常。 復(fù)現(xiàn)問題一、創(chuàng)建一個WPF消息 發(fā)送端 <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="發(fā)送" 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 結(jié)構(gòu) [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 { //釋放分配的內(nèi)存,即使發(fā)生異常也不會泄漏資源 Marshal.FreeHGlobal(cds.lpData); } } #endregion } }
二、創(chuàng)建一個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="接收到的數(shù)據(jù):"/> <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 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 結(jié)構(gòu) [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 = ""; } }
三、結(jié)果 1、倆個都是管理員權(quán)限的,是可以接受到數(shù)據(jù)的
2、倆個進(jìn)程都是普通權(quán)限的,是可以接受到數(shù)據(jù) 3、發(fā)送端是管理員權(quán)限,接收端是 普通權(quán)限,是可以接受到數(shù)據(jù)
4、發(fā)送端是普通權(quán)限,接收端是 管理員權(quán)限,是接受不到數(shù)據(jù)
總結(jié):1、進(jìn)程間通信,最好使用無權(quán)限限制的方案 2、使用ChangeWindowMessageFilterEx 進(jìn)行權(quán)限過濾 轉(zhuǎn)自https://www.cnblogs.com/wuty/p/19137419 該文章在 2025/10/13 8:08:09 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |