天天看點

一個完整的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;  
}  
           

終于貼完了。一個完整的示例,親測可以哈!一起學習。

繼續閱讀