首页 > 其他分享 >ATL使用.rgs注册脚本文件操作注册表注册Com组件

ATL使用.rgs注册脚本文件操作注册表注册Com组件

时间:2023-08-10 16:07:42浏览次数:60  
标签:rgs hr ATL 注册 注册表 NULL 子键 LPCOLESTR


1.      ATL注册组件



1.1     创建注册脚本



注册脚本通过操作 系统注册表完成Com服务的注册,通过数字形式而非代码API的形式完成,这种形式显得更加简单有效,因为它只需要几行数字代码就可以将一个Key添加到注册表中。

使用ATL向导时,会自动的生成一个后缀为.rgs的注册脚本文件,ATL在服务安装时,会自动的调用脚本文件,实现对注册表的修改,完成Com服务的注册。



1.1.1       基本术语



符号释义

符号

解释

::=

相等

|

               或

X+

               一个或多个Xs

[X]

               X是可选的

字符串字面值:

字符串字面值

行为

ForceRemove

如果存在则删除,再重新建立

NoRemove

反注册时,不删除

val

用于指定一个键的值 

Delete

在注册时,删除Key

s

类型为REG_SZ

d

类型为REG_DWORD

m

类型为REG_MULTI_SZ

b

类型为REG_BINARY

示例:

Ø val'testhex' = d
键testhex的值类型为REG_DWORD, 值为&H55
Ø val'testmulti' = m
键testmulti的值类型为REG_MULTI_SZ, 值为String 1   String2
Ø  registryexpression ::= AddKey | DeleteKey
注册表达式等于Add Key 或Delete Key
Ø KeyName ::= 'AlphaNumeric+'
子键Name等于一个或多个任意的非空字符
Ø  registryexpression ::= [ForceRemove|NoRemove|val]
Add Key等于KeyName,ForceRemove、NoRemove、val都是可选项
Ø AlphaNumeric ::=any character not NULL, that is, ASCII 0
AlphaNumeric为任意的非空字符



1.1.2       分析树



在注册脚本文件中,你可以使用一个或多个分析树对注册表进行操作,其树型结构类似文件夹的目录与文件结构,单个结构如下:

root key{registryexpression}+


详细介绍如下:

rootkey ::= HKEY_CLASSES_ROOT | HKEY_CURRENT_USER |
              HKEY_LOCAL_MACHINE | HKEY_USERS |
              HKEY_PERFORMANCE_DATA | HKEY_DYN_DATA |
              HKEY_CURRENT_CONFIG | HKCR | HKCU |
              HKLM | HKU | HKPD | HKDD | HKCC
registryexpression ::= AddKey | DeleteKey
AddKey ::=[ForceRemove | NoRemove | val]Key Name
             [KeyValue][{< AddKey>}]
DeleteKey ::= Delete KeyName
KeyName ::='AlphaNumeric+'
AlphaNumeric ::=any character not NULL, i.e. ASCII 0
KeyValue ::== KeyType KeyName
KeyType ::=s | d
KeyValue ::='AlphaNumeric'

具体含义,基本术语已经详细介绍了,其中HKEY_CLASSES_ROOT 等于HKCR,HKEY_CURRENT_USER等于HKCU等。

一个分析树可以一次添加一个或多个子键,这种方式通过避免一次只能添加一个子键的限制,显得很有效。



1.1.3       示例



【1】  【1】添加多个子键及键值 



 C++ Code 



HKCU       
 {       
            'MyVeryOwnKey' = s        'HowGoesIt?'       
     {       
                'HasASubkey'       
         {       
                    'PrettyCool?' = d        '55'       
             val        'ANameValue' = s        'WithANamedValue'       
         }       
     }       
 }



在主键HKCU下添加了默认值为'HowGoesIt?'的子键'MyVeryOwnKey',在该子键下添加'HasASubkey'子键,在'HasASubkey'子键下,添加了默认值为'55'的'PrettyCool?'子键和键值对为'WithANamedValue'的'ANameValue',类似文件夹与文件的层次关系,很简单

【2】 注册Com服务 



 C++ Code 



