COM---类厂

问题:为什么要使用类厂?
答案:http://www.cppblog.com/ivenher/articles/16460.html

使用类厂的流程:
客户调用CoCreateInstance,而CoCreateInstance调用CoGetClassObejct,CoGetClassObejct的作用是调用LoadLibrary寻找指定的COM组件(dll),然后使用GetProcAddress寻找组件的入口函数,其中DllGetClassObject被调用,这几步不可见,因为微软已经封装好了。
问题:CoGetClassObejct要加载dll,但我们并没有传dll路径,如何加载dll的?
答案:是通过第一个参数CLSID(组件id,从CreateInstance传过去)去注册表中找到这个组件的DLL路径,然后将DLL加载起来,就可以使用DLL的导出函数DllGetClassObject了,并把CLSID,类厂接口ID传给它,去创建所需的组件,并返回所需的接口。

注意:组件并不等于dll,一个dll可以提供多个组件

接口

//
// Iface.h - 
//    Declarations of interfaces, IIDs, and CLSID
//    shared by the client and the component.
//
interface IX : IUnknown
{
    virtual void pascal Fx() = 0 ;
};


interface IY : IUnknown
{
    virtual void pascal Fy() = 0 ;
};


interface IZ : IUnknown
{
    virtual void pascal Fz() = 0 ;
};

//
// Declaration of GUIDs for interfaces and component.
//   These constants are defined in GUIDs.cpp.
//
extern "C" const IID IID_IX ;
extern "C" const IID IID_IY ;
extern "C" const IID IID_IZ ;

extern "C" const CLSID CLSID_Component1 ;

连接客户和组件—GUID

//
// GUIDs.cpp
//   - Defines all IIDs and CLSIDs for the client and the component.
//     The declaration of these GUIDs is in Iface.h
//
#include <objbase.h>

