4

我一直在用 C++ 中的 C#、C++/CX 和 WRL 试验 WinRT 组件。到目前为止,我设法做了所有我尝试过的事情,即使与 COM 相比,有些东西已经改变,或者令人困惑或令人沮丧。

我正在尝试的最后一件事是 COM 的基本架构模式,但到目前为止我还做不到。我只是想创建一个 WRL 组件的实例,而不引用正在使用该组件的项目中的 DLL。据我所知,这是COM的基本行为,提供COM的CoClass的GUID,使用程序只知道接口,CoCreateInstance将动态加载COM并创建一个附加到您请求的接口的实例.

我找不到如何使用 WRL 做到这一点。我定义了几个简单的接口,我什至在注册表中都找不到它们。但是,由于 COM 可以在没有注册表的情况下使用对象并且现在有窗口元数据,我想这就是原因。

有人知道这是否不是对 WinRT 的限制(这将使其成为一个非常糟糕的架构......),或者如果有可能如何实现与 WRL 的后期绑定。

为了清楚起见,在调用程序中,我只想提供接口的信息(这可以是 .h),然后我需要能够使用其 GUID 或名字对象名称创建 WinRT 组件的实例。这是我在 C++/COM、C# 和 Java 中使用的架构模式,因为您可以编写应用程序并支持新功能,而无需触及应用程序的任何一行,甚至无需重新编译它。

谢谢 O. Rouit

4

1 回答 1

7

到目前为止,尚不清楚您实际上要做什么。WRL 只是 WinRT 的 C++ 帮助程序库,如果您使用 C++(将其视为 WRL-is-to-WinRT-as-ATL-is-to-COM)。

让我们以 C++ 为例,因为它是“最原始的”,并且没有像 C# 或 JS 这样的虚拟机或运行时。您正在尝试实例化未链接的 WinRT 对象?如果是这样,那很简单——ActivateInstance(activateableclassid)。真正的问题是您要实例化什么?如果它是第一方(收件箱/Windows)组件,它应该可以正常工作。这与 COM 非常相似,其中 ACID 类似于 CLSID,ActivateInstance() 类似于 CoCreateInstance()。

如果您尝试实例化第 3 方 WinRT 组件(未随 Windows 提供),它会更简单一些。注册第 3 方 WinRT 组件的唯一方法是将它们包含在您的包中。包是相互隔离的,所以你不能让例如 AngryBirds 提供一个 FOO WinRT 对象并在 Scrabble 包中的应用程序中使用它。与注册在机器范围内的 COM 不同(或者在极少数情况下,即使您在 HKCU 而不是 HKLM 下注册,用户范围内),WinRT 3rd 方(打包)WinRT 对象仅注册供该包中的应用程序使用。(1)

(1) 这是一个善意的谎言。从技术上讲,您的应用程序可以实例化随 Windows 提供的 WinRT 组件以及包图中的包提供的 WinRT 组件。您可以制作一个包含 WinRT 对象的框架包,并让您的应用程序包依赖于它。Windows 认为我们的包取决于框架,因此您的“包图”中有2 个包 - 您的应用程序包和框架包。您不能将框架包提交到商店。本地开发和企业/侧载部署可以做到这一点(它们不通过 Store,因此不需要满足 Store 提交条件),但任何提交到 Store 的应用程序包只能依赖于 Windows 提供的框架(WinJS、VCLibs、PlayReady/DRM)。这就是 PlayReady 的工作原理——它是一个包含(除其他外)一些 WinRT 对象的框架包;如果您的应用程序包在其上声明了 a,则您的包图将包含 2 个包(您的应用程序包 + playready 的包),并且 ActivateInstance() 可以跨包图中的包联合解析 ACID。

应用程序模型中内置了很多保护措施。这是其中之一。这可以防止“COM Hell”和“DLL Hell”——一切都很好,然后 6 个月后您安装了应用程序 Y,并且应用程序 X 无缘无故不再工作。新的 appmodel 旨在防止这种情况。

另一个保护措施是限制可以找到打包的 WinRT 对象的位置。即使您将文件放入应用程序的本地文件夹(例如 ApplicationData.current.localFolder),ActivateInstance() 也不会找到它。WinRT 不会在 AppData(或其他许多地方)下查找已注册的 WinRT 对象——仅在您的包图中(以及操作系统提供的第一方 (Windows) 组件,例如 StorageFolder)中查找。

提供 COM 的 CoClass 的 GUID,使用程序只知道接口,并且 CoCreateInstance 将动态加载 COM 并创建一个附加到您请求的接口的实例。WinRT等效项是提供 WinRT [组件] 的运行时类的ACID,使用程序只知道接口,并且ActivateInstance()将动态加载WinRT [组件] 并创建一个附加到您请求的接口的实例.

需要注意的是,WinRT 组件的实现必须在您的包图中注册,即必须在您的应用程序包的 AppXManifest.xml 或依赖项的 AppXManifest.xml 中列出。

如果您在 ABI 级别直接处理 WinRT,那是最原始的级别。C++ 投影是等价的,只是语法更方便。CLR 和 JS 运行时提供了它们自己的附加和强制执行的变体(例如搜索“windows 8 javascript local vs web 隔间”),但它们只是进一步为行为着色。他们不能推翻底层操作系统的基线行为。

正如达米尔所说

您将无法以任何其他方式将新文件放入安装文件夹,这是应用程序可以从中加载可执行代码的唯一位置。“可执行代码”有多种形式,具体取决于您的定义。

WinRT 组件可以从其他地方加载(Windows 提供的 WinRT 组件、依赖包,例如 PlayReady 框架包)。

(非 WinRT、非 COM)“本机”DLL 可以从其他位置(可执行文件的目录、System32 等)加载。请参阅Windows 商店应用程序的搜索顺序

DLL 中的 .NET 程序集有它们自己的类似限制,例如 Assembly.Load()。

有些人认为 Javascript 是“代码”,并且有整个本地与网络隔间的东西来进一步着色可以从中解析代码的地方。

作为一般规则,您可以通过多种方式动态加载代码,但它需要是已知代码。没有受支持的方式可以创建例如将加载在应用商店提交时未知的 DLL(WinRT 或非 WinRT)的 C++ 应用程序。您可以使用可选(条件加载)代码编写应用程序,您可以拥有“插件”——但当您提交到商店时,它们需要在您的包中。

您不能像现在这样构建例如 Outlook,其中 Outlook 使用开放式插件模型提交到应用商店,并且稍后安装 Outlook 可以找到和使用的 OutlookNiftyCalendar 插件。不在 Windows 8 中。

(有一些方法可以通过 web 隔间在 Javascript 应用程序中稍微改变这个规则,但这本身就是一个复杂的话题,即使这也有硬性和软性/策略的限制。如果你不写,那就无关紧要了Javascript 应用程序)

于 2012-12-24T01:03:45.337 回答