COM_第四讲_保存GUID_优化使用代码

    优化以前的代码,让使用者更方便

一丶 优化思路

1.我们可以将我们写的GUID(类工厂的ID)保存到注册表中,并且保存一下DLL的文件路径,遍历注册表去DLL路径即可.

2.每个类工厂我们就要使用一个GUID,而我们就要写到注册表中GUID

注册表在系统的文件夹下:

C:\\ WINDWOS \\ System32\\config下面,当然这个使我们不能删除的,也不能查看的.我们需要调用API来操作

如果要查看,可以运行CMD命令:  

  regedit命令来查看注册表

二丶插件注册

问题一:

  当我们要把类工厂的ID写到注册表中,但是DLL的路径我们不知道,这些都是动态写入的,所以我们需要利用插件注册模式

问题二:

  我们要怎么注册,要写到哪里合适,要怎么注册

1.我们要写到的是注册表的

  计算机\HKEY_CLASSES_ROOT\CLSID 里面,其中项的名称就是类工厂的GUID

2.注册要调用系统的注册工具,我们需要实现3个API供他调用

HRESULT __stdcall DllCanUnloadNow()    /*能否卸载*/

HRESULT __stdcall DllRegisterServer()    /*是否注册*/

HRESULT __stdcall DllUnregisterServer()   /*卸载插件*/

HRESULT __stdcall DllGetClassObject(const GUID& clsid, const GUID& riid, void **ppObject)(其中这个就是COM前边讲的根据类ID返回类工厂)

 三丶设计注册表存储

上面已经准备好了,我们就要设计注册表了,然后依次写入到注册表

