For beginner COM, a complete example is still quite troublesome. Recently I have been studying and learned the basic principles through my own exploration. Here we will explain a simple string example step by step.
Source code download
1. Create a project
First, use vs2010 to create a project. Select an empty project and name it mycom.
2. Create an Interface Class
#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. Create component classes
#ifndef String_h__#define String_h__#include "IString.h"class String :public IString{public:String();~String();public://IUkown FunctionHRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid,LPVOID *ppv);ULONG STDMETHODCALLTYPE AddRef();ULONG STDMETHODCALLTYPE Release();//IString FunctionHRESULT 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. Define a factory
#ifndef CFactory_h__#define CFactory_h__#include <Unknwn.h>class CFactory : public IClassFactory{public:CFactory();~CFactory();//IUnknown membersHRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void **ppv);ULONGSTDMETHODCALLTYPE AddRef();ULONGSTDMETHODCALLTYPE Release();//IClassFactory membersHRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *, const IID& iid, void **ppv);HRESULT STDMETHODCALLTYPE LockServer(BOOL bIsLocck);protected:ULONG m_Ref;};#endif // CFactory_h__
4. factory implementation
#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++;elseg_LockNumber--;return S_OK;}
5. Export the function def File
LIBRARY "MyCom"EXPORTS ; Explicit exports can go hereDllGetClassObject PRIVATEDllRegisterServer PRIVATEDllUnregisterServer PRIVATEDllCanUnloadNow PRIVATE
6. Component Registration
#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. Component registration implementation
//// 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 stringconst 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. Introduction function and component function implementation
# Include "cfactory. H "# include" registry. H "# include" string. H "ulong g_locknumber = 0; ulong g_stringnumber = 0; // {struct} extern" C "const guid clsid_string = {0x913aae18, 0x1d57, 0x4868, {0xaf, 0x2f, 0xb4, 0x7d, 0x32, 0x16, 0x3e, 0x8f }}; // {struct} 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, DWORD ul_reason_for_call, lpvoid lpreserved) {g_hmodule = hmodule; return true ;} extern "C" hresult stdmethodcalltype encode () {If (g_locknumber = 0) & (g_stringnumber) return s_ OK; elsereturn s_false;} extern "C" hresult stdmethodcalltype dllregisterserver () {char szmodule [1024]; DWORD dwresult =: getmodulefil Ename (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 * GMM) {If (rclsid = clsid_string) {cfactory * pfactory = new cfactory (); If (pfactory = NULL) return e_outofmemory; hresult hR = pfactory-> QueryInterface (riid, 1); Return hr;} else {return class_e_classnotavailable;} hresult string: QueryInterface (refiid IID, lpvoid * bp) {If (IID = iid_iunknown) {* GMM = (iunknown *) This; (iunknown *) (* bp))-> addref ();} else if (IID = iid_istring) {* GMM = (iclassfactory *) This; (Iclassfactory *) (* GMM)-> addref ();} else {* NPV = 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; // copy the buffer of iexample to the input 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; // Copy the passed STR to the buffer of iexample. 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. Write the test file (remember to manually register the 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;}
Finally, the post is complete. A complete example! Learn together.