Internet Explorer_Server
容器(通俗来讲,就是Internet Explorer)或者在DirectUIHWND
容器(这是Microsoft专有的类,用于呈现他们未记录的UI),全部在窗口中使用WS_EX_TOPMOST
风格,这使它们渲染在其他内容之上。就是这样!让我们分割桌面并使用 Spy++
查看底层发生了什么:
如果我们查看“天气”应用程序窗口,它只是类名为“Internet Explorer_Server”的常规(Win32)窗口,该窗口位于“Web Platform Embedding”类的窗口中,而后者又位于具有WS_EX_TOPMOST
和WS_EX_NOREDIRECTIONBITMAP
样式的“Windows.UI.Core.CoreWindow”容器中:
WWAHOST.exe
进程运行的,简单来说,这是运行Metro应用程序JavaScript的容器。从中我们可以获得开始屏幕的窗口句柄(在我的情况下为0x10158
),并在Spy++中查找:
DirectUIHWND
,它位于一个名为ImmersiveLauncher
类的窗口内部,该窗口拥有WS_EX_TOPMOST
和WS_EX_NOREDIRECTIONBITMAP
样式,使其保持在顶部。这是它和任何由“桌面”应用程序创建的其他窗口之间唯一的区别。C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
"中呈现Windows.UI.Core.CoreWindow
类窗口。因此,不需要深入了解,显然可以将Metro风格应用程序封装在非Microsoft容器中,这对于不关心AppStore XAML应用程序的开发人员来说是一个好消息 :)在进程清单中设置UIAccess="true"
。您可以在Visual Studio中通过转到项目属性
->链接器
->清单文件
并将UAC Bypass UI Protection
设置为YES来完成此操作。(请注意,您可以保持UAC Execution Level
为asInvoker
,或者不要求提升您的进程权限。)
对您的进程进行代码签名。这很重要,因为没有签名它将无法工作,您将看到此错误消息:“从服务器返回了一个引用。”
除了签名(或在开发系统上进行测试的情况下),您可以将以下注册表键设置为0。 (尽管我没有尝试过,但由于明显的安全问题,我不建议这样做!但如果没有代码签名证书,则似乎是另一种测试的方式。)
HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\ValidateAdminCodeSignatures
%windir%\System32
文件夹中,或更现实的是放置在%ProgramFiles%\Company\Product
文件夹中,或者放置在另一个%ProgramFiles(X86)%\Company\Product
文件夹中以供产品安装使用。另外,您可以考虑阅读雷蒙德·陈(Raymond Chen)的文章了解更多相关主题。
WS_EX_TOPMOST
样式时,它将显示在任何其他窗口之上,包括Metro应用、开始屏幕等。因此,换句话说,做这个:
//You may also consider setting the WS_EX_NOACTIVATE style
::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0 , 0, 0, SWP_NOMOVE | SWP_NOSIZE);
能够实现这个:
你说你实际的问题是如何知道 Metro 应用是否正在运行,答案是调用 IAppVisibility::GetAppVisibilityOnMonitor
。传入要检查的监视器。请注意这将给出正确的答案,无论应用程序在哪个桌面上运行。
CoCreateInstance
函数并传入CLSID_AppVisibility
。这将为您提供一个支持IAppVisiblity
的对象。调用GetAppVisibilityOnMonitor
方法即可。 - Raymond Chen