【问题标题】:What desktop does Metro stuff run in?Metro 的东西在什么桌面上运行?
【发布时间】:2014-06-04 08:52:02
【问题描述】:

只是好奇,从 WinAPI 开发人员的角度来看,Metro 应用运行在什么 desktop 中?

这些东西:

【问题讨论】:

  • 这是一个实现细节,可能会发生变化。你的实际编程问题是什么?
  • @RaymondChen:知识。除此之外,如果 Metro 应用程序正在运行,我可能需要显示弹出通知。
  • 已经有一个very similar question,但显然没人知道。尽管如此,除了技术基础之外,我还想知道如何做出这样一个以全屏模式运行应用程序的疯狂决定,然后再实施和推出,然后……忽略客户反馈。太不可思议了,太棒了,我真的很想知道它到底是怎么可能的。
  • 这很快就会成为 StackOverflow 的话题。
  • 这是一个技巧问题,因为没有人使用 Metro :)

标签: c++ c winapi microsoft-metro win32gui


【解决方案1】:

我不知道这会是一个秘密......所以我不得不做一些调查,这就是我发现的:

首先,回答我最初的问题——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_TOPMOSTWS_EX_NOREDIRECTIONBITMAP 样式的 "Windows.UI.Core.CoreWindow" 容器中:

如果你看得更深一点,微软的所有 Metro stuff 似乎都是从 WWAHOST.exe 进程运行的,简单来说,它就是为 Metro 应用程序运行 JavaScript 的容器。

现在让我们看看Start Screen 本身。由于它完全覆盖了桌面,我们需要使用不同的工具及其 Shift 键快照功能来实现它:

从中我们可以得到开始屏幕的窗口句柄(或者在我的例子中是0x10158)并在 Spy++ 中查找它:

正如您从这两个工具中看到的那样,开始屏幕具有窗口类 DirectUIHWND,它位于 ImmersiveLauncher 类的窗口内,即具有 WS_EX_TOPMOSTWS_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);

可以做到这一点:

【讨论】:

    【解决方案2】:

    既然您说您的实际问题是知道 Metro 应用程序是否正在运行,那么答案是致电 IAppVisibility::GetAppVisibilityOnMonitor。通过您要检查的监视器。请注意,无论应用程序在哪个桌面上运行,这都会给出正确答案。

    【讨论】:

    • 嗯。谢谢。虽然我不完全清楚如何从 Win32 应用程序调用它?
    • 正如文档中所说,call the CoCreateInstance function with CLSID_AppVisibility。这为您提供了一个支持IAppVisiblity 的对象。调用GetAppVisibilityOnMonitor 方法。
    • 谢谢你,雷蒙德。我试图在 VS 2008 中实现这个接口,但它没有定义:stackoverflow.com/q/23207291/843732 知道在 VS 2012 之前如何做到这一点吗?
    • 该接口是在 Windows 8 中引入的,因此您需要安装适用于 Windows 8 的 Platform SDK。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 2021-02-08
    • 2018-12-03
    相关资源
    最近更新 更多