COM组件是跨语言的,组件被注册到注册表中,在加载时由加载函数在注册表中查找到对应模块的路径并进行相关加载。它的存储规则如下:

1. 在注册表的HKEY_CLASSES_ROOT中以模块名的方式保存着COM模块的GUID,比如HKEY_CLASSES_ROOT\ADODB.Error\CLSID键中保存着模块ADODB.Error的GUID为{00000541-0000-0010-8000-00AA006D2EA4}

2. 在HKEY_CLASSES_ROOT\CLSID中以GUID为项名保存着对应组件的详细信息,比如之前的{00000541-0000-0010-8000-00AA006D2EA4}这个GUID在注册表中的位置为HKEY_CLASSES_ROOT\CLSID\{00000541-0000-0010-8000-00AA006D2EA4}\InprocServer32\项的默认键中保存着模块所在路径为%CommonProgramFiles%\System\ado\msado15.dll

一般的COM模块都是使用regsvr32程序注册到注册表中,该程序在注册时会在模块中查找DllRegisterServer函数,卸载时调用模块中提供的DllUnregisterServer,所以要实现注册的功能主要需要实现这两个函数

这两个函数的原型如下:

STDAPI DllRegisterServer();
STDAPI DllUnregisterServer();

通过VS的F12功能查找STDAPI 的定义如下:

#define STDAPI  EXTERN_C HRESULT STDAPICALLTYPE

在查看STDAPICALLTYPE得到如下结果:

#define STDAPICALLTYPE          __stdcall

所以这个宏展开也就是

extern "C" HRESULT __stdcall DllRegisterServer();

为了实现注册功能,首先定义一个全局的变量,用来表示需要写入到注册表中的项