const char* g_szRegTable[][3] ={

{"CLSID\\{450A883B-F00A-46b3-AF3C-EC559997396A}", 0, "SuperMath"  /*你的类工厂的GUID*/

}, { "CLSID\\{450A883B-F00A-46b3-AF3C-EC559997396A}\\InprocServer32", 0 ,(const char*)-1(代表你可以动态的写入DLL路径) }, { "CLSID\\{450A883B-F00A-46b3-AF3C-EC559997396A}\\ 这个是可选的,因为你的GUID要存储进去,当我们取出来的时候要根据GUID查找,很麻烦,所以定义怎么一个文件夹,里面存放的就是GUID,可以直接通过他来获得GUID", 0, "SuperMathsrv.SuperMath.1"( }, { "CLSID\\{450A883B-F00A-46b3-AF3C-EC559997396A}\\TypeLib", 0, "{450A883B-F00A-46b3-AF3C-EC559997396A}"你要包含的头文件的路径,放在Typelib里面 }, { "SuperMathsrv.SuperMath", 0, "SuperMath"先定义一个目录,下面取消注册,删除插件的时候需要删除这个文件夹(也就是注册表的一项) }, { "SuperMathsrv.SuperMath\\CLSID", 0, "{450A883B-F00A-46b3-AF3C-EC559997396A}"写入类工厂的GUID }, { "SuperMathsrv.SuperMath\\CurVer", 0, "SuperMathsrv.SuperMath.1"写入类工厂的版本号 }, { "SuperMathsrv.SuperMath.1", 0, "" }, { "SuperMathsrv.SuperMath.1\\CLSID", 0, "{450A883B-F00A-46b3-AF3C-EC559997396A}" }, };

上面是一个二维数组里面保存了要创建注册表的信息

 详解二维数组里面的文件夹:

1.SuperMath 你的类工厂的名字,要创建怎么一个文件夹

2.InprocServer32 这个是注册表标准的文件夹,这里面的默认项填写的是当前COM(也就是DLL)的路径

3.ProID 可选写入 版本

4.TypeLib 这个是使用者需要用#include,所以我们把他的路径也封装一下

5. 这个是可选的,因为你的GUID要存储进去,当我们取出来的时候要根据GUID查找,很麻烦,所以定义怎么一个文件夹,里面存放的就是GUID,可以直接通过他来获得GUID

 这个是可选的,因为你的GUID要存储进去,当我们取出来的时候要根据GUID查找,很麻烦,所以定义怎么一个文件夹,里面存放的就是GUID,可以直接通过他来获得GUID,需要先定义怎么一个文件夹,我们删除的时候使用

最后一个GUID,写入的GUID

四丶在插件注册标准的函数中写注册表

 1  for (int i = 0; i < sizeof(g_szRegTable) / sizeof(g_szRegTable[0]); i++)
 2   {
 3     const char* pszKey = g_szRegTable[i][0]; /*找到数组的第第0项里面以为数组的第0项的值*/
 4     const char* pszValueName = g_szRegTable[i][1];/*一次类推*/
 5     const char* pszValue = g_szRegTable[i][2];
 6     char szModuleName[MAX_PATH];
 7 
 8     HKEY  hKey;
 9     if (RegCreateKeyEx(HKEY_CLASSES_ROOT, /*写入注册表*/
10                       pszKey, NULL, NULL, 
11                      REG_OPTION_VOLATILE, 
12                      KEY_ALL_ACCESS, 
13                      NULL, 
14                      &hKey, 
15                      NULL) != ERROR_SUCCESS)
16       return S_FALSE;
17 
18     if (pszValue == (const char*)-1)/*判断里面的内容是否是这个(主要是第二次循环要动态写入DLL路径)*/
19     {
20       GetModuleFileName(g_hInstan, szModuleName, sizeof(szModuleName));      /*获得DLL路径写入,g_Hinstan是从DLLmain里面保存的,是一个全局变量,因为要获取当前DLL的模块*/
21       pszValue = szModuleName;
22     }
23 
24     if (RegSetValueEx(hKey, pszValueName, NULL, REG_SZ, /*写入值*/
25       (BYTE*)pszValue, strlen(pszValue)) != ERROR_SUCCESS)
26       return S_FALSE;
27 
28     RegCloseKey(hKey); /*关闭Key*/
29   }
30 
31   return S_OK;卸载的时候需要反向卸载
 1 HRESULT __stdcall DllUnregisterServer()
 2 {
 3   int nCount = sizeof(g_szRegTable) / sizeof(g_szRegTable[0]);/*获得大小*/
 4   for (int i = nCount - 1; i >= 0; i--)
 5   {
 6     const char* pszKey = g_szRegTable[i][0];/*获得第x项的第0个下标(一维数组的第一项)的内容*/
 7     if (RegDeleteKey(HKEY_CLASSES_ROOT, pszKey) != ERROR_SUCCESS)
 8       return S_FALSE; /*删除*/
 9   }
10 
11 
12   return S_OK;
13 }

解决全新的字符串格式

我们的COM组件要跨平台使用,所以这个时候不得不考虑字符串了,C语言中的字符串是\0结尾,而Pascal是前边是字符串的长度,后面是字符串

全新的字符串格式 BSTR 他是他们两个的组合 前边是长度,中间是字符串,后边是\0结尾

而COM是C/c++程序员设计的,所以使用BSTR的时候,直接使用,他会默认帮我们移动到数据位,直到遇到\0结尾

而Pascal想要使用,就要自己减去一个,得到长度,然后获得字符串,不考虑\0结尾.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序猿DD

Spring Boot使用@Async实现异步调用:自定义线程池

在之前的Spring Boot基础教程系列中,已经通过《Spring Boot中使用@Async实现异步调用》一文介绍过如何使用 @Async注解来实现异步调用...

71980
来自专栏公众号_薛勤的博客

[转]Spring基础知识汇总 Java开发必看

Spring框架由Rod Johnson开发,2004年发布了Spring框架的第一版。Spring是一个从实际开发中抽取出来的框架,因此它完成了大量开发中的通...

16330
来自专栏日常分享

抛开深层次底层,快速入门SpringMVC

SpringMVC主要有三个核心部分组成,DispatcherServlet、Controller、ViewResolver。      Dispatche...

12130
来自专栏Java 技术分享

两篇 Spring 总结(一)

14830
来自专栏Spring相关

第2章—装配Bean—自动化装配Bean

CD和CDPlayer,如果你不将CD放入(注入)到播放器中,那么CD播放器其实是没多大用处的,所以说,CD播放器是依赖于CD才能完成它的使命.

9120
来自专栏JackieZheng

学习SpringMVC——说说视图解析器

  各位前排的,后排的,都不要走,咱趁热打铁,就这一股劲我们今天来说说spring mvc的视图解析器(不要抢,都有位子~~~)   相信大家在昨天那篇如何获取...

273100
来自专栏静默虚空的博客

[Spring]04_最小化Spring XML配置

4.1 自动装配 Bean Spring 装配 bean 时,有时非常明确,就是需要将某个 bean 的引用装配给指定属性。 例如,若应用上下文中只有一个 j...

203100
来自专栏程序猿DD

【译】Spring 官方教程:创建批处理服务

原文:Creating a Batch Service 译者:Mr.lzc 校对:lexburner 本指南将引导你完成创建基本的批处理驱动解决方案的过程。 你...

55570
来自专栏一个会写诗的程序员的博客

《Spring Boot极简教程》第9章 Spring Boot集成Scala混合Java开发参考资料

本章我们使用Spring Boot集成Scala混合Java开发一个Web性能测试平台。

22920
来自专栏Gaussic

Spring MVC绑定 List 对象参数 原

       最近做的一个小小的项目碰上了如何用 post 传递一整个 list 的问题,在解决这个问题的同时,也顺带升级一下 Spring 的版本,并精简一下...

24510

扫码关注云+社区

领取腾讯云代金券