当我开始大学时,Java和.NET是用于教学的技术。
我已经熟悉并在过去三年中获得了基于COM(组件对象模型)的语言(如VB6)的经验。我理解基于COM的语言与更高级别的现代语言之间的区别。
我不明白注册表中发生了什么。例如,我执行以下命令:
regsvr32 myDLL.dll
然后我可以在以下位置找到一个条目:HKEY_LOCAL_MACHINE \ SOFTWARE \ Classes \ CLSID。这是VB6程序的唯一条目吗?例如,如果我执行了以下操作,那么DLL仍然可用:
我试过这个并没有用。
答案 0 :(得分:9)
Regsvr32.exe是一个非常的简单程序,它对注册本身的贡献很小。它只是使用LoadLibrary()来加载您作为参数传递的名称的DLL,然后使用GetProcAddress()来定位DLL中的导出函数。哪个是DllRegisterServer(),如果使用/ u选项取消注册,那么它会查找DllUnregisterServer()。并调用该函数,就是这样。
DllRegisterServer由组件作者编写。究竟它的作用是不可预测的,一切皆有可能。但肯定存在共性,其目的是编写组件需要可从其他程序使用的注册表项。您将需要使用SysInternals的Process Monitor,它的跟踪显示了正在完成的工作。
您已经了解了HKLM\Software\Classes\CLSID\{guid}
注册表项。非常重要的是,这是客户端程序中CoCreateInstance()调用的强大功能。通过简单地指定一个数字(CLSID)在服务器中创建一个对象,COM基础结构确保找到并加载正确的DLL,其DllGetClassObject()
入口点是提供对象的工厂函数。
核心功能是客户端程序不必知道有关DLL本身的任何信息,它所提供的只是提供一个数字,它神奇地获取了一个创建的对象。这提供了很多灵活性的DLL构造方式,完全不依赖于编写DLL源代码的语言。例如,在编写[ComVisible] .NET组件时利用的功能,像C#这样的语言不支持导出DllGetClassObject()之类的函数。仍然有效(有点超出范围),客户完全忘记了CLR中的管道,使其工作。
几乎所有COM服务器的注册功能都会写入这些键:
HKLM\Classes\Software\CLSID\{guid}\InprocServer32
。为服务器实现的每个coclass编写。此键的默认值包含DLL的路径。告诉COM管道加载哪个DLL来查找DllGetClassObject入口点。进程外服务器(EXE而不是DLL)使用LocalServer32密钥。ThreadingModel
值。指定COM对象的线程要求。非常常见的是“Apartment”,告诉COM基础结构COM对象不是线程安全的,COM应该以线程安全的方式调用服务器内部的函数。其他常见值有“Both”(.NET组件的默认值)和“Free”,为可以自己处理来自工作线程的调用的组件编写。HKLM\Classes\Software\Interface\{guid}\ProxyStubClsid32
。为COM coclass实现的每个接口编写。对于任何非自由线程的COM对象都是必需的,它包含COM对象的CLSID,该对象知道如何对从一个线程到另一个线程的接口方法进行调用。您可以找到一个非常常见的值{00020424-0000-0000-C000-000000000046},它是Windows中包含的默认编组程序,它知道如何根据类型库的内容封送调用。自定义的也不常见,特别是对于通过描述IDL语言中的接口而启动的COM服务器。可以从IDL自动生成此类组件的代理/存根。HKLM\Classes\Software\Interface\{guid}\Typelib
。对于依赖于标准编组器的服务器,默认值为类型库的guid。HKLM\Classes\Software\Typelib\{guid}
。对于依赖于标准编组器的服务器,请告诉COM在何处找到所需的类型库。HLKM\Classes\Software\{progid}
。对于支持后期绑定的服务器来说很常见,允许从Javascript或VBScript等脚本语言中使用它们。其中{progid}是一个友好的字符串,用于标识组件而不是guid。为许多语言中的CreateObject()运行时支持函数提供支持。此键中的CLSID子键告诉运行时它应该使用哪个guid来定位CLSID键。您可能会看到更多的密钥被写入。 ActiveX组件在CLSID中写入一串键,以将信息传递给主机应用程序和VB6等编程工具。用.NET编写的服务器添加了几个键来帮助CLR找到包含[ComVisible]组件的程序集。
答案 1 :(得分:2)
然后我可以在HKEY-Local-Machine-CLSID下找到一个条目。这是 只有为VB6程序输入的内容?
不,有multiple entries;例如\TYPELIB
和SOFTWARE\CLASSES\PROGID
其中PROGID
是YourSever.YourClass
标识符。
当您取消注册组件时,这些组件将被删除,因此重新阻止CLSID密钥将无法恢复功能。
如果类型定义未存储在文件中(在它们之前) 注册),然后他们存储了吗?
COM DLL可以在内部将其类型库存储为二进制TYPELIB资源。
答案 2 :(得分:1)
请记住,regsvr32并不神奇。它加载目标DLL(或OCX)并调用该库的自注册入口点。这通常会产生一个或多个类,ProgIds和类型库的简单注册,只要VB6编译器生成一个类就嵌入到这些DLL中。 ActiveX EXE以类似方式执行自注册,但不通过外部调用方执行。而是通过regserver
命令行开关传递EXE的特殊运行。
自行注册不是在目标系统上安装任何这些内容的首选方式。它只是编译器可以生成的最小的,简单的注册,而无需阅读开发人员的想法。它还完全跳过在注册表中创建重要的服务条目,例如卸载程序链接,创建/递增使用计数等。并且它无法生成代码可能依赖的大量其他注册表项(shell扩展信息,数据文件类型/扩展关联,服务信息,DCOM激活参数等)。
其他编译器提供了在单独的typelib文件中创建类型信息的选项,但VB6没有。
所以你提出的建议是合理的,但却错过了很多东西。首先,您已经在HKEY_CLASSES_ROOT\TypeLib\
下找到了类型信息(类型库)注册,但在HKEY_CLASSES_ROOT\
下也有ProgId信息,依此类推。
有关详情,请参阅INFO: Registry Entries Made by an ActiveX Component。
请记住,VB6不会创建原始COM组件,而是ActiveX组件,这是COM添加OLE2方面的超集。
.Net依赖于基于文件位置的更原始的类Java机制,除非您使用GAC程序集(.Net版本的注册表发布)。
答案 3 :(得分:0)
虽然.NET程序集直接在生成的.EXE或.DLL文件中包含其类型定义(类,方法等),但COM组件不会,因此需要首先“注册”才能识别。
注册和取消注册过程独立于存储的.DLL文件运行。因此,取消注册COM组件不会删除.DLL文件,只是删除用于标识它的信息。