大胖的部落格

Just a note

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  112 随笔 :: 0 文章 :: 3 评论 :: 0 Trackbacks


声明自定义的接口继承于IUnknown。需要一个GUID与该接口对应。
定义一个类继承于该接口用来实现。
定义一个类Factory继承于IClassFactory,用来创建实现类。需要一个GUID与该factory对应。


实现类除了需要实现自定义的接口外,还要声明一个用来计数的成员,用来统计多少用户引用了自己,并实现IUnknown中声明的三个纯虚函数:
AddRef:计数加1。
Release:计数减一,当计数为0的时候,delete自己。
QueryInterface:根据传入的GUID,把自己的this指针转换成GUID对应的接口类型,传给用户,调用一次AddRef(因为又多了一个使用该对象的用户)。用户得到的是接口类型指针,可以调用函数。

Factory类除了实现上面三个纯虚函数外,还需要实现另外两个纯虚函数:
CreateInstance:创建一个实现类对象,调用一次该对象的QueryInterface(对象计数+1,表示对象已被创建);将对象以IUnknown类型传给用户(用户不需要知道对象具体类型,但需要得到对象)。
LockServer:--


该com组件以DLL形式存在,需要导出以下四个函数:
DllGetClassObject:com库在载入DLL后,会调用此函数,在此函数中创建Factory类对象,调用一次QueryInterface(对象计数+1)。
DllCanUnloadNow:判断DLL是否可以被卸载。
DllRegisterServer: 当执行RegSvr32命令加载DLL时被调用,用来写注册表。
DllUnregisterServer :当执行RegSvr32 -u命令卸载DLL时被调用。


自定义的COM组建在被COM库使用前必须在HKEY_CLASSES_ROOT\CLSID键值下注册。用factory的GUID 作为
键名字,这个键值必须包含两个子键,一是DLL的位置,二是DLL的线程模型。





客户端使用时按如下步骤:
1、调用CoInitialize初始化COM库。
2、调用CoCreateInstance指定factory的GUID,获得IUnknown类型的对象指针(不需要知道对象类型)。
3、调用QueryInterface指定接口的GUID,获得接口指针(实际指向实现类对象)。
4、用该接口指针调用自定义的方法。
5、调用Release释放接口、对象,CoUninitialize释放com库资源。

过程如下图所示:





自定义接口头文件 IMyInterface.h

#ifndef __MY_INTERFACE__
#define __MY_INTERFACE__

#include 
"Unknwn.h"

//自己的接口
interface IMyInterface: public IUnknown
{
public:
    
virtual void MyTest() = 0;
}
;

#endif

实现类头文件 MyClass.h
#ifndef __MY_CLASS__
#define __MY_CLASS__

#include 
"IMyInterface.h"

//实现接口的类
class MyClass: public IMyInterface
{
public:
    MyClass();
    
~MyClass();

    
//from IUnknown
    ULONG    STDMETHODCALLTYPE AddRef();
    ULONG    STDMETHODCALLTYPE Release();
    HRESULT STDMETHODCALLTYPE QueryInterface(
const IID& iid, void** ppvObject);

    
//from IMyInterface
    void    MyTest();

private:
    
int        m_Ref ;
}
;

#endif

类工厂头文件 MyFactory.h
#ifndef __MY_FACTORY__
#define __MY_FACTORY__

#include 
"Unknwn.h"

//创建类的类工厂
class MyFactory: public IClassFactory
{
   
public:
      MyFactory ();
      
~MyFactory ();

      
//from IUnknown
      HRESULT    STDMETHODCALLTYPE QueryInterface(const IID& iid, void **ppv);
      ULONG        STDMETHODCALLTYPE AddRef();
      ULONG        STDMETHODCALLTYPE Release();

      
//from IClassFactory
      HRESULT    STDMETHODCALLTYPE CreateInstance(IUnknown* , const IID& iid, void **ppv);
      HRESULT    STDMETHODCALLTYPE LockServer(BOOL);

private:
      ULONG        m_Ref;
}
;

#endif

类的实现 MyClass.cpp
#include "MyClass.h"
#include 
<stdio.h>

//接口的GUID
extern "C" const GUID IID_IMyInterface = 
        
0x54bf65690x10070x11d1,
        
0xb00xaa0x440x450x530x540x000x00} }
 ;

ULONG    g_ClassNum 
= 0;        //统计类对象
ULONG    g_LockNumber = 0;        

MyClass::MyClass()
:m_Ref(
0)
{
    
++g_ClassNum;
}


MyClass::
~MyClass()
{
    
--g_ClassNum;
}


ULONG MyClass::AddRef()
{
    
++m_Ref;
    
return (ULONG)m_Ref;
}


ULONG MyClass::Release()
{
    
--m_Ref;
    
if (m_Ref == 0 ) {
        delete 
this;
        
return 0;
    }

    
return  (ULONG) m_Ref;
}


