用c++实现com组件示例

 

1、 创建一个win32  dll应用类型项目工程。

2、  添加ComTest.hComTest.cpp文件,并在ComTest.h头文件包含Unknwn.h头文件

3、  guid.exe生成一个接口IID及com对象类CLSID

代码如下:

//ComTest.h

#pragma once

 

#include <Unknwn.h>

 

EXTERN_C const CLSID CLSID_TestObject;

EXTERN_C const CLSID IID_ObjectInterface;

 

MIDL_INTERFACE("DE5A091A-EF80-4bd3-8AEB-CB20B879A2F1")

IObjectInterface :public IUnknown

{

   virtual void __stdcall TestMethod() PURE;

};

//ComTest.cpp

#include "StdAfx.h"

#include "ComTest.h"

 

 

EXTERN_C const CLSID CLSID_TestObject  =

{0xa33e547a, 0x8a95, 0x4118, {0x86, 0xa, 0x46, 0xb2, 0x3c, 0x6d, 0x40, 0xbd}};

EXTERN_C const CLSID IID_ObjectInterface  =

{0xde5a091a, 0xef80, 0x4bd3, {0x8a, 0xeb, 0xcb, 0x20, 0xb8, 0x79, 0xa2, 0xf1}};

 

 

 

4、  添加CTestObject类,这个类必须实现IObjectInterface接口,并且必须实现IUnkown接口的三个函数。

代码如下

//TestObject.h

#pragma once

#include "ComTest.h"

 

class CTestObject:public IObjectInterface

{

public:

CTestObject(void);

public:

~CTestObject(void);

 

public:

HRESULT __stdcall QueryInterface( REFIID riid,void **ppvObject);

ULONG   __stdcall AddRef( void);

ULONG   __stdcall Release( void);

public:

void   __stdcall TestMethod();

private:

int m_nRef;

};

 //TestObject.cpp

#include "StdAfx.h"

#include "TestObject.h"

#include <iostream>

using namespace std;

 

CTestObject::CTestObject(void)

:m_nRef(0)

{

}

 

CTestObject::~CTestObject(void)

{

}

 

HRESULT  CTestObject::QueryInterface( REFIID riid,void **ppvObject)

{

  if (riid==__uuidof(IUnknown))

  {

     *ppvObject = (IUnknown*)this;

     ((IUnknown*)*ppvObject)->AddRef();

     return S_OK;

  }

  else if (riid==__uuidof(IObjectInterface))

  {

     *ppvObject = (IObjectInterface*)this;

     ((IObjectInterface*)*ppvObject)->AddRef();

     return S_OK;

  }

  else

  {

     *ppvObject = NULL;

     return E_NOINTERFACE;

  }

}

ULONG    CTestObject::AddRef( void)

{

  m_nRef++;

  return m_nRef;

}

ULONG    CTestObject::Release( void)

{

  m_nRef--;

  if (m_nRef==0)

  {

     delete this;

  }

  return m_nRef;

}

 

void CTestObject::TestMethod()

{

  cout<<"this is my com test!"<<endl;

}

 

5、 必须要为com对象创建一个工厂类,该工厂类还必须实现IClassFactory接口。

当我们调用CoCreateInstance函数创建com对象的时候,com标准库会调用DllGetClassObject获取工厂对象,再由工厂对象调用其成员函数CreateInstance来创建我们需要的com对象。

代码如下:

  //.h

#pragma once

#include <Unknwn.h>

 

extern ULONG    g_LockNumber;

class CTestObjectFactory:public IClassFactory

{

protected:

  int m_nRef;

public:

  CTestObjectFactory(void);

public:

  ~CTestObjectFactory(void);

public:

  HRESULT __stdcall QueryInterface( REFIID riid,void **ppvObject);

  ULONG   __stdcall AddRef( void);

  ULONG   __stdcall Release( void);

public:

  HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter,REFIID riid,void **ppvObject);

  HRESULT STDMETHODCALLTYPE LockServer(BOOL fLock) ;

};

//.cpp

#include "StdAfx.h"

 

#include "ComTest.h"

#include "TestObject.h"

#include "TestObjectFactory.h"

 

CTestObjectFactory::CTestObjectFactory(void)

:m_nRef(0)

{

}

 

CTestObjectFactory::~CTestObjectFactory(void)

{

}

 

HRESULT  CTestObjectFactory::QueryInterface( REFIID riid,void **ppvObject)

{

   if (riid==__uuidof(IUnknown))

   {

      *ppvObject = (IUnknown*)this;

      ((IUnknown*)*ppvObject)->AddRef();

      return S_OK;

   }

   else if (riid==__uuidof(IClassFactory))

   {

      *ppvObject = (IClassFactory*)this;

      ((IClassFactory*)*ppvObject)->AddRef();

      return S_OK;

   }

   else

   {

      *ppvObject = NULL;

      return E_NOINTERFACE;

   }

}

ULONG    CTestObjectFactory::AddRef( void)

{

   m_nRef++;

   return m_nRef;

}

ULONG    CTestObjectFactory::Release( void)

{

   m_nRef--;

   if (m_nRef==0)

   {

      delete this;

   }

   return m_nRef;

}

HRESULT CTestObjectFactory::CreateInstance(IUnknown *pUnkOuter,REFIID riid,void **ppvObject)

