0
 

使用ATL建立支持IClassFactory2的COM组件

 

关键字:COMIClassFactory2、对象创建权限、LicenseLicense Key

 

本文详细描述了如何使用ATL自身的功能创建具有创建权限功能的COM对象。最后还讲述了如何创建具有固定和临时权限的COM对象,以及如何获取注册码。

1      概述

IClassFactory2接口的作用是为给COM对象增加限制控制的功能。通过这个接口,只能在有合法使用权的电脑上才可以创建COM对象的实例。

COM对象的权限有两种,一种是固定权限,在创建COM对象之前就存在电脑中,创建COM对象时不需要提供附加的信息。另一种是临时的权限,在创建对象的时候必须提供表明具有权限的注册码,临时权限不能保留在电脑中,所以,每次创建实例的时候都需要提供注册码。每个COM对象可以选择使用固定权限方式、临时权限方式或两者都使用。

COM对象可以提供取得注册码的功能。通过这个功能,可以在具有固定权限的电脑上获取的注册码。

COM对象被创建的时候,应该检查注册码或者固定权限的信息,如果COM对象判定用户没有使用权限,可以返回CLASS_E_NOTLICENSED

2      ATL对IClassFactory2的支持

ATL完全支持IClassFactory2。通过宏DECLARE_CLASSFACTORY2声明COM对象支持IClassFactory2接口。DECLARE_CLASSFACTORY2宏需要一个License类实现具体的许可权限验证算法和注册码验证算法。License类可以使用任何名字,其中必须定义如下的几个成员函数。License类的形式如下:

 

class CLicenseCls

{

protected:

  static BOOL VerifyLicenseKey(BSTR bstr);

  static BOOL GetLicenseKey(DWORD dwReserved, BSTR* PBstr);

  static BOOL IsLicenseValid();

};

 

VerifyLicenseKey函数用于验证注册码的合法性。GetLicenseKey用于获取注册码。IsLicenseValid函数用于验证是否存在固定的使用权限。

用户可以根据需要,提供这三个函数的实现。如下表:

所需功能

VerifyLicenseKey

GetLicenseKey

IsLicenseValid

不检查权限

FALSE

FALSE

TRUE

固定权限

FALSE

FALSE

检查固定权限

临时权限

检测注册码

FALSE

FALSE

固定权限和

临时权限

检测注册码

FALSE

检查固定权限

固定权限和

临时权限和

获取注册码

检测注册码

返回注册码

检查固定权限

3      实现方式

3.1     License类

实现License类的成员函数:

 

class CMyLicense

{

protected:

static BOOL VerifyLicenseKey(BSTR bstrLicenseKey)

{

  if (wcscmp(bstrLicenseKey, OLESTR("Template License Key")) == 0)

  {

    return TRUE;

  }

  return FALSE;

}

 

static BOOL GetLicenseKey(DWORD dwReserved, BSTR* pBstrLicenseKey)

{

  if (pBstrLicenseKey)

  {

    * pBstrLicenseKey = SysAllocString(OLESTR("Template License Key "));

  }

  return TRUE;

}

 

static BOOL IsLicenseValid() {  return TRUE; }

};

 

以上例子中,IsLicenseValid函数永远返回真。在实际使用中,要验证电脑中是否存在固定权限。如果存在固定权限则返回真,否则返回假。这个例子中使用的是固定注册码,也可以根据需要使用伪随机注册码。

3.2     实现IClassFactory2接口

ATLCOM对象类中通过DECLARE_CLASSFACTORY2宏声明在类对象中使用IClassFactory2接口。DECLARE_CLASSFACTORY2宏的定义如下:

 

DECLARE_CLASSFACTORY2(lic)

 

其中licLicense类的名称,本例中为CMyLicense

4      创建需要License的COM对象

4.1     具有固定权限的COM对象

创建具有固定权限的COM对象的方法和创建普通COM对象是相同的。不需要提供任何附加的信息。

