COM开发入门基础及实例
组件对象模型(Component Object Model,简称COM)是Microsoft开发的一种二进制接口标准,用于实现软件组件间的互操作。COM是Windows平台上许多关键技术的基础,包括ActiveX、OLE、DirectX和Windows Shell等。本文将介绍COM的基本概念、工作原理,并通过实例演示如何开发COM组件。
1. COM基础概念
1.1 COM的核心特性
COM基于以下几个核心概念:
- 接口:所有COM组件通过接口与外界交互,接口是一组相关函数的集合
- 引用计数:管理组件生命周期的机制
- 接口查询:允许客户端发现组件支持的功能
- 二进制兼容性:组件可以在不同版本间保持兼容
- 语言独立性:COM组件可以用任何语言编写,并被任何语言调用
1.2 IUnknown接口
所有COM接口都继承自IUnknown,它定义了三个基本方法:
cpp
interface IUnknown {
HRESULT QueryInterface(REFIID riid, void** ppvObject);
ULONG AddRef();
ULONG Release();
};
- QueryInterface:允许客户端查询组件支持的其他接口
- AddRef:增加引用计数
- Release:减少引用计数,当计数为零时释放组件
1.3 GUID和接口标识符
COM使用全局唯一标识符(GUID)来标识每个接口和组件:
cpp
// IExample接口的ID定义
// {12345678-1234-1234-1234-123456789ABC}
DEFINE_GUID(IID_IExample,
0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc);
2. 创建第一个COM组件
2.1 定义接口
首先定义一个自定义接口:
cpp
// ICalculator.h
#include <unknwn.h>
// {5B4F9CEF-3742-4B9B-8F26-B8C0B2D238A6}
DEFINE_GUID(IID_ICalculator,
0x5b4f9cef, 0x3742, 0x4b9b, 0x8f, 0x26, 0xb8, 0xc0, 0xb2, 0xd2, 0x38, 0xa6);
// 定义计算器接口
interface ICalculator : public IUnknown {
virtual HRESULT __stdcall Add(int a, int b, int* result) = 0;
virtual HRESULT __stdcall Subtract(int a, int b, int* result) = 0;
virtual HRESULT __stdcall Multiply(int a, int b, int* result) = 0;
virtual HRESULT __stdcall Divide(int a, int b, int* result) = 0;
};
2.2 实现组件类
接下来实现组件类:
cpp
// Calculator.h
#include "ICalculator.h"
#include <atomic>
// {8C42B6C0-9C8A-4C54-B2A5-E9D9D4E4D178}
DEFINE_GUID(CLSID_Calculator,
0x8c42b6c0, 0x9c8a, 0x4c54, 0xb2, 0xa5, 0xe9, 0xd9, 0xd4, 0xe4, 0xd1, 0x78);
class Calculator : public ICalculator {
public:
// IUnknown方法
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
// ICalculator方法
HRESULT __stdcall Add(int a, int b, int* result) override;
HRESULT __stdcall Subtract(int a, int b, int* result) override;
HRESULT __stdcall Multiply(int a, int b, int* result) override;
HRESULT __stdcall Divide(int a, int b, int* result) override;
// 构造和析构函数
Calculator();
~Calculator();
private:
std::atomic<ULONG> m_refCount;
};
2.3 实现组件方法
cpp
// Calculator.cpp
#include "Calculator.h"
// 构造函数
Calculator::Calculator() : m_refCount(1) {
// 初始化工作
}
// 析构函数
Calculator::~Calculator() {
// 清理工作
}
// IUnknown方法实现
HRESULT __stdcall Calculator::QueryInterface(REFIID riid, void** ppvObject) {
if (ppvObject == NULL) {
return E_POINTER;
}
if (riid == IID_IUnknown) {
*ppvObject = static_cast<IUnknown*>(this);
}
else if (riid == IID_ICalculator) {
*ppvObject = static_cast<ICalculator*>(this);
}
else {
*ppvObject = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG __stdcall Calculator::AddRef() {
return ++m_refCount;
}
ULONG __stdcall Calculator::Release() {
ULONG newCount = --m_refCount;
if (newCount == 0) {
delete this;
}
return newCount;
}
// ICalculator方法实现
HRESULT __stdcall Calculator::Add(int a, int b, int* result) {
if (result == NULL) {
return E_POINTER;
}
*result = a + b;
return S_OK;
}
HRESULT __stdcall Calculator::Subtract(int a, int b, int* result) {
if (result == NULL) {
return E_POINTER;
}
*result = a - b;
return S_OK;
}
HRESULT __stdcall Calculator::Multiply(int a, int b, int* result) {
if (result == NULL) {
return E_POINTER;
}
*result = a * b;
return S_OK;
}
HRESULT __stdcall Calculator::Divide(int a, int b, int* result) {
if (result == NULL) {
return E_POINTER;
}
if (b == 0) {
return E_INVALIDARG; // 除数不能为零
}
*result = a / b;
return S_OK;
}
2.4 实现类工厂
类工厂负责创建组件实例:
cpp
// CalculatorFactory.h
#include <unknwn.h>
class CalculatorFactory : public IClassFactory {
public:
// IUnknown方法
HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject) override;
ULONG __stdcall AddRef() override;
ULONG __stdcall Release() override;
// IClassFactory方法
HRESULT __stdcall CreateInstance(IUnknown* pUnkOuter, REFIID riid, void** ppvO