我不知道这会是一个秘密......所以我不得不做一些调查,这就是我发现的:
首先,回答我最初的问题——Metro(或现代 UI)的东西在与“桌面”应用程序完全相同的desktop 中运行(请原谅双关语。)实际上都非常简单。简短的回答——所有 Microsoft 批准 Metro 的东西都在 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" 容器中:
如果你看得更深一点,微软的所有 Metro stuff 似乎都是从 WWAHOST.exe 进程运行的,简单来说,它就是为 Metro 应用程序运行 JavaScript 的容器。
现在让我们看看Start Screen 本身。由于它完全覆盖了桌面,我们需要使用不同的工具及其 Shift 键快照功能来实现它:
从中我们可以得到开始屏幕的窗口句柄(或者在我的例子中是0x10158)并在 Spy++ 中查找它:
正如您从这两个工具中看到的那样,开始屏幕具有窗口类 DirectUIHWND,它位于 ImmersiveLauncher 类的窗口内,即具有 WS_EX_TOPMOST 和 WS_EX_NOREDIRECTIONBITMAP 样式的窗口它仍然在顶部。这是 it 与“桌面”应用程序创建的任何其他窗口之间的唯一区别。
同样有趣的是“桌面”本身在拆分窗口情况下是如何呈现的。我最初假设在这种情况下,桌面只是简单地移动(或移动)到一侧并调整大小,但 不是 会发生什么......实际上(或在我的 Windows 8.1 中)将桌面和 Metro 应用分开,Metro 应用只是覆盖桌面,但桌面本身不会改变其位置或大小。在这种情况下,只有任务栏和现有桌面窗口会被移动并调整大小以适应拆分。这张图可以说明这一点:
附带说明,这样的移动和调整大小对于用户来说可能非常烦人,因为当分割消失时,桌面窗口的原始位置和大小不会恢复。
最后,一个有点出乎意料的发现。我决定检查 Google 人员如何实现他们的 Chrome 浏览器(作为 Metro 应用程序运行)并发现:
Chrome 在 Windows.UI.Core.CoreWindow 类窗口中渲染,属于 Google 自己的进程:“C:\Program Files (x86)\Google\Chrome\Application\chrome.exe”。因此,无需深入探讨,显然可以将 Metro 风格的应用程序封装在非 Microsoft 容器中,这对于不关心 AppStore XAML 应用程序的开发人员来说是个好消息:)
编辑:忘了提一下,如果您打算在 Metro 应用程序顶部显示您自己的来自 Win32 进程的弹出消息,您需要执行以下操作:
在进程清单中设置UIAccess="true"。您可以在 Visual Studio 中执行此操作,方法是转到 Project Properties -> Linker -> Manifest Files 并将 UAC Bypass UI Protection 设置为 YES。 (请注意,您可以将UAC Execution Level 保留为asInvoker,或者不需要提升您的进程。)
对您的流程进行代码签名。这很重要,因为没有签名就无法工作,并且您会看到以下错误消息:“从服务器返回了一个推荐。”
作为签名的替代方案(或用于在您的开发系统上进行测试),您可以将以下 registry key 设置为 0。(不过我没有尝试过,我不推荐它 由于明显的安全问题!但如果代码签名证书不可用,这似乎是另一种测试方法。)
HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\ValidateAdminCodeSignatures
- 将编译后的可执行文件放入
%windir%\System32 文件夹,或者更实际地放入%ProgramFiles%\Company\Product,或者放入产品安装位置的替代%ProgramFiles(X86)%\Company\Product 文件夹中。
您也可以考虑阅读Raymond Chen's article 了解此主题。
- 之后,当您在弹出窗口中设置
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);
可以做到这一点: