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

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 '&H55'

testhex的值类型为REG_DWORD, 值为&H55

 

Ø val'testmulti' = m 'String 1\0String2\0'

testmulti的值类型为REG_MULTI_SZ, 值为String 1   String2

 

Ø  registryexpression ::= AddKey DeleteKey

注册表达式等于Add KeyDelete Key

 

Ø KeyName ::= 'AlphaNumeric+'

子键Name等于一个或多个任意的非空字符

 

Ø  registryexpression ::= [ForceRemove|NoRemove|val]

Add Key等于KeyNameForceRemoveNoRemoveval都是可选项

 

Ø 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 等于HKCRHKEY_CURRENT_USER等于HKCU等。

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

 

1.1.3       示例

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

  C++ Code 
1
2
3
4
5
6
7
8
9
10
11
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 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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服务的实际路径(dllexe的路径)

如:

'MySampleKey' =s '%MODULE%,1'

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

 

  C++ Code 
1
2
3
TCHAR  szModule[_MAX_PATH];
::GetModuleFileName(_AtlBaseModule.GetModuleInstance(),  szModule,  _MAX_PATH);
p->AddReplacement(OLESTR( "Module"),  T2OLE(szModule)); 

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

 

注意:

为了替换可替换参数的值,需要脚本中移除DECLARE_REGISTRY_RESOURCEDECLARE_REGISTRY_RESOURCEID宏。使用自定义的UpdateRegistry方法调用CAtlModule::UpdateRegistryFromResourceDCAtlModule::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表示模块路径,nIDszType表示资源的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组件_第1张图片


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

  C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#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 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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组件_第2张图片



【6】源码下载地址

RgsFile

你可能感兴趣的:(ATL使用.rgs注册脚本文件操作注册表注册Com组件)