一个完整的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;
}
 终于贴完了。一个完整的示例,亲测可以哈!一起学习。



好的,下面是一个简单的循环队列的 C++ 代码示例: ```c++ #include <iostream> using namespace std; const int MAXSIZE = 10; // 队列的最大容量 class CircularQueue { private: int front; // 队头指针 int rear; // 队尾指针 int data[MAXSIZE]; // 队列数组 public: CircularQueue() { // 构造函数,初始化队列为空 front = rear = 0; } bool isFull() { // 判断队列是否已满 return (rear + 1) % MAXSIZE == front; } bool isEmpty() { // 判断队列是否为空 return front == rear; } bool enqueue(int x) { // 入队 if (isFull()) return false; data[rear] = x; rear = (rear + 1) % MAXSIZE; return true; } bool dequeue(int &x) { // 出队 if (isEmpty()) return false; x = data[front]; front = (front + 1) % MAXSIZE; return true; } }; int main() { CircularQueue q; int x; for (int i = 0; i < 12; i++) { if (q.enqueue(i)) { cout << "入队 " << i << endl; } else { cout << "队列已满" << endl; } } for (int i = 0; i < 12; i++) { if (q.dequeue(x)) { cout << "出队 " << x << endl; } else { cout << "队列已空" << endl; } } return 0; } ``` 在上面的示例中,我们通过一个 `CircularQueue` 类来实现循环队列的基本操作。其中,`front` 和 `rear` 分别记录队头和队尾的位置,`data` 数组用来存储队列中的数据。在 `enqueue()` 和 `dequeue()` 函数中,我们使用了取余运算来实现循环队列的循环性质。在 `main()` 函数中,我们通过一个简单的循环来测试队列的入队和出队操作。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iot-genius

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值