使用CoCreateInstance可以方便的创见固定权限的COM对象。CoCreateInstance的定义如下:

 

STDAPI CoCreateInstance(

REFCLSID rclsid,

LPUNKNOWN pUnkOuter,

DWORD dwClsContext,

REFIID riid,

LPVOID * ppv

);

 

rclsid是要创建对象的CLSID

pUnkOuter用于聚合的情况,不使用聚合的时候,使用NULL

dwClsContext指定COM对象的运行环境,一般情况使用CLSCTX_ALL表示可以在任何环境运行。

riid是需要返回的接口的IID

ppv是返回的接口指针的地址。

具体代码如下:

 

Iyyy * pObj;

HRESULT hr;

hr = CoCreateInstance(CLSID_xxx, NULL, CLSCTX_ALL, IID_yyy, &pObj);

if (FAILED(hr))

{

    ...

}

 

4.2     使用临时权限

使用临时权限创建COM对象,需要一个注册码。注册码可以从COM对象本身获取,也可以通过其它方式取得(如购买等)。使用临时权限创建COM对象需要两个步骤:取得COM类对象和创建COM对象。

4.2.1        取得COM类对象

通过CoGetClassObject函数,可以获取类对象。CoGetClassObject的定义如下:

 

STDAPI CoGetClassObject(

REFCLSID rclsid,

DWORD dwClsContext,

COSERVERINFO * pServerInfo,

REFIID riid,

LPVOID * ppv

);

 

rclsid是要创建COM对象的CLSID

dwClsContextCOM对象的运行方式,一般情况使用CLSCTX_ALL表示可以在任何环境运行。

pServerInfo用于在另一台电脑上创建COM对象,在本地创建时用NULL

riid是所需要的接口的IID,这里使用IID_IClassFactory2

ppv是返回接口指针的地址。

可以看出,前两个参数和在CoCreateInstance中的定义是相同的。

具体代码:

 

    IClassFactory2 * pCF2;

    HRESULT hr;

  hr = CoGetClassObject(CLSID_xxx, CLSCTX_ALL, NULL,

IID_IClassFactory2, (void **)&pCF2);

    if (FAILED(hr))

{

    ...

}

    ...

       

4.2.2        创建对象

通过IClassFactory2CreateInstanceLic方法,可以使用临时权限创建对象。在取得了COM类对象之后,调用CreateInstanceLic方法,并且把注册码作为参数,就可以得到新建的COM对象的接口指针。

CreateInstanceLic的定义如下:

 

HRESULT CreateInstanceLic(

IUnknown* pUnkOuter,

IUnknown* pUnkReserved,

REFIID riid,

BSTR bstrKey,

void** ppvObject

);

 

pUnkOuter是聚合的外部对象指针,在不使用聚合的时候,用NULL

pUnkReserved是保留的参数,用NULL

riid是所需要返回的接口IID

bstrKey是注册码。

ppvObject是保存返回的接口指针的地址。

具体代码:

 

Ixxx * pObj;

hr = pCF2->CreateInstanceLic(NULL, NULL, IID_Ixxx,

bstrLicenseKey, (void**) &pObj);

if (FAILED(hr))

{

    ...

}

 

创建之后就可以像使用普通COM对象一样使用新建的COM对象。

4.3     获取注册码

首先要取得类对象的指针,详见第4.2.1节。

在取得了IClassFactory2的指针之后,通过RequestLicKey方法可以取得注册码。

RequestLicKey的定义如下:

 

HRESULT RequestLicKey(

  DWORD dwReserved,

  BSTR* pbstrKey

);

 

dwReserved是保留参数,用0

pbstrKey是保存返回的注册码的地址。调用方负责释放返回值的地址。

具体代码:

 

BSTR bstrLicKey;

hr = pCF2->RequestLicKey(0, &bstrLicKey);

if (FAILED(hr))

{

    ...

}

...

SysFreeString(bstrLicKey);

关闭 返回顶部
联系我们
Copyright © 2011. 聚财吧. All rights reserved.