一个完整的COM 示范Demo(C++语言描述)
一个完整的COM 示例Demo(C++语言描述)
对于初学com的,一个完整的示例还是挺麻烦的,最近笔者也在学习,通过自己的摸索了解了下基本原理。在此将一个简单string的示例一步一步的详解。
源代码下载
1.创建工程
首先使用vs2010(笔者使用的vs2010就拿此来讲)创建一个工程。选择空项目,笔者命名为MyCom。
2.创建接口类
#ifndef IString_h__ #define IString_h__ #include <Windows.h> #include <Unknwn.h> #include <ObjBase.h> extern "C" const GUID IID_IString; class IString : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE SetString(char*) = 0; virtual HRESULT STDMETHODCALLTYPE GetString(char*, long) = 0; virtual HRESULT STDMETHODCALLTYPE AboutMessage() = 0; }; #endif // IString_h__
3.创建组件类
#ifndef String_h__ #define String_h__ #include "IString.h" class String :public IString { public: String(); ~String(); public: //IUkown Function HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,LPVOID *ppv); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); //IString Function HRESULT STDMETHODCALLTYPE SetString(char* chBuf); HRESULT STDMETHODCALLTYPE GetString(char* chBuf, long cLength); HRESULT STDMETHODCALLTYPE AboutMessage(); protected: ULONG m_Ref; char buffer[80]; }; #endif // String_h__
3.定义类厂
#ifndef CFactory_h__ #define CFactory_h__ #include <Unknwn.h> class CFactory : public IClassFactory { public: CFactory(); ~CFactory(); //IUnknown members HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void **ppv); ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); //IClassFactory members HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *, const IID& iid, void **ppv); HRESULT STDMETHODCALLTYPE LockServer(BOOL bIsLocck); protected: ULONG m_Ref; }; #endif // CFactory_h__
4.类厂实现
#include "CFactory.h" #include "String.h" extern ULONG g_LockNumber; extern ULONG g_StringNumber; CFactory::CFactory() { m_Ref = 0; } CFactory::~CFactory(){} HRESULT CFactory::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 CFactory::AddRef() { m_Ref++; return m_Ref; } ULONG CFactory::Release() { m_Ref--; if (m_Ref == 0) { delete this; return 0; } return m_Ref; } HRESULT CFactory::CreateInstance(IUnknown *pUnknownOuter, const IID& iid, void **ppv) { HRESULT hr; String *pObj; *ppv = NULL; hr = E_OUTOFMEMORY; if(NULL != pUnknownOuter) return CLASS_E_NOAGGREGATION; pObj = new String(); if(NULL == pObj) return hr; hr = pObj->QueryInterface(iid,ppv); if (hr != S_OK) { g_StringNumber--; delete pObj; } return S_OK; } HRESULT CFactory::LockServer(BOOL bIsLock) { if (bIsLock) g_LockNumber++; else g_LockNumber--; return S_OK; }
5、引出函数def文件
LIBRARY "MyCom" EXPORTS ; Explicit exports can go here DllGetClassObject PRIVATE DllRegisterServer PRIVATE DllUnregisterServer PRIVATE DllCanUnloadNow PRIVATE
6.组件注册
#ifndef __Registry_H__ #define __Registry_H__ // // Registry.h // - Helper functions registering and unregistering a component. // // - These helper functions were borrowed and modifed from // Dale Rogerson's book Inside COM. // This function will register a component in the Registry. // DllRegisterServer function should call this function. HRESULT RegisterServer(const CLSID& clsid, const char *szFileName, const char* szProgID, const char* szDescription, const char* szVerIndProgID) ; // This function will unregister a component. Components // DllUnregisterServer function should call this function. HRESULT UnregisterServer(const CLSID& clsid, const char* szProgID, const char* szVerIndProgID) ; #endif
7.组件注册实现
// // Registry.cpp // #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. BOOL SetKeyAndValue(const char* pszPath, const char* szSubkey, const char* szValue) ; // Convert a CLSID into a char string. void CLSIDtoString(const CLSID& clsid, char* szCLSID, int length) ; // Delete szKeyChild and all of its descendents. LONG DeleteKey(HKEY hKeyParent, const char* szKeyString) ; //////////////////////////////////////////////////////// // // Constants // // Size of a CLSID as a string const int CLSID_STRING_SIZE = 39 ; ///////////////////////////////////////////////////////// // // Public function implementation // // // Register the component in the registry. // HRESULT RegisterServer(const CLSID& clsid, // Class ID const char *szFileName, // DLL module handle const char* szProgID, // IDs const char* szDescription, // Description String const char* szVerIndProgID) // optional { // Convert the CLSID into a char. char szCLSID[CLSID_STRING_SIZE] ; CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ; // Build the key CLSID\\{...} char szKey[64] ; strcpy_s(szKey, "CLSID\\") ; strcat_s(szKey, szCLSID) ; // Add the CLSID to the registry. SetKeyAndValue(szKey, NULL, szDescription) ; // Add the server filename subkey under the CLSID key. SetKeyAndValue(szKey, "InprocServer32", szFileName) ; // Add the ProgID subkey under the CLSID key. if (szProgID != NULL) { SetKeyAndValue(szKey, "ProgID", szProgID) ; SetKeyAndValue(szProgID, "CLSID", szCLSID) ; } if (szVerIndProgID) { // 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, szDescription) ; SetKeyAndValue(szVerIndProgID, "CLSID", szCLSID) ; SetKeyAndValue(szVerIndProgID, "CurVer", szProgID) ; // Add the versioned ProgID subkey under HKEY_CLASSES_ROOT. SetKeyAndValue(szProgID, NULL, szDescription) ; SetKeyAndValue(szProgID, "CLSID", szCLSID) ; } return S_OK ; } // // Remove the component from the registry. // HRESULT UnregisterServer(const CLSID& clsid, // Class ID const char* szProgID, // IDs const char* szVerIndProgID) // Programmatic { // Convert the CLSID into a char. char szCLSID[CLSID_STRING_SIZE] ; CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ; // Build the key CLSID\\{...} char szKey[64] ; strcpy_s(szKey, "CLSID\\") ; strcat_s(szKey, szCLSID) ; // Delete the CLSID Key - CLSID\{...} LONG lResult = 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) ; return S_OK ; } /////////////////////////////////////////////////////////// // // Internal helper functions // // Convert a CLSID to a char string. void CLSIDtoString(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 DeleteKey(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 = DeleteKey(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. // 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 ; }
8.引出函数及组件函数实现
#include "CFactory.h" #include "Registry.h" #include "String.h" ULONG g_LockNumber = 0; ULONG g_StringNumber = 0; // {913AAE18-1D57-4868-AF2F-B47D32163E8F} extern "C" const GUID CLSID_String = { 0x913aae18, 0x1d57, 0x4868, { 0xaf, 0x2f, 0xb4, 0x7d, 0x32, 0x16, 0x3e, 0x8f } }; // {416DC65F-48E2-436a-BA34-FC00AC3DA598} extern "C" const GUID IID_IString = { 0x416dc65f, 0x48e2, 0x436a, { 0xba, 0x34, 0xfc, 0x0, 0xac, 0x3d, 0xa5, 0x98 } }; HMODULE g_hModule=0; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { g_hModule = hModule; return TRUE; } extern "C" HRESULT STDMETHODCALLTYPE DllCanUnloadNow() { if((g_LockNumber == 0)&&(g_StringNumber)) return S_OK; else return S_FALSE; } extern "C" HRESULT STDMETHODCALLTYPE DllRegisterServer() { char szModule[1024]; DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, szModule, 1024); if (dwResult == 0) return -1; return RegisterServer(CLSID_String, szModule, "STRING.Object", "MyCom String Component", NULL); } extern "C" HRESULT STDMETHODCALLTYPE DllUnregisterServer() { return UnregisterServer(CLSID_String, "STRING.Object",NULL); } extern "C" HRESULT STDMETHODCALLTYPE DllGetClassObject(__in REFCLSID rclsid, __in REFIID riid, __deref_out LPVOID FAR* ppv) { if (rclsid == CLSID_String) { CFactory *pFactory = new CFactory(); if(pFactory == NULL) return E_OUTOFMEMORY; HRESULT hr = pFactory->QueryInterface(riid,ppv); return hr; }else { return CLASS_E_CLASSNOTAVAILABLE; } } HRESULT String::QueryInterface(REFIID iid,LPVOID *ppv) { if (iid == IID_IUnknown) { *ppv = (IUnknown*)this; ((IUnknown*)(*ppv))->AddRef(); }else if(iid == IID_IString) { *ppv = (IClassFactory*)this; ((IClassFactory*)(*ppv))->AddRef(); }else { *ppv = NULL; return E_NOINTERFACE; } return S_OK; } String::String() { m_Ref = 0; } String::~String() { } ULONG String::AddRef() { m_Ref++; return m_Ref; } ULONG String::Release() { m_Ref--; if (m_Ref == 0) { delete this; return 0; } return m_Ref; } HRESULT String::GetString(char*chBuf, long cLength) { long i; // 拷贝IExample的buffer到传入的buffer中 i = lstrlen(buffer); --cLength; if (i > cLength) i = cLength; CopyMemory(chBuf, buffer, i); chBuf[i] = 0; return(0); } HRESULT String::SetString(char* chBuf) { DWORD i; // 把传入的str拷贝到IExample的buffer中 i = lstrlen(chBuf); if (i > 79) i = 79; CopyMemory(buffer, chBuf, i); buffer[i] = 0; return(0); } HRESULT String::AboutMessage() { MessageBox(NULL,"hello, i am a message box!","Message",MB_OK); return S_OK; }
9.测试文件编写(记得手工注册下dll)
#include "IString.h" #include <Windows.h> #include <iostream> using namespace std; // {913AAE18-1D57-4868-AF2F-B47D32163E8F} extern "C" const GUID CLSID_String = { 0x913aae18, 0x1d57, 0x4868, { 0xaf, 0x2f, 0xb4, 0x7d, 0x32, 0x16, 0x3e, 0x8f } }; // {416DC65F-48E2-436a-BA34-FC00AC3DA598} extern "C" const GUID IID_IString = { 0x416dc65f, 0x48e2, 0x436a, { 0xba, 0x34, 0xfc, 0x0, 0xac, 0x3d, 0xa5, 0x98 } }; int main() { IString *pIStr; IUnknown *pIUk = NULL; HRESULT hr; char chGetChar[80]; CLSID rclsid; if(CoInitialize(NULL) != S_OK) { cout<<"initialize Failed"<<endl; return -1; } hr = CLSIDFromProgID(OLESTR("STRING.Object"),&rclsid); if (hr != S_OK) { cout<<"Can't find the dictionary CLSID!"<<endl; return -2; } hr = CoCreateInstance(rclsid,NULL,CLSCTX_INPROC_SERVER,IID_IUnknown,(LPVOID*)&pIUk); if (hr != S_OK) { cout<<"Create object failed!"<<endl; return -2; } hr = pIUk->QueryInterface(IID_IString,(LPVOID*)&pIStr); if (hr != S_OK) { pIUk->Release(); printf("QueryInterface IString failed!\n"); return -3; } pIStr->SetString("wqlgregergerg"); pIStr->GetString(chGetChar,sizeof(chGetChar)); cout<<chGetChar<<endl; pIStr->AboutMessage(); CoUninitialize(); return 0; }终于贴完了。一个完整的示例,亲测可以哈!一起学习。
- 1楼wqliceman昨天 11:01
- 支持