当我开始大学时,Java和.NET是用于教学的技术.
我已经熟悉并在过去三年中获得了基于COM(组件对象模型)的语言(如VB6)的经验.我理解基于COM的语言与更高级别的现代语言之间的区别.
我不明白注册表中发生了什么.例如,我执行以下命令:
regsvr32 myDLL.dll
Run Code Online (Sandbox Code Playgroud)
然后,我可以在以下位置找到一个条目:HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID.这是VB6程序的唯一条目吗?例如,如果我执行了以下操作,那么DLL仍然可用:
我试过这个并没有用.
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密钥.ThreadingModelCLSID中的值.指定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]组件的程序集.