const TCHAR *g_regTable[][3] = {
{_T("SOFTWARE\\ComDemo"), 0, _T("ComDemo")},
{_T("SOFTWARE\\ComDemo\\InporcServer32"), 0, (const TCHAR*)-1}

这三项分别为注册表项,注册表项中的键名和键值,当键名为0时会创建一个默认的注册表键,最后一个-1我们会在程序中判断,如果键值为-1,那么值取为模块的路径

下面是注册的函数

STDAPI DllRegisterServer()
{
HKEY hKey = NULL;
TCHAR szFileName[MAX_PATH] = _T("");
GetModuleFileName(g_hDllIns, szFileName, MAX_PATH); int nCount = sizeof(g_regTable) / sizeof(*g_regTable);
for (int i = 0; i < nCount; i++)
{
LPCTSTR pszKeyName = g_regTable[i][0];
LPCTSTR pszValueName = g_regTable[i][1];
LPCTSTR pszValue = g_regTable[i][2];
if (pszValue == (const TCHAR*)-1)
{
pszValue = szFileName;
} long err = RegCreateKey(HKEY_LOCAL_MACHINE, pszKeyName, &hKey);
if (err != ERROR_SUCCESS)
{
return SELFREG_E_LAST;
} err = RegSetValueEx(hKey, pszValueName, 0, REG_SZ, (const BYTE*)pszValue, _tcslen(pszValue) * sizeof(TCHAR));
if (err != ERROR)
{
return SELFREG_E_LAST;
} RegCloseKey(hKey);
} return S_OK;
}

在程序中会循环读取上述全局变量中的值,将值保存到注册表中,在上面的代码中有一句sizeof(g_regTable) / sizeof(*g_regTable);

这个是算需要循环多少次,第一个sizeof得到的是这个二维数组的总大小。在C语言中我们说二维数组可以看做是由一维数组组成的,这个二维数组可以看成是由两个一维数组——一个由3个const TCHAR *成员组成的一维数组组成。所以*g_regTab自然就是这个一维数组的首地址,第二个sizeof就是这个一维数组的大小,两个相除得到的就是一维数组的个数。

卸载函数如下:

STDAPI DllUnregisterServer()
{
int nCount = sizeof(g_regTable) / sizeof(*g_regTable);
for (int i = nCount - 1; i >= 0; i--)
{
LPCTSTR pszKeyName = g_regTable[i][0];
long err = RegDeleteKey(HKEY_LOCAL_MACHINE, pszKeyName);
if (err != ERROR_SUCCESS)
{
return SELFREG_E_LAST;
}
} return S_OK;
}

至此已经实现注册和卸载函数。后面就可以直接使用regsvr32这个程序进行注册和卸载了.

COM学习(二)——COM的注册和卸载的更多相关文章

  1. SpringCloud 学习(二) :服务注册与发现Eureka

    Spring Cloud应用中可以支持多种的服务治理框架,比如Eureka.Consul.Zookeeper等,现在我们用的是consul,本文以SpringCloud Dalston.SR5版本介绍 ...

  2. 【Spring Cloud学习之二】服务注册和发现

    环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 Spring Cloud 1.2 一.EurekaEureka是Netflix开源的一个RESTful服务,主要用于服 ...

  3. SpringMVC入门学习(二)

    SpringMVC入门学习(二) ssm框架 springMVC  在上一篇博客中,我简单介绍了一下SpringMVC的环境配置,和简单的使用,今天我们将进一步的学习下Springmvc的操作. mo ...

  4. emberjs学习二(ember-data和localstorage_adapter)

    emberjs学习二(ember-data和localstorage_adapter) 准备工作 首先我们加入ember-data和ember-localstorage-adapter两个依赖项,使用 ...

  5. Quartz学习--二 Hello Quartz! 和源码分析

    Quartz学习--二  Hello Quartz! 和源码分析 三.  Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...

  6. SpringCloud学习(二):微服务入门实战项目搭建

    一.开始使用Spring Cloud实战微服务 1.SpringCloud是什么? 云计算的解决方案?不是 SpringCloud是一个在SpringBoot的基础上构建的一个快速构建分布式系统的工具 ...

  7. DjangoRestFramework学习二之序列化组件、视图组件 serializer modelserializer

      DjangoRestFramework学习二之序列化组件.视图组件   本节目录 一 序列化组件 二 视图组件 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 序列化组 ...

  8. day 90 DjangoRestFramework学习二之序列化组件

      DjangoRestFramework学习二之序列化组件   本节目录 一 序列化组件 二 xxx 三 xxx 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 序列化组件 首先按照 ...

  9. SpringCloud(二)- 服务注册与发现Eureka

    离上一篇微服务的基本概念已经过去了几个月,在写那篇博客之前,自己还并未真正的使用微服务架构,很多理解还存在概念上.后面换了公司,新公司既用了SpringCloud也用了Dubbo+Zookeeper, ...

随机推荐

  1. Python 练习冊,每天一个小程序

    Python 练习冊,每天一个小程序 说明:     Github 原文地址: 点击打开链接 Python 练习冊.每天一个小程序.注:将 Python 换成其它语言,大多数题目也试用 不会出现诸如「 ...

  2. recover all files with git

    leon@DGLIRUAN2 /F/linux/android/leon/workspace/AngoWidget (master) $ git log commit 2f847e3a858ecb2f ...

  3. hdu 5635 LCP Array(BC第一题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5635 LCP Array Time Limit: 4000/2000 MS (Java/Others) ...

  4. Proactor 学习1

    Proactor    An Object Behavioral Pattern for Demultiplexingand Dispatching Handlers for Asynchronous ...

  5. Fiddler使用总结一(使用Fiddler捕获手机所有http/https通信)

    与后端数据通信是前端日常开发的重要一环,在与后端接口联调的时候往往需要通过查看后端返回的数据进行调试.如果在PC端,Chrome自带的DevTools就已经足够用了,Network面板可以记录所有网络 ...

  6. springmvc返回json字符串中文乱码问题

    问题: 后台代码如下: @RequestMapping("menuTreeAjax") @ResponseBody /** * 根据parentMenuId获取菜单的树结构 * @ ...

  7. 个人微信接入图灵机器人(基于Python)

    编程语言:Python2.7 1.在图灵机器人官网(http://www.tuling123.com)注册账号, 创建机器人, 如果只是学习的话,可以使用2免费版 , 一个账号最多可以创建5个机器人 ...

  8. MFC学习之CWinApp类

    CWinApp是一个基类,你通过它来继承Windows应用程序对象.应用程序对象为你提供了初始化应用程序(以及它的每一个实例 和运行应用程序所需的成员函数.它实现主事件循环并把事件分发给MFC中其他类 ...

  9. 开源组件NanUI一周年 - 使用HTML/CSS/JS来构建.Net Winform应用程序界面

    NanUI是什么 NanUI基于ChromiumFX项目进行开发,它能让你在你的Winform应用程序中使用HTML5/CSS3/Javascript等网页技术来呈现用户界面(类似Electron). ...

  10. 【CSS3】颜色表示方式

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...