// {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
extern "C" const IID IID_IX = 
    {0x32bb8320, 0xb41b, 0x11cf,
    {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

// {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
extern "C" const IID IID_IY = 
    {0x32bb8321, 0xb41b, 0x11cf,
    {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

// {32bb8322-b41b-11cf-a6bb-0080c7b2d682}
extern "C" const IID IID_IZ = 
    {0x32bb8322, 0xb41b, 0x11cf,
    {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

// {0c092c21-882c-11cf-a6bb-0080c7b2d682}
extern "C" const CLSID CLSID_Component1 =
    {0x0c092c21, 0x882c, 0x11cf,
    {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;

组件

//
// Cmpnt.cpp
//
#include <iostream.h>
#include <objbase.h>

#include "Iface.h"      // Interface declarations
#include "Registry.h"   // Registry helper functions

// Trace function
void trace(const char* msg) { cout << msg << endl ;}

///////////////////////////////////////////////////////////
//
// 全局变量
//
static HMODULE g_hModule = NULL ;   // DLL module handle
static long g_cComponents = 0 ;     // Count of active components
static long g_cServerLocks = 0 ;    // Count of locks

// Friendly name of component
const char g_szFriendlyName[] = "Inside COM, Chapter 7 Example" ;

// Version-independent ProgID
const char g_szVerIndProgID[] = "InsideCOM.Chap07" ;

// ProgID
const char g_szProgID[] = "InsideCOM.Chap07.1" ;


///////////////////////////////////////////////////////////
//
// 组件
//
class CA : public IX,
           public IY 
{
public:
    // IUnknown
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;
    virtual ULONG __stdcall AddRef() ;
    virtual ULONG __stdcall Release() ;

    // Interface IX
    virtual void __stdcall Fx() { cout << "Fx" << endl ;}

    // Interface IY
    virtual void __stdcall Fy() { cout << "Fy" << endl ;} 

    // Constructor
    CA() ;

    // Destructor
    ~CA() ;

private:
    // 引用计数
    long m_cRef ;
} ;


//
// Constructor
//
CA::CA() : m_cRef(1)
{ 
    InterlockedIncrement(&g_cComponents) ;   //增加组件计数
}

//
// Destructor
//
CA::~CA() 
{ 
    InterlockedDecrement(&g_cComponents) ;   //减少组件计数
    trace("Component:\t\tDestroy self.") ;
}

//
// IUnknown implementation
//
HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{    
    if (iid == IID_IUnknown)
    {
        *ppv = static_cast<IX*>(this) ; 
    }
    else if (iid == IID_IX)
    {
        *ppv = static_cast<IX*>(this) ;
        trace("Component:\t\tReturn pointer to IX.") ; 
    }
    else if (iid == IID_IY)
    {
        *ppv = static_cast<IY*>(this) ; 
        trace("Component:\t\tReturn pointer to IY.") ; 
    }
    else
    {
        *ppv = NULL ;
        return E_NOINTERFACE ;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
    return S_OK ;
}

ULONG __stdcall CA::AddRef()
{
    return InterlockedIncrement(&m_cRef) ;
}

ULONG __stdcall CA::Release() 
{
    if (InterlockedDecrement(&m_cRef) == 0)
    {
        delete this ;
        return 0 ;
    }
    return m_cRef ;
}


///////////////////////////////////////////////////////////
//
// 类厂,由开发人员决定。创建好类厂后,调用CreateInstance创建组件
//
class CFactory : public IClassFactory
{
public:
    // IUnknown
    virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;         
    virtual ULONG   __stdcall AddRef() ;
    virtual ULONG   __stdcall Release() ;

      //IClassFactory 接口
    virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
                                             const IID& iid,
                                             void** ppv) ;
    virtual HRESULT __stdcall LockServer(BOOL bLock) ; 

    // Constructor
    CFactory() : m_cRef(1) {}

    // Destructor
    ~CFactory() { trace("Class factory:\t\tDestroy self.") ;}

private:
    long m_cRef ;
} ;

//
// Class factory IUnknown implementation
//
HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)
{    
    if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))
    {
        *ppv = static_cast<IClassFactory*>(this) ; 
    }
    else
    {
        *ppv = NULL ;
        return E_NOINTERFACE ;
    }
    reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
    return S_OK ;
}

ULONG __stdcall CFactory::AddRef()
{
    return InterlockedIncrement(&m_cRef) ;
}

ULONG __stdcall CFactory::Release() 
{
    if (InterlockedDecrement(&m_cRef) == 0)
    {
        delete this ;
        return 0 ;
    }
    return m_cRef ;
}

// IClassFactory implementation
//创建一个组件,然后向它查询某个接口
//CreateInstance 对其所创建的组件知根知底
//pUnknownOuter:同传给CoCreateInstance的IUnknown指针相同,用于聚合组
//剩余2个参数与QueryInterface相同
HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
                                           const IID& iid,
                                           void** ppv) 
{
    trace("Class factory:\t\tCreate component.") ;

    // Cannot aggregate.
    if (pUnknownOuter != NULL)
    {
        return CLASS_E_NOAGGREGATION ;
    }

    // 创建组件
    CA* pA = new CA ;
    if (pA == NULL)
    {
        return E_OUTOFMEMORY ;
    }

    // 查询接口
    HRESULT hr = pA->QueryInterface(iid, ppv) ;

    // 释放 IUnknown 指针
    // (If QueryInterface failed, component will delete itself.)
    pA->Release() ;
    return hr ;
}

// 将服务器保存在内存中,直至使用完毕
HRESULT __stdcall CFactory::LockServer(BOOL bLock) 
{
    if (bLock)
    {
        InterlockedIncrement(&g_cServerLocks) ;     //加锁
      }
    else
    {
        InterlockedDecrement(&g_cServerLocks) ;   //解锁
    }
    return S_OK ;
}


///////////////////////////////////////////////////////////
//
// 从DLL中输出的函数
//

//
// 被CoFreeUnusedLibraries调用,以询问DLL是否可被卸载掉,节省内存
//
STDAPI DllCanUnloadNow()
{
      //当DLL不再提供任何组件,且类厂没有锁
    if ((g_cComponents == 0) && (g_cServerLocks == 0))
    {
        return S_OK ;
    }
    else
    {
        return S_FALSE ;
    }
}

//由CoGetClassObject调用,创建客户所请求的类厂
//同CreateInstance类似,创建一个组件,然后向它查询某个接口
//DllGetClassObject 对其所创建的类厂无所不知
//clsid:类厂将要创建的组件的CLSID
//iid:类厂中客户希望得到的接口的ID
//ppv:保存接口指针
STDAPI DllGetClassObject(const CLSID& clsid,
                         const IID& iid,
                         void** ppv)
{
    trace("DllGetClassObject:\tCreate class factory.") ;

    // 检查客户所请求的类厂组件是否能创建
    if (clsid != CLSID_Component1)
    {
        return CLASS_E_CLASSNOTAVAILABLE ;
    }

    // 用new操作符完成组件的创建
    CFactory* pFactory = new CFactory ;  // No AddRef in constructor
    if (pFactory == NULL)
    {
        return E_OUTOFMEMORY ;
    }

    // 用类厂组件查询客户所请求的接口
    HRESULT hr = pFactory->QueryInterface(iid, ppv) ;
    pFactory->Release() ;

    return hr ;
}

//
// 在Windows注册表中登记组件
//
STDAPI DllRegisterServer()
{
    return RegisterServer(g_hModule, 
                          CLSID_Component1,
                          g_szFriendlyName,
                          g_szVerIndProgID,
                          g_szProgID) ;
}


//
// 在Windows注册表中注销组件
//
STDAPI DllUnregisterServer()
{
    return UnregisterServer(CLSID_Component1,
                            g_szVerIndProgID,
                            g_szProgID) ;
}

///////////////////////////////////////////////////////////
//
// DLL module information
//将模块句柄保存在全局变量g_hModule中,以供DllRegisterServer和  
//DllUnregisterServer使用
BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD dwReason,
                      void* lpReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        g_hModule = hModule ;
    }
    return TRUE ;
}

Cmpnt.def,定义dll要输出的函数

LIBRARY         Cmpnt.dll
DESCRIPTION     'Chapter 7 Example COM Component (c)1996-1997 Dale E. Rogerson'

EXPORTS
                DllGetClassObject   @2  PRIVATE
                DllCanUnloadNow     @3  PRIVATE
                DllRegisterServer   @4  PRIVATE
                DllUnregisterServer @5  PRIVATE

注册组件

#ifndef __Registry_H__
#define __Registry_H__
//
// Registry.h
//   - Helper functions 登记、注销组件
//

// 在Windows注册表中登记组件
// 被DllRegisterServer调用
HRESULT RegisterServer(HMODULE hModule, 
                       const CLSID& clsid, 
                       const char* szFriendlyName,
                       const char* szVerIndProgID,
                       const char* szProgID) ;

// 在Windows注册表中注销组件
// 被DllUnregisterServer调用
HRESULT UnregisterServer(const CLSID& clsid,
                         const char* szVerIndProgID,
                         const char* szProgID) ;

#endif
//
// Registry.cpp
//

//定义了 #define interface struct
#include <objbase.h>
#include <assert.h>

#include "Registry.h"

////////////////////////////////////////////////////////
//
// Internal helper functions prototypes
//

// Set the given key and its value.
BOOL setKeyAndValue(const char* pszPath,
                    const char* szSubkey,
                    const char* szValue) ;

// Convert a CLSID into a char string.
void CLSIDtochar(const CLSID& clsid, 
                 char* szCLSID,
                 int length) ;

// Delete szKeyChild and all of its descendents.
LONG recursiveDeleteKey(HKEY hKeyParent, const char* szKeyChild) ;

////////////////////////////////////////////////////////
//
// Constants
//

// Size of a CLSID as a string
const int CLSID_STRING_SIZE = 39 ;

/////////////////////////////////////////////////////////
//
// Public function implementation
//

//
// 在Windows注册表中登记组件
//
HRESULT RegisterServer(HMODULE hModule,            // DLL module handle
                       const CLSID& clsid,         // Class ID
                       const char* szFriendlyName, // Friendly Name
                       const char* szVerIndProgID, // Programmatic
                       const char* szProgID)       //   IDs
{
    // Get server location.
    char szModule[512] ;
    DWORD dwResult =
        ::GetModuleFileName(hModule, 
                            szModule,
                            sizeof(szModule)/sizeof(char)) ;
    assert(dwResult != 0) ;

    // Convert the CLSID into a char.
    char szCLSID[CLSID_STRING_SIZE] ;
    CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)) ;

    // Build the key CLSID\\{...}
    char szKey[64] ;
    strcpy(szKey, "CLSID\\") ;
    strcat(szKey, szCLSID) ;

    // Add the CLSID to the registry.
    setKeyAndValue(szKey, NULL, szFriendlyName) ;

    // Add the server filename subkey under the CLSID key.
    setKeyAndValue(szKey, "InprocServer32", szModule) ;

    // Add the ProgID subkey under the CLSID key.
    setKeyAndValue(szKey, "ProgID", szProgID) ;

    // Add the version-independent ProgID subkey under CLSID key.
    setKeyAndValue(szKey, "VersionIndependentProgID",
                   szVerIndProgID) ;

    // Add the version-independent ProgID subkey under HKEY_CLASSES_ROOT.
    setKeyAndValue(szVerIndProgID, NULL, szFriendlyName) ; 
    setKeyAndValue(szVerIndProgID, "CLSID", szCLSID) ;
    setKeyAndValue(szVerIndProgID, "CurVer", szProgID) ;

    // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
    setKeyAndValue(szProgID, NULL, szFriendlyName) ; 
    setKeyAndValue(szProgID, "CLSID", szCLSID) ;

    return S_OK ;
}

