news 2026/9/12 0:56:10

WPF 调用 ChangeWindowMessageFilterEx 修改指定窗口 (UIPI) 消息筛选器的用户界面特权隔离

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WPF 调用 ChangeWindowMessageFilterEx 修改指定窗口 (UIPI) 消息筛选器的用户界面特权隔离

说到了 发送端是普通权限的窗体 给 接收端是 管理员权限的窗体,通过 Win32 API的方式调用 SendMessage 发送窗口消息,管理员权限的窗体的钩子消息回传接受不到发送端的数据。

如下图所示:

image

这是由于 Windows系统在Windows NT6.0 开始,引入了受保护模式,阻止进程将所选窗口消息和其他 USER API 发送到运行完整性较高的进程

详情请看微软的详细说明:

受保护的模式 - Win32 apps | Microsoft Learn

Windows 完整性机制设计 | Microsoft Learn

二、函数说明

针对于以上的问题,微软也提供了相对应的接口来规避: ChangeWindowMessageFilterEx

ChangeWindowMessageFilterEx 函数 (winuser.h)

修改指定窗口 (UIPI) 消息筛选器的用户界面特权隔离。

语法

复制代码

BOOL ChangeWindowMessageFilterEx(

[in] HWND hwnd,

[in] UINT message,

[in] DWORD action,

[in, out, optional] PCHANGEFILTERSTRUCT pChangeFilterStruct

);

复制代码

参数

[in] hwnd

类型:HWND

要修改其 UIPI 消息筛选器的窗口的句柄。

[in] message

类型: UINT

消息筛选器允许通过 或 阻止的消息。

[in] action

类型:DWORD

要执行的操作,可以采用以下值之一:

值 含义

MSGFLT_ALLOW

1

允许消息通过筛选器。 这使 hWnd 能够接收消息,无论消息的来源如何,即使消息来自较低特权进程也是如此。

MSGFLT_DISALLOW

2

阻止消息从较低特权进程传递到 hWnd ,除非使用 ChangeWindowMessageFilter 函数或全局允许该消息在进程范围内传递。

MSGFLT_RESET

0

将 hWnd 的窗口消息筛选器重置为默认值。 允许全局或进程范围内的任何消息都将通过,但任何未包含在这两个类别中以及来自较低特权进程的消息都将被阻止。

[in, out, optional] pChangeFilterStruct

类型: PCHANGEFILTERSTRUCT

指向 CHANGEFILTERSTRUCT 结构的可选指针。

返回值

类型: BOOL

如果函数成功,则返回 TRUE;否则,它将返回 FALSE。 要获得更多的错误信息,请调用 GetLastError。

注解

UIPI 是一项安全功能,可防止从较低完整性级别的发件人接收消息。 可以使用此函数允许将特定消息传递到窗口,即使消息源自较低完整性级别的进程也是如此。 与控制进程消息筛选器的 ChangeWindowMessageFilter 函数不同, ChangeWindowMessageFilterEx 函数控制窗口消息筛选器。

应用程序可以使用 ChangeWindowMessageFilter 函数以进程范围的方式允许或阻止消息。 如果进程消息筛选器或窗口消息筛选器允许该消息,则会将其传递到窗口。

请注意,不允许 SECURITY_MANDATORY_LOW_RID 或以下的进程更改消息筛选器。 如果这些进程调用此函数,它将失败并生成扩展错误代码, ERROR_ACCESS_DENIED。

无论筛选器设置如何,值小于 WM_USER 的某些消息都需要通过筛选器传递。 尝试使用此函数允许或阻止此类消息时,将不起作用。

三、如何使用

1、WPF 的接受端窗口增加 对 ChangeWindowMessageFilterEx 函数的定义和封装

复制代码

// 定义MessageFilterAction 结构体

public enum MessageFilterAction : uint

{

MSGFLT_RESET = 0, // 重置过滤器

MSGFLT_ALLOW = 1, // 允许消息

MSGFLT_DISALLOW = 2 // 禁止消息

}

// 定义 消息过滤器状态结构体

[StructLayout(LayoutKind.Sequential)]

public struct CHANGEFILTERSTRUCT

{

public uint cbSize;

public uint ExtStatus;

}

// 导入 user32.dll 中的函数

[DllImport("user32.dll", SetLastError = true)]

