您的位置:首页 > 编程语言 > C语言/C++

用c++实现com组件示例

2008-09-27 16:35 232 查看

1、 创建一个win32 dll应用类型项目工程。
2、 添加ComTest.h及ComTest.cpp文件,并在ComTest.h头文件包含Unknwn.h头文件
3、 用guid.exe生成一个接口IID及com对象类CLSID
代码如下:
//ComTest.h
#pragmaonce

#include<Unknwn.h>

EXTERN_CconstCLSIDCLSID_TestObject;
EXTERN_CconstCLSIDIID_ObjectInterface;

MIDL_INTERFACE("DE5A091A-EF80-4bd3-8AEB-CB20B879A2F1")
IObjectInterface :publicIUnknown
{
virtualvoid__stdcallTestMethod() PURE;
};
//ComTest.cpp
#include"StdAfx.h"
#include"ComTest.h"

EXTERN_CconstCLSIDCLSID_TestObject =
{0xa33e547a, 0x8a95, 0x4118, {0x86, 0xa, 0x46, 0xb2, 0x3c, 0x6d, 0x40, 0xbd}};
EXTERN_CconstCLSIDIID_ObjectInterface =
{0xde5a091a, 0xef80, 0x4bd3, {0x8a, 0xeb, 0xcb, 0x20, 0xb8, 0x79, 0xa2, 0xf1}};

4、 添加CTestObject类,这个类必须实现IObjectInterface接口,并且必须实现IUnkown接口的三个函数。
代码如下
//TestObject.h
#pragmaonce
#include"ComTest.h"

classCTestObject:publicIObjectInterface
{
public:
CTestObject(void);
public:
~CTestObject(void);

public:
HRESULT__stdcallQueryInterface( REFIIDriid,void **ppvObject);
ULONG__stdcallAddRef( void);
ULONG__stdcallRelease( void);
public:
void__stdcallTestMethod();
private:
intm_nRef;
};
//TestObject.cpp
#include"StdAfx.h"
#include"TestObject.h"
#include<iostream>
usingnamespacestd;

CTestObject::CTestObject(void)
:m_nRef(0)
{
}

CTestObject::~CTestObject(void)
{
}

HRESULTCTestObject::QueryInterface( REFIIDriid,void **ppvObject)
{
if (riid==__uuidof(IUnknown))
{
*ppvObject = (IUnknown*)this;
((IUnknown*)*ppvObject)->AddRef();
returnS_OK;
}
elseif (riid==__uuidof(IObjectInterface))
{
*ppvObject = (IObjectInterface*)this;
((IObjectInterface*)*ppvObject)->AddRef();
returnS_OK;
}
else
{
*ppvObject = NULL;
returnE_NOINTERFACE;
}
}
ULONGCTestObject::AddRef( void)
{
m_nRef++;
returnm_nRef;
}
ULONGCTestObject::Release( void)
{
m_nRef--;
if (m_nRef==0)
{
deletethis;
}
returnm_nRef;
}

voidCTestObject::TestMethod()
{
cout<<"this is my com test!"<<endl;
}

5、 必须要为com对象创建一个工厂类,该工厂类还必须实现IClassFactory接口。
当我们调用CoCreateInstance函数创建com对象的时候,com标准库会调用DllGetClassObject获取工厂对象,再由工厂对象调用其成员函数CreateInstance来创建我们需要的com对象。
代码如下:
//.h
#pragmaonce
#include<Unknwn.h>

externULONGg_LockNumber;
classCTestObjectFactory:publicIClassFactory
{
protected:
intm_nRef;
public:
CTestObjectFactory(void);
public:
~CTestObjectFactory(void);
public:
HRESULT__stdcallQueryInterface( REFIIDriid,void **ppvObject);
ULONG__stdcallAddRef( void);
ULONG__stdcallRelease( void);
public:
HRESULTSTDMETHODCALLTYPECreateInstance(IUnknown *pUnkOuter,REFIIDriid,void **ppvObject);
HRESULTSTDMETHODCALLTYPELockServer(BOOLfLock) ;
};
//.cpp
#include"StdAfx.h"

#include"ComTest.h"
#include"TestObject.h"
#include"TestObjectFactory.h"

CTestObjectFactory::CTestObjectFactory(void)
:m_nRef(0)
{
}

CTestObjectFactory::~CTestObjectFactory(void)
{
}

