vista之后的windows引入了UAC(用户账户控制),意味着在同一个windows用户账号下,允许用户进程在运行时拥有不同的权限级别。而且低级别的进程不能向高级别进程发送消息,完成这件事情的技术叫做UIPI(用户界面特权隔离)。
如果在实际项目中出现了这种两个进程间无法发送消息时,应该第一时间排查是否是因为进程运行权限导致的问题。最简单直观的方式可以通过提升各自软件的权限看是否还存在这种问题。当然最好还是借助下工具,可以把问题看得更加透彻。推荐使用Windows Sysinternals 的Process Explorer查看权限级别。具体使用方法如下:
运行软件后选择添加列:
通过查看Integrity(完整性)列,既可以看出来各个进程运行时权限。
在确定是该问题后,如何解决呢?其实微软为了兼容之前版本的软件,已经提供了api帮助处理这种情况,具体的api是ChangeWindowMessageFilter和ChangeWindowMessageFilterEx,可以自行查看msdn。
如果我们想容许一个消息可以发送给较高特权等级的进程,我们可以在较高特权等级的进程中调用ChangeWindowMessageFilter函数,以MSGFLT_ADD作为参数将消息添加进消息过滤器的白名单。同样的,我们也可以以MSGFLT_REMOVE作为参数将这个消息从白名单中删除。
顺便说明下UIPI的其他限制:
较低权限的应用程序不能做如下操作:
• 验证更高权限进程创建的窗口。调用 SendMessage 或 PostMessage到更高权限进程创建的窗口
• 使用线程钩子来附加一个更高权限的进程。
• 使用日志钩子(SetWindowsHookEx) 来监视更高权限的进程
• DLL注入到更高权限的进程。
另外下列windows消息永远是允许状态:
• 0x000 - WM_NULL
• 0x003 - WM_MOVE
• 0x005 - WM_SIZE
• 0x00D - WM_GETTEXT
• 0x00E - WM_GETTEXTLENGTH
• 0x033 - WM_GETHOTKEY
• 0x07F - WM_GETICON
• 0x305 - WM_RENDERFORMAT
• 0x308 - WM_DRAWCLIPBOARD
• 0x30D - WM_CHANGECBCHAIN
• 0x31A - WM_THEMECHANGED