private static extern bool ChangeWindowMessageFilterEx(

IntPtr hWnd,

uint msg,

MessageFilterAction action,

ref CHANGEFILTERSTRUCT pChangeFilterStruct);

/// <summary>

/// 设置消息过滤

/// </summary>

/// <param name="hWnd"></param>

/// <param name="message"></param>

/// <param name="action"></param>

/// <returns></returns>

/// <exception cref="System.ComponentModel.Win32Exception"></exception>

public static bool SetMessageFilter(IntPtr hWnd, uint message, MessageFilterAction action)

{

// 初始化结构体

CHANGEFILTERSTRUCT changeFilter = new CHANGEFILTERSTRUCT

{

cbSize = (uint)Marshal.SizeOf(typeof(CHANGEFILTERSTRUCT)),

ExtStatus = 0

};

// 调用 API

bool result = ChangeWindowMessageFilterEx(hWnd, message, action, ref changeFilter);

if (!result)

{

// 获取错误信息(可选)

int error = Marshal.GetLastWin32Error();

throw new System.ComponentModel.Win32Exception(error);

}

return result;

}

复制代码

2、在接收数据的 FramworkReceieve 窗口 的Loaded时间调用 SetMessageFilter,最主要的是第三个参数需要设置:MessageFilterAction.MSGFLT_ALLOW

复制代码

private void MainWindow_Loaded(object sender, RoutedEventArgs e)

{

_customMessageId = RegisterWindowMessage("MyApp");

// 获取窗口句柄并添加消息钩子

_hwndSource = PresentationSource.FromVisual(this) as HwndSource;

if (_hwndSource != null)

{

var handle = _hwndSource.Handle;

SetMessageFilter(handle, WM_COPYDATA, MessageFilterAction.MSGFLT_ALLOW);

_hwndSource.AddHook(WndProc);

}

}

复制代码

3、完整代码如下:

消息发送端:

复制代码

<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>

</Window>

复制代码

复制代码

namespace FramworkSender

{

/// <summary>

/// MainWindow.xaml 的交互逻辑

/// </summary>

public partial class MainWindow : Window

{

public MainWindow()

{

InitializeComponent();

}

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)

{

// 获取接收窗口的句柄

IntPtr hwnd = FindWindow(null, "FramworkReceieve");

if (hwnd == IntPtr.Zero)

{

MessageBox.Show("找不到窗口");

}

else

{

SendMessageString(hwnd, "123");

}

}

#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

}

}

复制代码

消息接收端:

复制代码

<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>

复制代码

复制代码

namespace FramworkReceieve

{

/// <summary>

/// MainWindow.xaml 的交互逻辑

/// </summary>

public partial class MainWindow : Window

{

public MainWindow()

{

InitializeComponent();

Loaded += MainWindow_Loaded;

}

private HwndSource _hwndSource;

private void MainWindow_Loaded(object sender, RoutedEventArgs e)

{

// 获取窗口句柄并添加消息钩子

_hwndSource = PresentationSource.FromVisual(this) as HwndSource;

if (_hwndSource != null)

{

var handle = _hwndSource.Handle;

SetMessageFilter(handle, WM_COPYDATA, MessageFilterAction.MSGFLT_ALLOW);

_hwndSource.AddHook(WndProc);

}

}

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 CopyData

public const int WM_COPYDATA = 0x004A;

// 定义 COPYDATASTRUCT 结构

[StructLayout(LayoutKind.Sequential)]

public struct COPYDATASTRUCT

{

public IntPtr dwData;

public int cbData;

public IntPtr lpData;

}

#endregion

// 定义MessageFilterAction 结构体

public enum MessageFilterAction : uint

{

MSGFLT_RESET = 0, // 重置过滤器

MSGFLT_ALLOW = 1, // 允许消息

MSGFLT_DISALLOW = 2 // 禁止消息

}

// 定义 消息过滤器状态结构体

[StructLayout(LayoutKind.Sequential)]

public struct CHANGEFILTERSTRUCT

{

public uint cbSize;

public uint ExtStatus;

}

// 导入 user32.dll 中的函数

[DllImport("user32.dll", SetLastError = true)]

private static extern bool ChangeWindowMessageFilterEx(

IntPtr hWnd,

uint msg,

MessageFilterAction action,

ref CHANGEFILTERSTRUCT pChangeFilterStruct);

/// <summary>

/// 设置消息过滤

/// </summary>

/// <param name="hWnd"></param>

/// <param name="message"></param>

/// <param name="action"></param>

/// <returns></returns>

/// <exception cref="System.ComponentModel.Win32Exception"></exception>

public static bool SetMessageFilter(IntPtr hWnd, uint message, MessageFilterAction action)

{

// 初始化结构体

CHANGEFILTERSTRUCT changeFilter = new CHANGEFILTERSTRUCT

{

cbSize = (uint)Marshal.SizeOf(typeof(CHANGEFILTERSTRUCT)),

ExtStatus = 0

};

// 调用 API

bool result = ChangeWindowMessageFilterEx(hWnd, message, action, ref changeFilter);

if (!result)

{

// 获取错误信息(可选)

int error = Marshal.GetLastWin32Error();

throw new System.ComponentModel.Win32Exception(error);

}

return result;

}

protected override void OnClosed(EventArgs e)

{

_hwndSource?.RemoveHook(WndProc);

base.OnClosed(e);

}

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)

{

txtMessage.Text = "";

}

}

}

