从.NET

时间:2016-10-23 11:37:15

标签: c# .net windows com activex

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

我已经阅读了几篇关于注册免费激活的深度帖子,其中一些更好的是

A lengthy one from Steve White and Leslie Muller

This one from samuel jack

And another from Mike Makarov

从我可以看到它是可能的。然而,几个小时和几百个测试后来我不能让它工作。在我的职业生涯中,我已经完成了一些PInvoking,甚至更少使用.NET中的ActiveX控件,所以非常感谢任何可能在此之前就已经踢过目标的人的任何意见。

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

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

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

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

当前状态是我收到InvalidCastException &#34;无法将System .__ ComObject类型的COM对象强制转换为接口类型MyFunkyDllLib.FunkyDllControl。此操作失败,因为QueryInterface调用COM组件上的接口与IID&#39; {some guid}&#39;由于以下错误而失败:库未注册。

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

UPDATE1: 虽然Joe的回答不起作用,但确实给了我一些关于免费COM的更好的见解。在Interop dll的属性(从开发机器上已安装的COM组件列表中添加到项目引用的属性)中,我将Isolated Property更改为True。这具有使VS转储到DLL \ debug文件夹的COM转储(不是互操作,它嵌入在exe中)的副本的效果。然后VS也会创建一个myapplication.exe.manifest。

在这个清单文件中可以说是reg free com的足够信息。我发现其他帖子表明此方法取得了成功,但在我的情况下,我仍然使用相同的InvalidCastException

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

然而,我们仍然没有在Toto的巫师城堡。

现在我回到我在this SO帖子上发布的同一个问题。但是在这种情况下,不涉及单元测试。只是一个包含10行代码的普通控制台应用程序。在正常注册的COM模式下工作正常,但在免注册模式下不工作。

2 个答案:

答案 0 :(得分:1)

经过数小时的反复试验后,我终于找到了如何成功实施RegFree COM的解决方案。 这是一个完整的解释,因为它可以帮助其他人。

  1. 我在VS
  2. 中创建了一个新的.NET类库
  3. 右键单击引用并选择感兴趣的COM组件。 (注意:要使COM在列表中可见,必须注册它们 在开发机器上。这可以通过使用来实现 Windows附带的Regsvr32.exe工具。致电&#34; regsvr32 mycomdll.dll&#34;将它注册到Windows注册表中)
  4. 右键单击COM引用,转到属性,然后设置Isolated = True。这会导致VS输出一个.manifest文件,该文件应该包含消费.exe所需的所有注册表详细信息,以了解要加载的资源而不是查询注册表。但在我的情况下它是不完整的。调用Interop方法可行,但COM组件的事件不会。请参阅步骤5以获取我的解决方案)
  5. 构建项目。 .manifest应出现在构建输出中。
  6. 在记事本或类似内容中打开清单。在<assembly />代码中,我需要添加<comInterfaceExternalProxyStub />代码,其中包含相应的IIDtlbidproxyStubClsid32 GUID元素。清单的元素记录在案on msdn。在我的例子中,代理/存根是proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"/>,它是内置的Windows代理。我最初通过调用regsvr32时通过Process Monitor发现的iid和tlbid。我后来发现的一个更简单,更可靠的选项是使用像SxS manifest maker这样的工具,因为它添加了我原本没有的第二个<comInterfaceExternalProxyStub />
  7. 在VS中创建一个exe项目并引用以前构建的库。
  8. 构建exe项目。
  9. 运行regsvr32 / u mycomdll.dll。删除所有注册表关联。
  10. 运行exe。在我的例子中,类库中COM组件的调用和事件工作得很好。
  11. 警告:我不知道为什么VS不会在.manifest中自动包含<comInterfaceExternalProxyStub />元素。在撰写本文时,自动更新清单的唯一方法是在VS中添加post build任务。在我的例子中,我将整个XML清单复制到类库项目中的XML中,然后在构建输出中覆盖.manifest文件。

    COM的单元(集成)测试不一致。目前在我的情况下调用Interop方法工作,但事件没有。它与Test Runner未编译时具有依赖关系的知识有关,因此在激活上下文中不存在。

答案 1 :(得分:0)

你可能错过了一个类型库声明......但现在忽略它......相反,请执行以下操作......

在打开和关闭一段时间之后,我认为最简单的方法是使用MSBuild和GenerateApplicationManifest任务。我一直在使用非托管应用,但我不明白为什么它不适用于托管应用。我说&#34; app&#34; ...因为我的应用程序是托管的,但我有COM库和.NET程序集,其中包含ComVisible类。

从您的描述中可以看出您正在处理COM并且不必担心从COM使用.NET程序集。您可以谷歌搜索MSBUILD和GenerateApplicationManifest以获取示例MSBuild文件。

所以,我认为你不需要填充&#34;依赖关系&#34;任务的属性。您将需要填充&#34; IsolatedComReferences&#34;带有COM DLL列表的属性。它们可以是一个简单的以分号分隔的列表,但通常它们位于&#34; ItemGroup&#34; MSBuild项目文件中的声明。需要在生成清单时注册COM DLL。

至于你的RCW,你没有什么特别需要做的。 IMO,他们不需要在清单中。只要它们与app / DLL位于同一目录中,.NET就可以找到它们。

如果您使用MSBuild,您将不必为您的COM DLL生成清单...它们可能已经有清单...通常,向导会自动生成清单并嵌入它们。唯一需要COM类型信息的清单是使用MSBuild生成的清单。

以这种方式使用的清单的重点是使用注册表中的所有COM信息填充清单空间。