//
// 在Windows注册表中注销组件
//
LONG UnregisterServer(const CLSID& clsid,         // Class ID
                      const char* szVerIndProgID, // Programmatic
                      const char* szProgID)       //   IDs
{
    // Convert the CLSID into a char.
    char szCLSID[CLSID_STRING_SIZE] ;
    CLSIDtochar(clsid, szCLSID, sizeof(szCLSID)) ;

    // Build the key CLSID\\{...}
    char szKey[64] ;
    strcpy(szKey, "CLSID\\") ;
    strcat(szKey, szCLSID) ;

    // Delete the CLSID Key - CLSID\{...}
    LONG lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szKey) ;
    assert((lResult == ERROR_SUCCESS) ||
           (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.

    // Delete the version-independent ProgID Key.
    lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID) ;
    assert((lResult == ERROR_SUCCESS) ||
           (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.

    // Delete the ProgID key.
    lResult = recursiveDeleteKey(HKEY_CLASSES_ROOT, szProgID) ;
    assert((lResult == ERROR_SUCCESS) ||
           (lResult == ERROR_FILE_NOT_FOUND)) ; // Subkey may not exist.

    return S_OK ;
}

///////////////////////////////////////////////////////////
//
// Internal helper functions
//

// Convert a CLSID to a char string.
void CLSIDtochar(const CLSID& clsid,
                 char* szCLSID,
                 int length)
{
    assert(length >= CLSID_STRING_SIZE) ;
    // Get CLSID
    LPOLESTR wszCLSID = NULL ;
    HRESULT hr = StringFromCLSID(clsid, &wszCLSID) ;
    assert(SUCCEEDED(hr)) ;

    // Covert from wide characters to non-wide.
    wcstombs(szCLSID, wszCLSID, length) ;

    // Free memory.
    CoTaskMemFree(wszCLSID) ;
}

//
// Delete a key and all of its descendents.
//
LONG recursiveDeleteKey(HKEY hKeyParent,           // Parent of key to delete
                        const char* lpszKeyChild)  // Key to delete
{
    // Open the child.
    HKEY hKeyChild ;
    LONG lRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,
                             KEY_ALL_ACCESS, &hKeyChild) ;
    if (lRes != ERROR_SUCCESS)
    {
        return lRes ;
    }

    // Enumerate all of the decendents of this child.
    FILETIME time ;
    char szBuffer[256] ;
    DWORD dwSize = 256 ;
    while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,
                        NULL, NULL, &time) == S_OK)
    {
        // Delete the decendents of this child.
        lRes = recursiveDeleteKey(hKeyChild, szBuffer) ;
        if (lRes != ERROR_SUCCESS)
        {
            // Cleanup before exiting.
            RegCloseKey(hKeyChild) ;
            return lRes;
        }
        dwSize = 256 ;
    }

    // Close the child.
    RegCloseKey(hKeyChild) ;

    // Delete this child.
    return RegDeleteKey(hKeyParent, lpszKeyChild) ;
}