复制代码

4、运行结果:

接收端是管理员权限,发送端是普通权限,可以收发数据了

image

四、总结

1、调用 ChangeWindowMessageFilterEx 需要设置第三个参数 action 的值为 枚举 :MessageFilterAction.MSGFLT_ALLOW,也就是数值 “1”。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 19:25:18

2025年软件工程/计算机科学与技术专业毕业设计选题推荐

&#x1f497;博主介绍&#xff1a;✌全网粉丝30W,CSDN全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云等平台优质作者,计算机毕设实战导师。目前专注于大学生项目实战开发,讲解,毕业答疑辅导✌ &#x1f497;主要服务内容&#xff1a;选题定题、开题报告、任务书…

作者头像 李华
网站建设 2026/9/11 17:04:00

NTFSTool:在macOS上实现NTFS磁盘完整读写的终极解决方案

NTFSTool&#xff1a;在macOS上实现NTFS磁盘完整读写的终极解决方案 【免费下载链接】ntfstool A ntfs tool for mac 项目地址: https://gitcode.com/gh_mirrors/nt/ntfstool 还在为Mac电脑无法正常编辑NTFS格式的移动硬盘而困扰吗&#xff1f;作为跨平台数据交换的常见…

作者头像 李华
网站建设 2026/9/12 3:36:27

Qwen3-Reranker-8B:重新定义文本检索效率与精度边界

Qwen3-Reranker-8B&#xff1a;重新定义文本检索效率与精度边界 【免费下载链接】Qwen3-Reranker-8B 项目地址: https://ai.gitcode.com/hf_mirrors/Qwen/Qwen3-Reranker-8B 在人工智能技术快速迭代的今天&#xff0c;文本检索作为信息处理的核心环节&#xff0c;其性能…

作者头像 李华
网站建设 2026/9/12 5:51:47

PingFang SC woff2字体:网页中文排版的终极解决方案

PingFang SC woff2字体&#xff1a;网页中文排版的终极解决方案 【免费下载链接】PingFangSC字体压缩版woff2介绍 本仓库提供了流行于数字平台的 PingFang SC 字体的压缩版本&#xff0c;采用 woff2 格式。这一系列字体以其清晰的显示效果和贴近简体中文阅读习惯的设计而广受欢…

作者头像 李华
网站建设 2026/9/11 20:24:44

ModernWMS开源仓库管理系统终极配置与功能详解

ModernWMS开源仓库管理系统终极配置与功能详解 【免费下载链接】ModernWMS The open source simple and complete warehouse management system is derived from our many years of experience in implementing erp projects. We stripped the original commercial system wms …

作者头像 李华
网站建设 2026/9/12 14:52:12

MPV播放器macOS硬件解码色彩异常终极修复指南

MPV播放器macOS硬件解码色彩异常终极修复指南 【免费下载链接】mpv &#x1f3a5; Command line video player 项目地址: https://gitcode.com/GitHub_Trending/mp/mpv 在macOS系统上使用MPV播放器进行硬件解码时&#xff0c;色彩异常问题严重影响观影体验。本文提供从问…

作者头像 李华