HRESULTCTestObjectFactory::QueryInterface( REFIIDriid,void **ppvObject)
{
if (riid==__uuidof(IUnknown))
{
*ppvObject = (IUnknown*)this;
((IUnknown*)*ppvObject)->AddRef();
returnS_OK;
}
elseif (riid==__uuidof(IClassFactory))
{
*ppvObject = (IClassFactory*)this;
((IClassFactory*)*ppvObject)->AddRef();
returnS_OK;
}
else
{
*ppvObject = NULL;
returnE_NOINTERFACE;
}
}
ULONGCTestObjectFactory::AddRef( void)
{
m_nRef++;
returnm_nRef;
}
ULONGCTestObjectFactory::Release( void)
{
m_nRef--;
if (m_nRef==0)
{
deletethis;
}
returnm_nRef;
}
HRESULTCTestObjectFactory::CreateInstance(IUnknown *pUnkOuter,REFIIDriid,void **ppvObject)
{
if (NULL != pUnkOuter)
returnCLASS_E_NOAGGREGATION;
DT(L"Enter CreateInstance...");
CTestObject *pObj=NULL;
pObj = newCTestObject();
if (pObj==NULL)
{
*ppvObject = NULL;
returnE_OUTOFMEMORY;
}
HRESULThr = pObj->QueryInterface(riid,ppvObject);
if (FAILED(hr))
{
DT(L"Failed to Create TestObj!");
deletepObj;
}
returnhr;
}
HRESULTCTestObjectFactory::LockServer(BOOLfLock)
{
if (fLock)
{
g_LockNumber++;
}
else
g_LockNumber--;
returnNOERROR;
}

6、 有了com对象类和工厂类后,我们要想办法将我们的com对象信息写到注册表中去,
一般要写入以下信息:
HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID/{A33E547A-8A95-4118-860A-46B23C6D40BD}
HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID/{A33E547A-8A95-4118-860A-46B23C6D40BD}/InprocServer32
HKEY_LOCAL_MACHINE/SOFTWARE/Classes/CLSID/{A33E547A-8A95-4118-860A-46B23C6D40BD}/ProgID
HKEY_LOCAL_MACHINE/SOFTWARE/Classes/TestCom.Object
HKEY_LOCAL_MACHINE/SOFTWARE/Classes/TestCom.Object/CLSID

7、 要添加导出文件,添加下面四个函数的实现:
LIBRARY "Component"

EXPORTS
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
DllCanUnloadNow PRIVATE

有关这四个函数的实现,参考如下代码:
// Registry.cpp

#include"StdAfx.h"

#include<objbase.h>
#include<assert.h>
#include"Registry.h"

////////////////////////////////////////////////////////
//
// Internal helper functions prototypes
//
// - These helper functions were borrowed and modifed from
// Dale Rogerson's book Inside COM.

// Set the given key and its value.
BOOLSetKeyAndValue(constTCHAR* pszPath,
constTCHAR* szSubkey,
constTCHAR* szValue) ;

// Convert a CLSID into a char string.
voidCLSIDtoString(constCLSID& clsid,
TCHAR* szCLSID,
intlength) ;

// Delete szKeyChild and all of its descendents.
LONGDeleteKey(HKEYhKeyParent, constTCHAR* szKeyString) ;

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

// Size of a CLSID as a string
constintCLSID_STRING_SIZE = 39 ;

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

//
// Register the component in the registry.
//
HRESULTRegisterServer(constCLSID& clsid, // Class ID
constTCHAR *szFileName, // DLL module handle
constTCHAR* szProgID, // IDs
constTCHAR* szDescription, // Description String
constTCHAR* szVerIndProgID) // optional

{
DT(szFileName);
DT(szProgID);
// Convert the CLSID into a char.
TCHARszCLSID[CLSID_STRING_SIZE] ;
CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ;
//StringFromCLSID(clsid,szCLSID);
// Build the key CLSID//{...}
TCHARszKey[64] ;
lstrcpy(szKey, L"CLSID//") ;
lstrcat(szKey, szCLSID) ;
DT(szKey);
// Add the CLSID to the registry.
SetKeyAndValue(szKey, NULL, szDescription) ;

// Add the server filename subkey under the CLSID key.
SetKeyAndValue(szKey, L"InprocServer32", szFileName) ;

// Add the ProgID subkey under the CLSID key.
if (szProgID != NULL) {
SetKeyAndValue(szKey, L"ProgID", szProgID) ;
SetKeyAndValue(szProgID, L"CLSID", szCLSID) ;
}

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

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

// Add the versioned ProgID subkey under HKEY_CLASSES_ROOT.
SetKeyAndValue(szProgID, NULL, szDescription) ;
SetKeyAndValue(szProgID, L"CLSID", szCLSID) ;
}

returnS_OK ;
}