HRESULT MyClass::QueryInterface(
const IID& iid, void** ppvObject)
{
    
if ( iid == IID_IUnknown )
    
{
        
*ppvObject = (IMyInterface *this ;
                ((IMyInterface 
*)(*ppvObject))->AddRef() ;
    }

    
else if ( iid == IID_IMyInterface ) 
    
{
        
*ppvObject = (IMyInterface *this ;
                ((IMyInterface 
*)(*ppvObject))->AddRef() ;
    }

    
else
    
{
        
*ppvObject = NULL;
        
return E_NOINTERFACE ;
    }


    
return S_OK;
}


void MyClass::MyTest()
{
    printf(
"MyTest called\n");
}

类工厂的实现 MyFactory.cpp
#include "MyFactory.h"
#include 
"MyClass.h"

extern ULONG    g_LockNumber;
extern ULONG    g_ClassNum;

MyFactory::MyFactory()
:m_Ref(
0)
{

}


MyFactory::
~MyFactory()
{

}


HRESULT  MyFactory::QueryInterface(
const IID& iid, void **ppv)
{
    
if ( iid == IID_IUnknown )
    
{
        
*ppv = (IUnknown *this ;
                ((IUnknown 
*)(*ppv))->AddRef() ;
    }
 
    
else if ( iid == IID_IClassFactory) 
    
{
        
*ppv = (IClassFactory *this ;
                ((IClassFactory 
*)(*ppv))->AddRef() ;
    }
 
    
else
    
{
        
*ppv = NULL;
        
return E_NOINTERFACE ;
    }

    
return S_OK;
}


ULONG MyFactory::AddRef()
{
    
++m_Ref;
    
return  (ULONG)m_Ref;
}


ULONG MyFactory::Release()
{
    
--m_Ref;
    
if (m_Ref == 0
    
{
        delete 
this;
        
return 0;
    }

    
return  (ULONG)m_Ref;
}


HRESULT MyFactory::CreateInstance(IUnknown 
*pUnknownOuter, 
                                           
const IID& iid, void **ppv)
{
   MyClass
*    pObj;   
   HRESULT hr;
   
   
*ppv=NULL;
   hr
=E_OUTOFMEMORY;

   
if (NULL != pUnknownOuter)
       
return CLASS_E_NOAGGREGATION;
   
   
//Create the object 
   pObj = new MyClass();
   
if (NULL==pObj)
      
return hr;   
   
   
//Obtain the first interface pointer (which does an AddRef)
   hr=pObj->QueryInterface(iid, ppv);

   
if (hr != S_OK) {
      delete pObj;
   }

   
   
return hr;   
}


HRESULT MyFactory::LockServer(BOOL bLock)
{
   
if (bLock)
      g_LockNumber 
++;
   
else
      g_LockNumber 
--;

   
return NOERROR;
}

需要导出的函数
MyCom.cpp
#include "MyFactory.h"


extern ULONG    g_LockNumber;
extern ULONG    g_ClassNum;
HANDLE            g_hModule 
= NULL;        //用来获得DLL文件名

//对应该com组件
extern "C" const GUID CLSID_Facotry = 
        
0x54bf65670x10070x11d1,
        
0xb00xaa0x440x450x530x540x000x00} }
 ;


//DLL 入口
BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
{
    g_hModule 
= hModule;
    
return TRUE;
}


//写注册表
//先创建,在写值
BOOL SetKey(const WCHAR* key, const WCHAR* value)
{
    HKEY hKey; 
    
//创建KEY
    long lResult = ::RegCreateKeyEx(HKEY_CLASSES_ROOT ,
                                  key, 
                                  
0, NULL, REG_OPTION_NON_VOLATILE,
                                  KEY_ALL_ACCESS, NULL, 
                                  
&hKey, NULL) ;
    
if (lResult != ERROR_SUCCESS)
    
{
        
return FALSE ;
    }


    
//写value
    lResult = ::RegSetValueEx(hKey, NULL, 0, REG_SZ, (const BYTE*)value, (DWORD)(wcslen(value)+1)*2);
    
if (lResult != ERROR_SUCCESS)
    
{
        ::RegCloseKey(hKey);
        
return FALSE ;
    }


    ::RegCloseKey(hKey);
    
return TRUE;
}


//删除注册表
//因为::RegDeleteKey只能删除没有子key的key,
//所以提供该函数,删除一个key时,先删除其所有子key
BOOL DelKey(HKEY key, const WCHAR* subkey)
{
    HKEY hKeyChild ;
    
//open the key
    LONG lRes = RegOpenKeyEx(key, subkey, 0,
                             KEY_ALL_ACCESS, 
&hKeyChild) ;
    
if (lRes != ERROR_SUCCESS)
    
{
        
return FALSE ;
    }


    WCHAR name[
1024] ;
    DWORD size 
= 2048;
    
while (::RegEnumKeyEx(hKeyChild, 0, name, &size, NULL, NULL, NULL, NULL) == S_OK)
    
{
        
//若还有子key,则递归调用该函数
        BOOL bRes = DelKey(hKeyChild, name) ;
        
if (FALSE == bRes)
        
{
            
// 出错,Close key
            ::RegCloseKey(hKeyChild) ;
            
return FALSE;
        }

        size 
= 2048 ;
    }


    
//该key没有子key,关闭该key,删除该key
    ::RegCloseKey(hKeyChild) ;
    
if(ERROR_SUCCESS != ::RegDeleteKey(key, subkey))
        
return FALSE;

    
return TRUE;
}


//供com库调用,创建factory类对象
extern "C" HRESULT   __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)
{
    
if (clsid == CLSID_Facotry ) 
    
{
        MyFactory 
*pFactory = new MyFactory;
        
        
if (pFactory == NULL) {
            
return E_OUTOFMEMORY ;
        }

        
        HRESULT result 
= pFactory->QueryInterface(iid, ppv);

        
return result;
    }
 else {
        
return CLASS_E_CLASSNOTAVAILABLE;
    }

}


//判断dll是否可以被卸载
extern "C" HRESULT __stdcall DllCanUnloadNow(void)
{
    
if ((g_ClassNum == 0&& (g_LockNumber == 0))
        
return S_OK;
    
else
        
return S_FALSE;
}


//使用regsvr32注册DLL时会被调用
//向注册表中写信息:1、DLL位置;2、线程模型
extern "C"  HRESULT __stdcall DllRegisterServer()
{
    
//Get DLL name
    WCHAR szName[1024];
    
if(0 == ::GetModuleFileName((HMODULE)g_hModule, szName, 2048))
        
return S_FALSE;

    
//Get key
    LPOLESTR sKey = NULL;
    
//由GUID获得字符串
    if(S_OK != ::StringFromCLSID(CLSID_Facotry, &sKey))
        
return S_FALSE;
    WCHAR wKey_1[
1024= L"CLSID\\"
    wcscat_s(wKey_1, 
sizeof(wKey_1), sKey);
    wcscat_s(wKey_1, 
sizeof(wKey_1), L"\\InprocServer32");

    
//Set first key and value
    SetKey(wKey_1, szName);
    
    WCHAR wKey_2[
1024= L"CLSID\\"
    wcscat_s(wKey_2, 
sizeof(wKey_2), sKey);
    wcscat_s(wKey_2, 
sizeof(wKey_2), L"\\ProgID");

    
//Set second key and value
    SetKey(wKey_2, L"MyCom");
    
    ::CoTaskMemFree(sKey);
    
return S_OK;
}


//使用regsvr32 -u卸载DLL时会被调用
//删除之前在注册表中写入的信息
extern "C" HRESULT __stdcall DllUnregisterServer()
{
    
//Get key
    LPOLESTR sKey = NULL;
    
if(S_OK != ::StringFromCLSID(CLSID_Facotry, &sKey))
        
return S_FALSE;
    WCHAR wKey[
1024= L"CLSID\\"
    wcscat_s(wKey, 
sizeof(wKey), sKey);
    
    
if(FALSE == DelKey(HKEY_CLASSES_ROOT, wKey))
        
return S_FALSE;

    
return S_OK;
}



导出声明 Export.def
LIBRARY    "TestCom"

EXPORTS
    DllGetClassObject    PRIVATE
    DllCanUnloadNow        PRIVATE
    DllRegisterServer    PRIVATE
    DllUnregisterServer    PRIVATE

以上文件在同一工程中,生成一个DLL,在注册表中注册后,客户端可以使用自己定义的接口。

客户端代码:
#include <iostream>
#include 
<comdef.h>
#include 
"IMyInterface.h"
using namespace std;

//Interface ID
extern "C" const GUID IID_IMyInterface = 
        
0x54bf65690x10070x11d1,
        
0xb00xaa0x440x450x530x540x000x00} }
 ;

//Class Factory ID
extern "C" const GUID CLSID_Facotry = 
        
0x54bf65670x10070x11d1,
        
0xb00xaa0x440x450x530x540x000x00} }
 ;


int main()
{
    IUnknown 
*pUnknown;            //指向对象,不需要知道对象是谁
    IMyInterface *pInterface;    //接口指针
    HRESULT hResult;

    
//初始化com库
    if (CoInitialize(NULL) != S_OK) {
        printf(
"Initialize COM library failed!\n");
        
return -1;
    }


    
//创建类对象
    hResult = CoCreateInstance(CLSID_Facotry, NULL, 
        CLSCTX_INPROC_SERVER, IID_IUnknown, (
void **)&pUnknown);
    
if (hResult != S_OK) 
    
{
        printf(
"Create object failed!\n");
        
return -2;
    }


    
//获得接口
    hResult = pUnknown->QueryInterface(IID_IMyInterface, (void **)&pInterface);
    
if (hResult != S_OK) {
        pUnknown
->Release();
        printf(
"QueryInterface IDictionary failed!\n");
        
return -4;
    }


    
//调用函数
    pInterface->MyTest();

    
//释放
    pInterface->Release();
    pUnknown
->Release();

    
//释放com库资源
    CoUninitialize();

    
return 0;
}
posted on 2009-06-25 15:52 大胖 阅读(334) 评论(0)  编辑 收藏 引用 所属分类: Win32

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理