在不引用DLL/程序集的情况下加载WinRT组件

Loading WinRT component without referencing the DLL/assembly

本文关键字:情况下 加载 WinRT 组件 程序集 引用 DLL      更新时间:2023-10-16

我一直在用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

到目前为止,还不清楚你到底想做什么。如果你使用C++,WRL只是WinRT的C++辅助库(把它想象成WRL对WinRT的作用,就像ATL对COM的作用一样)。

让我们以C++为例,因为它是"最原始的",没有像C#或JS那样的vm或运行时。你正在尝试实例化一个没有链接的WinRT对象?如果是这样的话,那就是简单的-ActivateInstance(activeableclassid)。真正的问题是您试图实例化什么?如果它是第一方(收件箱/Windows)组件,它应该可以正常工作。这非常像COM,其中ACID类似于CLSID,ActivateInstance()类似于CoCreateInstance()。

如果您试图实例化第三方WinRT组件(未随Windows一起提供),它会简单一点。ONLY注册第三方WinRT组件的方法是将它们包含在您的软件包中。程序包是相互隔离的,所以你不能有,例如AngryBirds提供一个FOO WinRT对象并在拼字游戏程序包中的应用程序中使用它与COM不同的是,注册是机器范围的(或者在极少数情况下,即使您在HKCU而不是HKLM下注册,也是用户范围的),WinRT第三方(软件包)WinRT对象只注册供该软件包中的应用程序使用。(1)

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

应用程序模型中内置了许多保护措施。这是其中之一。这防止了"COM地狱"answers"DLL地狱"-一切都很好,然后6个月后你安装了应用程序Y,毫无明显原因,应用程序X不再工作。新的应用程序模型旨在防止出现这种情况。

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

提供COM的CoClass的GUID,使用程序知道仅关于接口和CoCreateInstance将动态加载COM,并创建一个附加到您所在接口的实例请求。WinRT等价于提供WinRT[组件]的runtimeclassACID,使用程序只知道接口,ActivateInstance()将动态加载WinRT[组件]并创建一个附加到您请求的接口的实例。

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

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

正如Damir所指出的

您将无法以任何其他方式将新文件放入安装文件夹,并且这是唯一可以加载可执行代码的位置应用程序。根据您的定义,"可执行代码"有不同的形式。

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

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

DLL中的.NET程序集也有类似的限制,例如Assembly.Load().

有些人认为Javascript是"代码",还有整个本地与web分区的事情可以进一步着色代码。

一般来说,您可以通过各种方式动态加载代码,但它需要是已知的代码。没有支持的方法可以创建,例如,一个C++应用程序,它将加载在Store提交时未知的DLL(WinRT或非WinRT)。您可以使用可选(有条件加载)代码编写应用程序,也可以有"插件",但当您提交到应用商店时,它们需要在您的包中。

你不能像今天这样构建Outlook,Outlook是用开放式插件模型提交到商店的,稍后安装Outlook可以找到并使用的OutlookNiftyCalendar插件。不在Windows 8中。

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