HKCR       
 {       
     ATL.Registrar = s        'ATL Registrar Class'       
     {       
         CLSID = s        '{44EC053A-400F-11D0-9DCD-00A0C90391D3}'       
     }       
     NoRemove CLSID       
     {       
         ForceRemove {44EC053A - 400F - 11D0 - 9DCD - 00A0C90391D3} = s        'ATL Registrar Class'       
         {       
             ProgID = s        'ATL.Registrar'       
             InprocServer32 = s        '%MODULE%'       
             {       
                 val ThreadingModel = s        'Apartment'       
             }       
         }       
     }       
 }



这段理解很简单,在HKCR主键下添加了默认值为'ATL RegistrarClass'的ATL.Registrar子键,在ATL.Registrar子键下添加了默认值为{44EC053A-400F-11D0-9DCD-00A0C90391D3}的CLSID子键。

在HKCR主键下添加了CLSID子键,设定属性为NoRemove,表示反注册时,不删除该子键,在该子键下添加默认值为'ATLRegistrarClass的{44EC053A-400F-11D0-9DCD-00A0C90391D3}子键,设定属性为ForceRemove,表示注册时,如果存在该子键,则首先将该子键下的所有的子键与键值都删除,再重新建立。在{44EC053A-400F-11D0-9DCD-00A0C90391D3}子键下添加了默认值'ATL.Registrar'的子键ProgID与默认值为'%MODULE%'的InprocServer32子键(%MODULE%会自动释义为模块的全路径),在InprocServer32子键下添加键值对'Apartment'的ThreadingModel。

注意一个注册脚本的大小为4K!!!



1.1.4       可替换参数



%MODULE%   ——Com服务的实际路径(dll或exe的路径)

如:

'MySampleKey' =s

在调用注册脚本前,需要建立可替换参数MODULE的映射,调用AddReplacement添加映射,如下:



 C++ Code 



TCHAR szModule[_MAX_PATH];       
 ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szModule, _MAX_PATH);       
 p->AddReplacement(OLESTR(       "Module"), T2OLE(szModule));



这样,在运行时,MODULE会自动释义为Com服务的全路径。

注意:

为了替换可替换参数的值,需要脚本中移除DECLARE_REGISTRY_RESOURCE 和DECLARE_REGISTRY_RESOURCEID宏。使用自定义的UpdateRegistry方法调用CAtlModule::UpdateRegistryFromResourceD或CAtlModule::UpdateRegistryFromResourceS,传入类型为_ATL_REGMAP_ENTRY结构体的数组(至少有一个元素设为{NULL,NULL},且为最后一个元素)否则调用UpdateRegistryFromResource将产生错误。

当创建的是可执行的exe服务时,使用可替换参数%MODULE%,运行时会自动的在映射的路径上添加引用,如果你不想要,可以使用%MODULE_RAW%替换%MODULE%;如果创建的是DLL,则不会添加引用。



1.2     调用注册脚本



使用API调用注册脚本很简单,这里简单介绍:

方法

详细解释

ResourceRegister

HRESULT ResourceRegister(LPCOLESTR resFileName ,UINT nID ,LPCOLESTR szType );

注册脚本包含在资源文件中.resFileName表示模块路径,nID和szType表示资源的ID与类型。 

ResourceUnregister

HRESULT ResourceUnregister(LPCOLESTR resFileName ,UINT nID ,LPCOLESTR szType );

ResourceRegisterSz

HRESULT ResourceRegisterSz(LPCOLESTR resFileName ,LPCOLESTR szID ,LPCOLESTR szType );                        szID包含资源字符串的标识

ResourceUnregisterSz

HRESULT ResourceUnregisterSz(LPCOLESTR resFileName ,LPCOLESTR szID ,LPCOLESTR szType );

FileRegister

HRESULT FileRegister(LPCOLESTR fileName );注册脚本包含在文件中

FileUnregister

HRESULT FileUnregister(LPCOLESTR fileName );

StringRegister

HRESULT StringRegister(LPCOLESTR data );  注册脚本包含在字符串中

StringUnregister

HRESULT StringUnregister(LPCOLESTR data );



1.3    完整测试用例



前面介绍的都是基于ATL向导生成的工程,来操作注册表,完成Com组件的注册,很简单,没有什么技术含量,实用性不强。那如果非ATL向导生成的工程也想使用rgs注册脚本文件进行注册表的操作可以吗?答案是肯定的!

本测试用例就是基于win32控制台应用程序,通过rgs注册脚本文件,操作注册表。

有以下几个步骤:

【1】项目属性要设置使用ATL

ATL使用.rgs注册脚本文件操作注册表注册Com组件_默认值

 

ATL使用.rgs注册脚本文件操作注册表注册Com组件_默认值_02

【2】添加rgs注册脚本文件,设置注册的内容



 C++ Code 



HKEY_CURRENT_USER       
 {       
     NoRemove        'MySOFTWARE' = s        'My Software Test'       
     {       
         NoRemove        'VisualStudio'       
         {       
             NoRemove        '9.0'       
             {       
                 ForceRemove        'CppClean.Connect'       
                 {       
                     val LoadBehavior    = d        0       
                     val CommandLineSafe = d        0       
                     val FriendlyName    = s        'CppClean AddIn'       
                 }       
             }       
         }       

         val DllPath = s        '%Module%'       
     }       
 }



【3】编写操作rgs文件的代码



 C++ Code 



#ifndef _AFXSTD_091159A6_4CF3_4FD0_87B6_8411D7A2F123_INCLUDE_H_       
#define _AFXSTD_091159A6_4CF3_4FD0_87B6_8411D7A2F123_INCLUDE_H_       

#if _MSC_VER >        1000       
#pragma once       
#endif       

#include        "afxwin.h"       
#include        "atlbase.h"       
#include        "statreg.h"       

#define  ATL_NO_ASSERT_ON_DESTROY_NONEXISTENT_WINDOW       
#define  BREAK_ON_FAIL(value)                   if (FAILED(value)){       break;}       
#define  BREAK_ON_NULL(value, newHr)            if (       NULL == value){hr = newHr;        break;}       


class CRegOper       
 {       
public:       
     CRegOper(HRESULT *pHr)       
     {       
         ::CoInitialize(       NULL);       

         HRESULT hr = CoCreateInstance(CLSID_Registrar,        
                                              NULL,       
                                       CLSCTX_INPROC_SERVER,        
                                       IID_IRegistrar,        
                                       (       void**)&m_pRegistrar);       

                if (       NULL != pHr)       
         {       
             *pHr = hr;       
         }       
     }       

            virtual ~CRegOper()       
     {       
         m_pRegistrar =        NULL;       
         ::CoUninitialize();       
     }       

public:       
            //添加可替换参数映射       
     HRESULT AddReplacement(LPCOLESTR lpszKey,  LPCOLESTR lpszItem)       
     {                             
         HRESULT hr = S_OK;       
                do        
         {       
             BREAK_ON_NULL(m_pRegistrar, E_POINTER);            

             hr = m_pRegistrar->AddReplacement(lpszKey, lpszItem);       
         }        while (       false);       

                return(hr);       
     }       
            //rgs文件注册,传入rgs文件的全路径       
     HRESULT FileRegister(PCWSTR pRegFilePath)       
     {       
         HRESULT hr = S_OK;       
                do        
         {       
             BREAK_ON_NULL(m_pRegistrar, E_POINTER);        
             hr = m_pRegistrar->FileRegister(pRegFilePath);       
         }        while (       false);       

                return(hr);       
     }       
            //rgs文件反注册,传入rgs文件的全路径       
     HRESULT FileUnregister(PCWSTR pRegFilePath)       
     {       
         HRESULT hr = S_OK;       
                do        
         {       
             BREAK_ON_NULL(m_pRegistrar, E_POINTER);        
             hr = m_pRegistrar->FileUnregister(pRegFilePath);       
         }        while (       false);       

                return(hr);       
     }       

private:       
     CComPtr m_pRegistrar;       

 };       


#endif        // !_AFXSTD_091159A6_4CF3_4FD0_87B6_8411D7A2F123_INCLUDE_H_



【4】执行代码



 C++ Code 



#include        "stdafx.h"       
#include        "RegOper.h"       


int _tmain(       int argc, _TCHAR* argv[])       
 {       
     HRESULT   hr  = S_OK;       
     CRegOper  regOper(&hr);       

            if (FAILED(hr))       
     {       
                return(       1);       
     }       

     TCHAR szModule[_MAX_PATH] = {       0};       

     USES_CONVERSION;       
     GetModuleFileName(       NULL, szModule, _MAX_PATH);          
     hr = regOper.AddReplacement(OLESTR(       "Module"), T2OLE(szModule));       
            if (SUCCEEDED(hr))       
     {       
         hr = regOper.FileRegister(L       "RegScript.rgs");       
     }       

            return        0;          
 }



