.NET 的本机 COM (activex) 组件免注册激活

Ord*_*nge 1 .net c# windows com activex

我有一个本机 dll(它是一个 activex 控件),我需要将其与我的 .NET 应用程序一起使用,而无需在注册表中注册该 dll。

我读过几篇关于免费注册激活的深入文章,其中一些更好的是

史蒂夫·怀特和莱斯利·穆勒的长篇文章

这是塞缪尔·杰克的作品

迈克·马卡洛夫的另一个

据我所知这是可能的。然而几个小时和数百次测试后我就是无法让它工作。在我的职业生涯中,我已经完成了一些 PInvoking 工作,甚至更少使用 .NET 中的 ActiveX 控件,因此,对于以前可能在这方面达成目标的任何人提供的任何意见,我将不胜感激。

到目前为止,我遵循 Steves 的建议,构建一个可以工作的应用程序,然后尝试通过重复运行 regsvr32 命令来从注册表中添加和删除非托管 dll 来制定获胜的清单文件语法。只是一个简单的 .Net 控制台应用程序,大约有 10 行代码......

我感到困惑的一部分是互操作。我拥有的本机 dll 还附带托管运行时可调用包装器 (RCW)。在我的 .NET 应用程序中,我添加对这些 RCW 的引用,然后可以使用非托管 dll 提供的相应类和功能。我不是通过 PInvoking dllimport

在创建清单文件时,我不确定是否需要担心这些 RCW 以及它们在免注册场景中如何工作,或者即使它们是否需要出现在编译输出中?

我还尝试了几种工具,例如(OLE/COM 对象查看器、Windows sdk 中的 Mt.exe 和 codeproject 中的 regsvr42)。但不同工具和帖子的清单结构和必要的 GUID 都不同。

当前状态是我收到一条InvalidCastException “无法将 System.__ComObject 类型的 COM 对象转换为 MyFunkyDllLib.FunkyDllControl 接口类型。此操作失败,因为对具有 IID '{some guid}' 的接口的 COM 组件上的 QueryInterface 调用因以下原因失败:出现以下错误:库未注册。

任何人都可以确认应用程序和 dll 清单文件的正确语法吗?网上帖子的名称甚至各不相同,有些在名称中使用了 sxs......

Update1: ​​虽然下面 Joe 的回答不起作用,但它确实让我对 reg free COM 有了更好的了解。在 Interop dll 的属性中(从开发计算机上已安装的 COM 组件列表添加到项目引用的那个),我将独立属性更改为 True。这具有使 VS 将 COM dll(不是互操作,它嵌入在 exe 中)的副本转储到 bin\debug 文件夹的效果。然后 VS 还会创建一个 myapplication.exe.manifest。

在此清单文件中,据称包含了 reg free com 的足够信息。我发现其他帖子表明这种方法成功,但就我而言,我仍然得到了相同的结果InvalidCastException

再次阅读 Samuel Jacks 的帖子,我尝试了他的方法,使用 VStudio 输出清单中的 clsid 信息为 exe 和 COM dll 创建清单Isolated=true。(我还<file/>从exe.manifest中删除了VS创建的部分)。从注册表中取消注册 COM 后,我现在成功了!应用程序启动并且没有错误。为什么这种方法有效,而不是Isolated=true我不知道,因为它超出了我对清单和程序集的了解。

然而我们还没有到达巫师城堡托托。

现在我又回到了我在此线程上发布的同一问题。然而,在这种情况下,不涉及单元测试。只是一个带有 10 行代码的普通控制台应用程序。在正常注册 COM 模式下工作正常,但在免注册模式下则不行。

Ord*_*nge 5

经过几个小时的反复试验,我终于找到了如何成功实现 RegFree COM 的解决方案。这是完整的解释,以防对其他人有所帮助。

  1. 我在 VS 中创建一个新的 .NET 类库
  2. 右键单击引用并选择感兴趣的 COM 组件。(注意:要使 COM 在列表中可见,它们必须在开发计算机上注册。这可以通过使用 Windows 附带的 Regsvr32.exe 工具来实现。调用“regsvr32 mycomdll.dll”将其注册到 Windows 注册表中)
  3. 右键单击 COM 引用,转到“属性”,然后设置“Isolated=True”。这会导致 VS 输出一个 .manifest 文件,该文件据称包含消费 .exe 所需的所有注册表详细信息,以了解要加载哪些资源,而不是查询注册表。但就我而言,它是不完整的。对 Interop 方法的调用可以工作,但来自 COM 组件的事件则不行。我的解决方案请参阅步骤 5)
  4. 构建项目。.manifest 应出现在构建输出中。
  5. 在记事本或类似工具中打开清单。在<assembly />标签内,我需要添加一个<comInterfaceExternalProxyStub />带有适当的IID,tlbidproxyStubClsid32GUID 元素的标签。清单的元素记录在 msdn 上。就我而言,代理/存根proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"/>是内置的 Windows 代理。我最初在调用 regsvr32 时通过Process Monitor发现了 iid 和 tlbid 。我后来发现的一个更简单、更可靠的选择是使用像SxS 清单制作器<comInterfaceExternalProxyStub />这样的工具,因为它添加了我最初没有的第二个工具。
  6. 在VS中创建一个exe项目并引用之前构建的库。
  7. 构建exe项目。
  8. 运行 regsvr32 /u mycomdll.dll。删除所有注册表关联。
  9. 运行该exe。在我的例子中,对类库中 COM 组件的调用和事件都运行得很好。

注意事项:我不知道为什么 VS 不<comInterfaceExternalProxyStub />自动在 .manifest 中包含该元素。在撰写本文时,自动更新清单的唯一方法是在 VS 中添加后期构建任务。就我而言,我将整个 XML 清单复制到类库项目中的 XML 中,然后覆盖构建输出中的 .manifest 文件。

COM 的单元(集成)测试不一致。目前,在我的例子中,对 Interop 方法的调用可以工作,但事件却不能。这与测试运行程序未在了解依赖项的情况下进行编译的事实有关,因此这些依赖项不存在于激活上下文中。