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. PXE搭建

    前提最好是防火墙规则-F,关闭,selinux 是disable 这个在以后更新linux系统的时候还可以在这个基础上再次增加可以一体化安装的系统. 1.用yum来安装所需要的软件包,先来搭建yum光 ...

  3. mentohust 使用

    可使用帮助命令 mentohust -h 或着查看 https://wenku.baidu.com/view/95c08019ff00bed5b9f31d1a.html

  4. Git 企业开发者教程

      为什么要写这样一个面向企业开发者的Git教程?这个问题也困扰我自己很久.其实我使用git的时间也不短了,但是就和正在阅读本文的每一位一样,常用的基本就是那么几个(git clone, git pu ...

  5. Codebase Refactoring (with help from Go)

    Codebase Refactoring (with help from Go) 代码库重构(借助于Go) 1.摘要 Go应该添加为类型创建替代等效名称的能力,以便在代码库重构期间渐进代码修复.本文解 ...

  6. php 理解

    <?php class t { var $num; var $dynamic_function; public function dynamic_function() { $func = $th ...

  7. Python sort方法

    官方文档: sort(*, key=None, reverse=False) This method sorts the list in place, using only < comparis ...

  8. Git详解之八:Git与其他系统

    Git 与其他系统 世界不是完美的.大多数时候,将所有接触到的项目全部转向 Git 是不可能的.有时我们不得不为某个项目使用其他的版本控制系统(VCS, Version Control System ...

  9. 跟我一起,利用bitcms内容管理系统从0到1学习小程序开发:一、IIS下SSL环境搭建

    缘起 1.从事互联网十来年了,一直想把自己的从事开发过程遇到的问题给写出来,分享给大家.可是可是这只是个种想法,想想之后就放下了,写出来的类文章是少之又少.古人说无志之人常立志,有志之人立长志.今天, ...

  10. php curl 请求302跳转页面

    今天对接支付接口,需要获取支付页面,发现支付商那边给的链接会发送302 跳转,最后发现该方法,绝对给力: <?php $url = 'http://auto.jrj.com.cn/'; $ch ...