{

   if (NULL != pUnkOuter)

      return CLASS_E_NOAGGREGATION;

   DT(L"Enter CreateInstance...");

   CTestObject *pObj=NULL;

   pObj = new CTestObject();

   if (pObj==NULL)

   {

      *ppvObject = NULL;

      return E_OUTOFMEMORY;

   }

   HRESULT hr = pObj->QueryInterface(riid,ppvObject);

   if (FAILED(hr))

   {

      DT(L"Failed to Create TestObj!");

      delete pObj;

   }

   return hr;

}

HRESULT CTestObjectFactory::LockServer(BOOL fLock)

{

   if (fLock)

   {

      g_LockNumber++;

   }

   else

      g_LockNumber--;

   return NOERROR;

}

 

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.

BOOL SetKeyAndValue(const TCHAR* pszPath,

                const TCHAR* szSubkey,

                const TCHAR* szValue) ;

 

// Convert a CLSID into a char string.

void CLSIDtoString(const CLSID& clsid,

               TCHAR* szCLSID,

               int length) ;

 

// Delete szKeyChild and all of its descendents.

LONG DeleteKey(HKEY hKeyParent, const TCHAR* 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 TCHAR *szFileName,     // DLL module handle

                   const TCHAR* szProgID,       //   IDs

                   const TCHAR* szDescription,  // Description String

                   const TCHAR* szVerIndProgID) // optional

 

{

   DT(szFileName);

   DT(szProgID);

   // Convert the CLSID into a char.

   TCHAR szCLSID[CLSID_STRING_SIZE] ;

   CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ;

   //StringFromCLSID(clsid,szCLSID);

   // Build the key CLSID//{...}

   TCHAR szKey[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) ;

   }

 

   return S_OK ;

}

 

//

// Remove the component from the registry.

//

HRESULT UnregisterServer(const CLSID& clsid,      // Class ID

                    const TCHAR* szProgID,       //   IDs

                    const TCHAR* szVerIndProgID) // Programmatic

{

   // Convert the CLSID into a char.

   TCHAR szCLSID[CLSID_STRING_SIZE] ;

   CLSIDtoString(clsid, szCLSID, sizeof(szCLSID)) ;

   //StringFromCLSID(clsid,szCLSID);

   // Build the key CLSID//{...}

   TCHAR szKey[64] ;

   lstrcpy(szKey, L"CLSID//") ;

   lstrcat(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,

               TCHAR* szCLSID,

               int length)

{

   assert(length >= CLSID_STRING_SIZE) ;

   // Get CLSID

   LPOLESTR wszCLSID = NULL ;

   HRESULT hr = StringFromCLSID(clsid, &wszCLSID) ;

   assert(SUCCEEDED(hr)) ;

   lstrcpy(szCLSID,wszCLSID);

   DT(szCLSID);

 

   // Free memory.

   CoTaskMemFree(wszCLSID) ;

}

 

//

// Delete a key and all of its descendents.

//

LONG DeleteKey(HKEY hKeyParent,           // Parent of key to delete

            const TCHAR* 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 ;

   TCHAR 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 TCHAR* szKey,

                const TCHAR* szSubkey,

                const TCHAR* szValue)

{

   HKEY hKey;

   TCHAR szKeyBuf[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.

   long lResult = 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!");

      return FALSE ;

   }

 

   // Set the Value.

   if (szValue != NULL)

   {

      RegSetValueEx(hKey, NULL, 0, REG_SZ,

         (BYTE *)szValue,

         2*lstrlen(szValue)+1) ;

   }

 

   RegCloseKey(hKey) ;

   DT(L"SetKeyAndValue Succeed!");

   return TRUE ;

}

 

 

 

//componet.com

 

 

#include "stdafx.h"

 

 

#include "Registry.h"

//#include "ComTest.h"

#ifdef _MANAGED

#pragma managed(push, off)

#endif

HMODULE g_hModule = NULL;

ULONG    g_LockNumber = 0;

 

 

 

EXTERN_C const CLSID CLSID_TestObject;

EXTERN_C const CLSID IID_ObjectInterface;

//class CTestObjectFactory;

#include "TestObjectFactory.h"

STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)

{

   DT(L"DllGetClassObject...");

   if (clsid == CLSID_TestObject ) {

 

      CTestObjectFactory *pFactory = new CTestObjectFactory;

 

      if (pFactory == NULL) {

         return E_OUTOFMEMORY ;

      }

 

      HRESULT result = pFactory->QueryInterface(iid, ppv);

 

      return result;

   } else {

      return CLASS_E_CLASSNOTAVAILABLE;

   }

}

 

STDAPI DllCanUnloadNow(void)

{

   if (g_LockNumber == 0)

      return S_OK;

   else

      return S_FALSE;

}

STDAPI DllRegisterServer()

{

   TCHAR szFileName[MAX_PATH];

   ::GetModuleFileName((HMODULE)g_hModule,szFileName,sizeof(szFileName));

   DT(szFileName);

   return RegisterServer(CLSID_TestObject,szFileName,L"TestCom.Object",L"Test Componet",NULL);

 

}

 

 

 

STDAPI DllUnregisterServer()

{

   //return AMovieDllRegisterServer2(FALSE);

   return UnregisterServer(CLSID_TestObject,L"TestCom.Object",NULL);

 

}

BOOL APIENTRY DllMain( HMODULE hModule,

                       DWORD  ul_reason_for_call,

                       LPVOID lpReserved

                 )

{

   if (!g_hModule)

   {

      g_hModule = hModule;

   }

    return TRUE;

}

 

#ifdef _MANAGED

#pragma managed(pop)

#endif

你可能感兴趣的:(C++,String,null,delete,Class,Access)