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

1.      ATL注册组件

1.1     创建注册脚本

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

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

符号释义

符号

解释

::=

相等

|

               或

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 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 
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服务的实际路径(dll或exe的路径)

如:

'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::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组件
 

【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组件


 

【6】源码下载地址

RgsFile

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郎涯技术

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值