问题:为什么要使用类厂?
答案: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