//
// Remove the component from the registry.
//
HRESULTUnregisterServer(constCLSID& clsid, // Class ID
constTCHAR* szProgID, // IDs
constTCHAR* szVerIndProgID) // Programmatic
{
// Convert the CLSID into a char.
TCHARszCLSID[CLSID_STRING_SIZE] ;
CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ;
//StringFromCLSID(clsid,szCLSID);
// Build the key CLSID//{...}
TCHARszKey[64] ;
lstrcpy(szKey, L"CLSID//") ;
lstrcat(szKey, szCLSID) ;

// Delete the CLSID Key - CLSID/{...}
LONGlResult = DeleteKey(HKEY_CLASSES_ROOT, szKey) ;

// Delete the version-independent ProgID Key.
if (szVerIndProgID != NULL)
lResult = DeleteKey(HKEY_CLASSES_ROOT, szVerIndProgID) ;

// Delete the ProgID key.
if (szProgID != NULL)
lResult = DeleteKey(HKEY_CLASSES_ROOT, szProgID) ;

returnS_OK ;
}

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

// Convert a CLSID to a char string.
voidCLSIDtoString(constCLSID& clsid,
TCHAR* szCLSID,
intlength)
{
assert(length >= CLSID_STRING_SIZE) ;
// Get CLSID
LPOLESTRwszCLSID = NULL ;
HRESULThr = StringFromCLSID(clsid, &wszCLSID) ;
assert(SUCCEEDED(hr)) ;
lstrcpy(szCLSID,wszCLSID);
DT(szCLSID);

// Free memory.
CoTaskMemFree(wszCLSID) ;
}

//
// Delete a key and all of its descendents.
//
LONGDeleteKey(HKEYhKeyParent, // Parent of key to delete
constTCHAR* lpszKeyChild) // Key to delete
{
// Open the child.
HKEYhKeyChild ;
LONGlRes = RegOpenKeyEx(hKeyParent, lpszKeyChild, 0,
KEY_ALL_ACCESS, &hKeyChild) ;
if (lRes != ERROR_SUCCESS)
{
returnlRes ;
}

// Enumerate all of the decendents of this child.
FILETIMEtime ;
TCHARszBuffer[256] ;
DWORDdwSize = 256 ;
while (RegEnumKeyEx(hKeyChild, 0, szBuffer, &dwSize, NULL,
NULL, NULL, &time) == S_OK)
{
// Delete the decendents of this child.
lRes = DeleteKey(hKeyChild, szBuffer) ;
if (lRes != ERROR_SUCCESS)
{
// Cleanup before exiting.
RegCloseKey(hKeyChild) ;
returnlRes;
}
dwSize = 256 ;
}

// Close the child.
RegCloseKey(hKeyChild) ;

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

// Create a key and set its value.
//
BOOLSetKeyAndValue(constTCHAR* szKey,
constTCHAR* szSubkey,
constTCHAR* szValue)
{
HKEYhKey;
TCHARszKeyBuf[1024] ;

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

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

// Create and open key and subkey.
longlResult = RegCreateKeyEx(HKEY_CLASSES_ROOT ,
szKeyBuf,
0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL,
&hKey, NULL) ;
if (lResult != ERROR_SUCCESS)
{
DT(L"SetKeyAndValue Failed!");
returnFALSE ;
}

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

RegCloseKey(hKey) ;
DT(L"SetKeyAndValue Succeed!");
returnTRUE ;
}

//componet.com

#include"stdafx.h"

#include"Registry.h"
//#include "ComTest.h"
#ifdef_MANAGED
#pragma managed(push, off)
#endif
HMODULEg_hModule = NULL;
ULONGg_LockNumber = 0;

EXTERN_CconstCLSIDCLSID_TestObject;
EXTERN_CconstCLSIDIID_ObjectInterface;
//class CTestObjectFactory;
#include"TestObjectFactory.h"
STDAPIDllGetClassObject(constCLSID& clsid, constIID& iid, void **ppv)
{
DT(L"DllGetClassObject...");
if (clsid == CLSID_TestObject ) {

CTestObjectFactory *pFactory = newCTestObjectFactory;

if (pFactory == NULL) {
returnE_OUTOFMEMORY ;
}

HRESULTresult = pFactory->QueryInterface(iid, ppv);

returnresult;
} else {
returnCLASS_E_CLASSNOTAVAILABLE;
}
}

STDAPIDllCanUnloadNow(void)
{
if (g_LockNumber == 0)
returnS_OK;
else
returnS_FALSE;
}
STDAPIDllRegisterServer()
{
TCHARszFileName[MAX_PATH];
::GetModuleFileName((HMODULE)g_hModule,szFileName,sizeof(szFileName));
DT(szFileName);
returnRegisterServer(CLSID_TestObject,szFileName,L"TestCom.Object",L"Test Componet",NULL);

}

STDAPIDllUnregisterServer()
{
//return AMovieDllRegisterServer2(FALSE);
returnUnregisterServer(CLSID_TestObject,L"TestCom.Object",NULL);

}
BOOLAPIENTRYDllMain( HMODULEhModule,
DWORDul_reason_for_call,
LPVOIDlpReserved
)
{
if (!g_hModule)
{
g_hModule = hModule;
}
returnTRUE;
}

#ifdef_MANAGED
#pragma managed(pop)
#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: