COM注册失败:“自动化错误:系统找不到指定的文件”,将dll安装到tlb文件以外的其他文件夹中

时间:2012-07-26 16:31:34

标签: com wix registry dllregistration heat

我们在VB.NET中开发了一个COM组件(我们称之为MyLib),用于我们的Access应用程序(让我们称之为MyApp)。为此,我们需要使用生成的MyLib.dll和MyLib.tlb文件进行COM注册。当我将这两个文件安装到MyApp的文件夹中时,一切正常,COM函数被正确调用。但是,当我将dll安装到公共文件夹时,我在标题中提到了错误 - 我这样做的原因是因为我们希望允许在同一台机器上安装不同版本的MyApp。因此,如果COM组件没有改变,我们当然希望在这些不同版本之间共享它,并让Windows执行引用计数。

我不确定将MyLib.tlb文件放在MyApp的安装文件夹中,或者放在与MyLib.dll相同的公共文件夹中。但无论如何,我尝试了两个位置,他们都给出了同样的错误。当我将MyLib。*放入MyApp的文件夹时,以及将MyLib.dll放入公共文件夹的情况下,我尝试比较案例之间的注册表文件。我看不出有任何区别,当然我正在尝试在HKCR \ Wow6432nodes \ CLSID {MYCLSID} \ InprocServer32下注册的类CodeBase。我不明白的另一件事是在两种情况下都没有在HKCR \ Wow6432nodes \ CLSID {MYCLSID}下名为TypeLib的子键,在我的理解中是将TypeLib链接到dll的方式(但为什么仍然有效)当我把tlb和dll放到同一个文件夹中?)因为在MyApp中它只知道我们通过引用MyLib.tlb添加了一个引用。

我不清楚COM引用究竟是如何为Access应用程序工作的,所以如果我错了,请纠正我。谁能告诉我我做错了什么?注册共享COM dll的正确方法是什么(无论是否将dll和tlb都放入共享文件夹)?谢谢!

更新:

关于COM注册,我使用WIX创建Windows安装程序和heat.exe以从dll和tlb文件中获取信息。生成的文件包含Class,ProgID,TypeLib和Registry标记的信息。正如我所提到的,从WIX配置的角度来看,我的两种情况之间唯一的区别就是我放置MyLib.dll文件的位置(我假设将MyLib.tlb文件放在MyApp安装文件夹中是正确的方法,请再说一次我的错误),当我将dll和tlb文件放入应用程序的安装文件夹时,它确实有效。这是注册后的一些注册表结构

首先我有HKCR \ CLSID \ {MYCLSIDs},每个都代表我的COM类之一。在名为“InprocServer32”的子键中,我有Assembly,Class,CodeBase,RuntimeVersion,threadingModel。 CodeBase是公共文件夹(不工作)或MyApp的安装文件夹(工作),这是我放置dll的不同位置。我认为在{MYCLSIDs}下会有另一个子键TypeLib,因为Access只能看到TypeLib,我认为应该有一些从TypeLib到实际dll的链接,但是,在这两种情况下,这个子键都丢失但是在第二种情况它仍然有效。有问题吗?

其次我有HKLM \ Software \ Classes \ CLSID \ {MYCLSIDs},这个键具有与上述相同的结构。

第三,HKCR \ {MYPROGIDs},这些只是我班级的ProgID

第四,HKCR \ Typelib \ {LibID},其中包含来自tlb文件的信息,此ID来自COM组件项目的程序集GUID。

最后,HKEY_CLASSES_ROOT \ Interface \ {InterfaceID},有一个名为ProxyStubClsid32的子键,值为{00020424-0000-0000-C000-000000000046},名为TypeLib的子键值为my LibID。

似乎唯一的区别是第一项中的CodeBase(我可能错了,但这就是我所看到的)。如果您发现任何问题,请告诉我。谢谢!

第二次更新:

将MyLib.dll安装到共享文件夹后,COM调用失败。但是,如果我将SHARED_FOLDER \ MyLib.dll的所有CodeBase值替换为INSTALLDIR \ MyLib.dll,并将MyLib.dll复制到INSTALLDIR,它实际上是有效的。反之,在我将MyLib.dll安装到INSTALLDIR(在这种情况下COM正在工作)之后,我将CodeBase值从INSTALLDIR \ MyLib.dll更改为SHARED_FOLDER \ MyLib.dll,并将副本复制到SHARED_FOLDER,这次它失败了。所以它似乎正是安装位置的问题,这与我对COM的理解相反。而且我认为SHARED_FOLDER没有权限问题(我可能错了),因为它位于我的安装程序创建的文件夹中。

2 个答案:

答案 0 :(得分:7)

  

我不清楚COM引用究竟是如何用于Access应用程序的,

自从这些东西出现在1990年以来,com对象如何适用于Windows。所以我们谈论的是一个已经存在了22年的肉和土豆主流或技术(并且很久以前它就是如何在.net中创建对象的了。 )。

所以com的工作方式与Access,Delphi,FoxPro或VB6或任何能够使用com对象的系统相同。

接下来请务必记住,对于此类com对象,计算机上此类对象的注册表本质上是GLOBAL。

与.net中放置在同一文件夹中的对象的动态链接概念没有任何关系。

因此,way.net的工作方式不需要全局注册(实际上您不需要任何注册!)。

但是在.NET中,如果您愿意,可以在全局程序集中注册一个对象(GAC)。所以这是你的选择,但这样的选择不是标准的windows com对象,而是.net对象的选择。所以那些对象与我们22年来的标准windows com对象有零和零。

因此.net中的大多数对象实际上是dir的本地对象,但这不是标准窗口com对象的选择。

因此,要将.net对象或程序集正确转换为可用且正常工作的Windows com对象,则该对象必须将GLOBAL注册到计算机。这意味着你不使用regsvr32,但事实上它将使用名为regasm的.net注册工具(实际上,在为你构建com对象桥后,它最终会为你做一个regsvr32)。还要记住,你需要在这里编译正确的位版本。

如果您部署到其他计算机,则将项目设置为生成2.0对象,这样您就很有可能在目标计算机上安装了.net库。因此,在部署期间,您必须使用regasm:

这一个: C:\的Windows \ Microsoft.NET \框架\ V2.0.50727 \ RegAsm.exe

最重要的是不要忘记将/ codebase添加到命令行使用regasm.exe,因为您必须在GAC(全局程序集缓存)中注册.net对象。如果不这样做,那么支持windows com对象的非.net应用程序将无法看到noir能够将程序集用作标准的Windows com对象。

因此,当谈论非.net对象时,没有概念在文件夹库中注册ActiveX或文件夹中常见的windows com对象 - 它本质上总是全局的。

因此,将.dll放入哪个目录或文件夹是没有意义的。一旦您正确注册.dll,它将可用于支持com对象的所有系统。

这也意味着在.net注册过程中你必须使用全局程序集注册表选项(否则它将不起作用)。

答案 1 :(得分:2)

事实证明,MyLib.dll正在使用其他一些库,这些库仍然安装在MyApp安装文件夹中。因此,在MyLib.dll安装在共享文件夹中的情况下,它会尝试在相同的库中找到这些库,这当然会失败。当我在共享文件夹中安装这些库时,它正在运行。

BTW我发现fulogvw.exe在追踪装配加载问题时非常有用。例如,在我的情况下,在失败的日志中,它说无法在SHARED_FOLDER中加载文件xxx.dll,xxx.dll是MyLib.dll正在使用的一些库,我不知道MyLib.dll需要它,直到我看到日志。