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. C#线程等待句柄

    相互排斥对象 Mutex private Mutex m = new Mutex(); public void Method(){ m.WaitOne(); //运行操作 m.ReleaseMutex ...

  2. Parcel.js + Vue 2.x 极速零配置打包体验

    继 Browserify.Webpack 之后,又一款打包工具 Parcel 横空出世 Parcel.js 的官网有这样的自我介绍 “极速零配置Web应用打包工具” 简单接触了一下,单从效率上来说,确 ...

  3. Docker-py 的使用

    Docker SDK for Python A Python library for the Docker Engine API 具体文档这里,https://docker-py.readthedoc ...

  4. MAC系统里JDK版本切换

    1.首先安装需要的JDK版本 JDK7,JDK8则需要自己到Oracle官网下载安装对应的版本.自己安装的JDK默认路径为:/Library/Java/JavaVirtualMachines/jdk1 ...

  5. 如何连接别人电脑上的Oracle数据库--duende99

    需要一些前提条件: 1.对方的主机能被连接(如在同一局域网内) 2.需要知道对方数据库IP.端口号.服务名 3.需要知道对方提供的管理数据库的用户名及密码 连接方法: 1.在本地的oracle安装目录 ...

  6. iOS开发 字符串的转化 小技巧

    /字典或者数组转化为nsstring NSArray *arr = [NSArray arrayWithObject:@"1"]; NSString *str = [arr JSO ...

  7. spark-submit参数说明--standalone

    示例: spark-submit [--option value] <application jar> [application arguments] 参数名称 含义 --master M ...

  8. www.netcraft.com查看站点服务器使用的是什么操作系统

    查看站点服务器使用的是什么操作系统

  9. 【java】实现一个简单的正则:判断一个字符串是否全由数字组成

    package 正则; public class TestIsNum { public static void main(String[] args) { String s1="abc&qu ...

  10. 【java】ArrayList、Iterator用法

    package com.tn.collect; import java.util.ArrayList; import java.util.Iterator; class Product{ public ...