//
// Create a key and set its value.
//   - This helper function was borrowed and modifed from
//     Kraig Brockschmidt's book Inside OLE.
//
BOOL setKeyAndValue(const char* szKey,
                    const char* szSubkey,
                    const char* szValue)
{
    HKEY hKey;
    char szKeyBuf[1024] ;

    // Copy keyname into buffer.
    strcpy(szKeyBuf, szKey) ;

    // Add subkey name to buffer.
    if (szSubkey != NULL)
    {
        strcat(szKeyBuf, "\\") ;
        strcat(szKeyBuf, szSubkey ) ;
    }

    // Create and open key and subkey.
    long lResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,
                                  szKeyBuf, 
                                  0, NULL, REG_OPTION_NON_VOLATILE,
                                  KEY_ALL_ACCESS, NULL, 
                                  &hKey, NULL) ;
    if (lResult != ERROR_SUCCESS)
    {
        return FALSE ;
    }

    // Set the Value.
    if (szValue != NULL)
    {
        RegSetValueEx(hKey, NULL, 0, REG_SZ, 
                      (BYTE *)szValue, 
                      strlen(szValue)+1) ;
    }

    RegCloseKey(hKey) ;
    return TRUE ;
}

在Cmpnt.dll的编译和连接后使用以下命令

regsvr32 -s Cmpnt.dll

REGSVR32.exe将调用DllRegisterServer函数完成组件的登记

参考
http://www.360doc.com/content/12/0228/09/7023119_190190971.shtml

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值