【5】执行结果

ATL使用.rgs注册脚本文件操作注册表注册Com组件_默认值

ATL使用.rgs注册脚本文件操作注册表注册Com组件_可替换参数_04

 

【6】源码下载地址

RgsFile

标签:rgs,hr,ATL,注册,注册表,NULL,子键,LPCOLESTR
From: https://blog.51cto.com/u_13675550/7036701

相关文章

  • eureka服务注册与发现
    创建eureka服务器1:为eureka创建模块,在pom中添加支持。2:在yml文件中配置对应参数即可。  创建成功后,将项目接口注册入服务器同样为两步:在pom中添加支持,然后在yml文件中配置好服务器名称和地址即可(该地址应该与服务器地址相同) 注册成功后可以不在使用端口号直接输入配置名调......
  • usb_register注册流程分析
    usb_register流程本文编写的背景是分析RTL8152B的驱动程序,所以先给出该驱动程序的基本信息。/*tableofdevicesthatworkwiththisdriver*/staticstructusb_device_idrtl8152_table[]={ {USB_DEVICE(VENDOR_ID_REALTEK,PRODUCT_ID_RTL8152)}, {}};MODULE_DEVI......
  • 什么是服务注册和发现
    1.什么是服务注册和发现假如这个产品已经在线上运行,有一天运营想搞一场促销活动,那么我们相对应的【用户服务】可能就要新开启三个微服务实例来支撑这场促销活动。而与此同时,作为苦逼程序员的你就只有手动去APIgateway中添加新增的这三个微服务实例的ip与port,一个真正在线......
  • SolidWorks2021中文版软件图文安装教程,注册激活方法【附安装包下载】
    一、下载方式[软件名称]:SolidWorks2021[软件语言]:简体中文 [软件大小]:14.6G[安装环境]:Win11/Win10[硬件要求]:[email protected]内存@8G及以上下载链接%70%61%6E%2E%62%61%69%64%75%2E%63%6F%6D/%73/%31%47%4B%61%44%46%4D%44%56%77%59%34%75%6E%43%52%74%4C%68%47%36%37%41?%70%77%64=%......
  • Windows加域后通过注册表取消壁纸锁定更换壁纸
    打开注册表:开始--运行--regedit(快捷键Win+R)然后找到HKEY_CURRENT_USER==>Software==>Microsoft==>Windows==>CurrentVersion==>Policies,可以输入如下路径到路径栏计算机\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies该目录下有两个子......
  • nacos2.X版本无法注册的几个原因以及解决方案(踩坑避雷!)
    在使用nacos+dubbo注册服务的时候遇到了无法注册的问题记录一下踩的坑以及解决方案com.alibaba.nacos.api.exception.NacosException:Requestnacosserverfailed: atcom.alibaba.nacos.client.naming.remote.gprc.NamingGrpcClientProxy.requestToServer(NamingGrpcClie......
  • 使用$test$plusargs提高RTL验收速度
    0前言这段时间在整合一个小ip,因为要验证每个feature是否可行,需要用testbench+C语言的方式进行仿真验证,由于每种feature不仅要在C语言中修改寄存器配置,还要再testbench修改寄存器的配置,这导致每验证一种feature既需要修改C语言,也需要修改testbench,非常繁琐并且也不想把所有的f......
  • 注册事件
        ......
  • INS-10013:安装程序检测到此系统的中央资源清册中未注册当前home
    错误信息【汉】INS-10013:安装程序检测到此系统的中央资源清册中未注册当前home【英】INS-10013:Theinstallerhasdetectedthatcurrenthomeisnotregisteredinthecentralinventoryonthissystem.例CentOS7操作系统中,在安装Oracle数据库软件时报错。版本Oracle【11.2.0.......
  • Spring Boot 微服务架构中的服务发现和注册
    当涉及到SpringBoot中的微服务架构时,服务发现和注册是一个至关重要的话题。在微服务架构中,各个服务需要相互通信,而服务发现和注册机制则允许服务动态地发现和定位其他服务,从而实现更好的弹性和可扩展性。在本文中,我们将深入探讨如何在SpringBoot中实现服务发现和注册,以及如何......