The entire process of creating COM components (C ++)

Source: Internet
Author: User
1. Create an Interface

typedef  struct  InterfaceInterface ISimpleMsgBox : public IUnknown{    // IUnknown    STDMETHOD_(ULONG, AddRef)() PURE;    STDMETHOD_(ULONG, Release)() PURE;    STDMETHOD(QueryInterface)(REFIID riid, void** ppv) PURE;    // ISimpleMsgBox    STDMETHOD(DoSimpleMsgBox)(HWND hwndParent, BSTR bsMessageText) PURE;};

Alternative solution:Using the IDL file definition interface, it will generate the relevant header file, but the readability is very poor

2. Declare a C ++ class to implement this interface

class CSimpleMsgBoxImpl : public ISimpleMsgBox  {public:    CSimpleMsgBoxImpl();    virtual ~CSimpleMsgBoxImpl();    // IUnknown    STDMETHOD_(ULONG, AddRef)();    STDMETHOD_(ULONG, Release)();    STDMETHOD(QueryInterface)(REFIID riid, void** ppv);    // ISimpleMsgBox    STDMETHOD(DoSimpleMsgBox)(HWND hwndParent, BSTR bsMessageText);protected:    ULONG m_uRefCount;};

Implementation part. only focus on the QueryInterface and dosimplemsgbox sections.

STDMETHODIMP CSimpleMsgBoxImpl::QueryInterface ( REFIID riid, void** ppv ){HRESULT hrRet = S_OK;    TRACE(">>> SimpleMsgBoxSvr: In CSimpleMsgBoxImpl::QueryInterface()\n" );    // Check that ppv really points to a void*.    if ( IsBadWritePtr ( ppv, sizeof(void*) ))        return E_POINTER;    // Standard QI initialization - set *ppv to NULL.    *ppv = NULL;    // If the client is requesting an interface we support, set *ppv.    if ( InlineIsEqualGUID ( riid, IID_IUnknown ))        {        *ppv = (IUnknown*) this;        TRACE(">>> SimpleMsgBoxSvr: Client QIed for IUnknown\n" );        }    else if ( InlineIsEqualGUID ( riid, __uuidof(ISimpleMsgBox) ))        {        *ppv = (ISimpleMsgBox*) this;        TRACE(">>> SimpleMsgBoxSvr: Client QIed for ISimpleMsgBox\n" );        }    else        {        hrRet = E_NOINTERFACE;        TRACE(">>> SimpleMsgBoxSvr: Client QIed for unsupported interface\n" );        }    // If we're returning an interface pointer, AddRef() it.    if ( S_OK == hrRet )        {        ((IUnknown*) *ppv)->AddRef();        }    return hrRet;}//////////////////////////////////////////////////////////////////////// ISimpleMsgBox methodsSTDMETHODIMP CSimpleMsgBoxImpl::DoSimpleMsgBox ( HWND hwndParent, BSTR bsMessageText ){_bstr_t bsMsg = bsMessageText;LPCTSTR szMsg = (TCHAR*) bsMsg;         // Use _bstr_t to convert the string to ANSI if necessary.    TRACE(">>> SimpleMsgBoxSvr: In CSimpleMsgBoxImpl::DoSimpleMsgBox()\n" );    MessageBox ( hwndParent, szMsg, _T("Simple Message Box"), MB_OK );    return S_OK;}
3. Specify a guid for each interface and class

Use VC ++ Extension Method

struct __declspec(uuid("{7D51904D-1645-4a8c-BDE0-0F4A44FC38C4}")) ISimpleMsgBox;class  __declspec(uuid("{7D51904E-1645-4a8c-BDE0-0F4A44FC38C4}")) CSimpleMsgBoxImpl;
In this way, you can use the _ uuidof keyword to introduce the VC ++ extension syntax.

 

class Demo{};class __declspec(uuid("B372C9F6-1959-4650-960D-73F20CD479BA")) Demo; int main( void ){    CLSID clsid = __uuidof(Demo); }

 

4. Create a category Factory (required)

Each class must be equipped with a class factory. Follow the createinstance and lockserver methods.
The cocreateinstance method depends on this interface in its internal life cycle.

//////////////////////////////////////////////////////////////////////// IClassFactory methodsSTDMETHODIMP CSimpleMsgBoxClassFactory::CreateInstance ( IUnknown* pUnkOuter,                                                         REFIID    riid,                                                         void**    ppv ){HRESULT hrRet;CSimpleMsgBoxImpl* pMsgbox;    TRACE(">>> SimpleMsgBoxSvr: In CSimpleMsgBoxClassFactory::CreateInstance()\n" );    // We don't support aggregation, so pUnkOuter must be NULL.    if ( NULL != pUnkOuter )        return CLASS_E_NOAGGREGATION;    // Check that ppv really points to a void*.    if ( IsBadWritePtr ( ppv, sizeof(void*) ))        return E_POINTER;    *ppv = NULL;    // Create a new COM object!    pMsgbox = new CSimpleMsgBoxImpl;    if ( NULL == pMsgbox )        return E_OUTOFMEMORY;    // QI the object for the interface the client is requesting.    hrRet = pMsgbox->QueryInterface ( riid, ppv );    // If the QI failed, delete the COM object since the client isn't able    // to use it (the client doesn't have any interface pointers on the object).    if ( FAILED(hrRet) )        delete pMsgbox;    return hrRet;}STDMETHODIMP CSimpleMsgBoxClassFactory::LockServer ( BOOL fLock ){    // Increase/decrease the DLL ref count, according to the fLock param.    fLock ? g_uDllLockCount++ : g_uDllLockCount--;    TRACE(">>> SimpleMsgBoxSvr: In CSimpleMsgBoxClassFactory::LockServer(), new DLL ref count = %d\n", g_uDllLockCount );        return S_OK;}

 

5. Register COM components (manually register)

Everything is ready. Now we need to write its information into the registry,

1. Implement the dllregisterserver and dllunregisterserver methods, and declare the methods as stdapi, indicating they belong to the export function.

// DllRegisterServer() creates the registy entries that tells COM where our // server is located and its threading model.STDAPI DllRegisterServer(){HKEY  hCLSIDKey = NULL, hInProcSvrKey = NULL;LONG  lRet;TCHAR szModulePath [MAX_PATH];TCHAR szClassDescription[] = _T("SimpleMsgBox class");TCHAR szThreadingModel[]   = _T("Apartment");__try    {    // Create a key under CLSID for our COM server.    lRet = RegCreateKeyEx ( HKEY_CLASSES_ROOT, _T("CLSID\\{7D51904E-1645-4a8c-BDE0-0F4A44FC38C4}"),                            0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE | KEY_CREATE_SUB_KEY,                            NULL, &hCLSIDKey, NULL );        if ( ERROR_SUCCESS != lRet )         return HRESULT_FROM_WIN32(lRet);    // The default value of the key is a human-readable description of the coclass.    lRet = RegSetValueEx ( hCLSIDKey, NULL, 0, REG_SZ, (const BYTE*) szClassDescription,                           sizeof(szClassDescription) );    if ( ERROR_SUCCESS != lRet )        return HRESULT_FROM_WIN32(lRet);        // Create the InProcServer32 key, which holds info about our coclass.    lRet = RegCreateKeyEx ( hCLSIDKey, _T("InProcServer32"), 0, NULL, REG_OPTION_NON_VOLATILE,                            KEY_SET_VALUE, NULL, &hInProcSvrKey, NULL );    if ( ERROR_SUCCESS != lRet )        return HRESULT_FROM_WIN32(lRet);    // The default value of the InProcServer32 key holds the full path to our DLL.    GetModuleFileName ( g_hinstThisDll, szModulePath, MAX_PATH );    lRet = RegSetValueEx ( hInProcSvrKey, NULL, 0, REG_SZ, (const BYTE*) szModulePath,                            sizeof(TCHAR) * (lstrlen(szModulePath)+1) );    if ( ERROR_SUCCESS != lRet )        return HRESULT_FROM_WIN32(lRet);    // The ThreadingModel value tells COM how it should handle threads in our DLL.    // The concept of apartments is beyond the scope of this article, but for    // simple, single-threaded DLLs, use Apartment.    lRet = RegSetValueEx ( hInProcSvrKey, _T("ThreadingModel"), 0, REG_SZ,                           (const BYTE*) szThreadingModel,                            sizeof(szThreadingModel) );    if ( ERROR_SUCCESS != lRet )        return HRESULT_FROM_WIN32(lRet);    }   __finally    {    if ( NULL != hCLSIDKey )        RegCloseKey ( hCLSIDKey );    if ( NULL != hInProcSvrKey )        RegCloseKey ( hInProcSvrKey );    }    return S_OK;}// DllUnregisterServer() deleted the registy entries that DllRegisterServer() created.STDAPI DllUnregisterServer(){    // Delete our registry entries.  Note that you must delete from the deepest    // key and work upwards, because on NT/2K, RegDeleteKey() doesn't delete     // keys that have subkeys on NT/2K.    RegDeleteKey ( HKEY_CLASSES_ROOT, _T("CLSID\\{7D51904E-1645-4a8c-BDE0-0F4A44FC38C4}\\InProcServer32") );    RegDeleteKey ( HKEY_CLASSES_ROOT, _T("CLSID\\{7D51904E-1645-4a8c-BDE0-0F4A44FC38C4}") );    return S_OK;}

 

2. Define the def File

EXPORTS    DllRegisterServer   PRIVATE    DllUnregisterServer PRIVATE    DllGetClassObject   PRIVATE    DllCanUnloadNow     PRIVATE

 

3. Use the regsvr32 command after compilation to register the DLL component.

Before calling this COM component, you must use the CMD command to register it. It is very important that the dllregisterserver will become the entry point.,

 

6. Write dllgetclassobject

Only the global function dllgetclassobject can be used to create a class factory. This method is called by the COM class library and a class factory is returned Based on the CLSID (a DLL may have multiple com classes)

Lifecycle (important ):

Cocreateinstance-> cogetclassobject-> dllgetclassobject-> iclassfactory-> createinstance

STDAPI DllGetClassObject ( REFCLSID rclsid, REFIID riid, void** ppv ){HRESULT hrRet;CSimpleMsgBoxClassFactory* pFactory;    TRACE(">>> SimpleMsgBoxSvr: In DllGetClassObject()\n");    // Check that the client is asking for the CSimpleMsgBoxImpl factory.    if ( !InlineIsEqualGUID ( rclsid, __uuidof(CSimpleMsgBoxImpl) ))        return CLASS_E_CLASSNOTAVAILABLE;    // Check that ppv really points to a void*.    if ( IsBadWritePtr ( ppv, sizeof(void*) ))        return E_POINTER;    *ppv = NULL;    // Construct a new class factory object.    pFactory = new CSimpleMsgBoxClassFactory;    if ( NULL == pFactory )        return E_OUTOFMEMORY;    // AddRef() the factory since we're using it.    pFactory->AddRef();    // QI() the factory for the interface the client wants.    hrRet = pFactory->QueryInterface ( riid, ppv );        // We're done with the factory, so Release() it.    pFactory->Release();    return hrRet;}
7. Call the COM Component
void DoMsgBoxTest(HWND hMainWnd){ISimpleMsgBox* pIMsgBox;HRESULT hr;    hr = CoCreateInstance ( __uuidof(CSimpleMsgBoxImpl), NULL, CLSCTX_INPROC_SERVER,                            __uuidof(ISimpleMsgBox), (void**) &pIMsgBox );    if ( FAILED(hr) )        return;    pIMsgBox->DoSimpleMsgBox ( hMainWnd, _bstr_t("Hello COM!") );    pIMsgBox->Release();}

The preceding steps cannot be omitted. It can be seen that creating a COM component is a troublesome process and is prone to errors.

Or a common class factory

HRESULT hr;IClassFactory *pc=NULL;hr=::CoGetClassObject(__uuidof(CSimpleMsgBoxImpl), CLSCTX_INPROC_SERVER,NULL,     IID_IClassFactory, (void**) &pc );

 

 

 

 

 

 

 

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.