C++ COM编程学习详解攻略
什么是COM?
COM(Component Object Model)是一种面向对象的软件组件技术,主要用于在不同的应用程序之间通信。使用COM,你可以编写可重用的软件组件,这些组件可以跨越不同的编程语言,操作系统和网络。COM最初是由Microsoft开发的。
学习COM的前提条件
- 了解C++语言,并熟练掌握面向对象编程。
- 具备基本的Windows编程知识,例如Windows消息循环、窗口及控件的操作等。
- 了解COM相关的基本概念,例如接口、类工厂等。
COM编程基本步骤
- 设计COM接口和实现类
- 在COM中,接口是对象与外部世界进行交互的唯一方式。需要先设计接口,然后再根据接口定义实现类。
-
接口可以使用IDL(Interface Definition Language)定义,也可以使用C++定义。
-
实现COM对象
-
实现COM对象要实现接口,同时需要了解对象的生命周期和资源管理方法。
-
注册COM组件
-
注册COM组件需要使用注册表。注册表可以使用系统提供的RegEdit.exe工具查看和编辑,也可以使用编程语言访问。
-
创建COM对象
- 在客户端程序中,需要实例化COM对象并调用其提供的接口。
示例一:计算器COM组件
以下是一个简单的计算器组件,包含加、减、乘、除四个操作。
1. 设计接口
[object, uuid(b5c61d71-29b4-487d-a198-50842ac0cd33)]
interface ICalculator : IUnknown
{
HRESULT Add(double a, double b, [out] double* result);
HRESULT Subtract(double a, double b, [out] double* result);
HRESULT Multiply(double a, double b, [out] double* result);
HRESULT Divide(double a, double b, [out] double* result);
};
定义了四个方法Add、Subtract、Multiply、Divide,每个方法都有两个输入参数和一个输出参数。其中第三个参数是一个指向输出结果的指针。
2. 实现类
#include <windows.h>
#include "Calculator.h"
class Calculator : public ICalculator
{
public:
Calculator() :
m_refCount(1)
{}
// IUnknown methods
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)
{
if (riid == __uuidof(ICalculator) || riid == __uuidof(IUnknown))
{
*ppvObject = this;
AddRef();
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&m_refCount);
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG count = InterlockedDecrement(&m_refCount);
if (count == 0)
{
delete this;
}
return count;
}
// ICalculator methods
HRESULT STDMETHODCALLTYPE Add(double a, double b, double* result)
{
*result = a + b;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Subtract(double a, double b, double* result)
{
*result = a - b;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Multiply(double a, double b, double* result)
{
*result = a * b;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Divide(double a, double b, double* result)
{
if (b == 0)
{
return E_INVALIDARG;
}
*result = a / b;
return S_OK;
}
private:
ULONG m_refCount;
};
实现了ICalculator接口,其中QueryInterface、AddRef和Release方法是实现IUnknown接口所必需的。对象的引用计数由m_refCount维护。
3. 注册COM组件
需要在注册表中添加以下记录:
[HKEY_CLASSES_ROOT\CLSID\{B5C61D71-29B4-487D-A198-50842AC0CD33}]
@="Calculator"
[HKEY_CLASSES_ROOT\CLSID\{B5C61D71-29B4-487D-A198-50842AC0CD33}\InProcServer32]
@="C:\\calc.dll"
"ThreadingModel"="Apartment"
其中{B5C61D71-29B4-487D-A198-50842AC0CD33}是所分配的GUID,C:\calc.dll是计算器组件的实现文件路径。
4. 创建COM对象
#include <windows.h>
#include <iostream>
#include "Calculator.h"
int main()
{
// 初始化COM
CoInitialize(nullptr);
// 创建COM对象
ICalculator* calculator = nullptr;
HRESULT hr = CoCreateInstance(CLSID_Calculator, nullptr, CLSCTX_INPROC_SERVER,
IID_ICalculator, (LPVOID*)&calculator);
if (SUCCEEDED(hr))
{
double result = 0;
calculator->Add(2, 3, &result);
std::cout << "2 + 3 = " result << std::endl;
calculator->Subtract(4, 1, &result);
std::cout << "4 - 1 = " << result << std::endl;
calculator->Multiply(2, 4, &result);
std::cout << "2 * 4 = " << result << std::endl;
calculator->Divide(8, 2, &result);
std::cout << "8 / 2 = " << result << std::endl;
calculator->Release();
}
// 反初始化COM
CoUninitialize();
return 0;
}
在程序中,使用CoCreateInstance方法实例化COM对象,调用其接口方法完成四则运算。
示例二:主机监视器COM组件
另一个示例是一个主机监视器组件,用于获取电脑的CPU使用率和内存占用情况。
1. 设计接口
[object, uuid(4589bac9-b3e9-4bcf-9987-3d5c8cf842bb)]
interface IHostMonitor : IUnknown
{
HRESULT GetCpuUsage([out] double* usage);
HRESULT GetMemoryUsage([out] double* usage);
};
定义了两个方法GetCpuUsage和GetMemoryUsage。
2. 实现类
#include <windows.h>
#include "HostMonitor.h"
static const int SAMPLING_TIME = 1000;
class HostMonitor : public IHostMonitor
{
public:
HostMonitor() :
m_refCount(1)
{
m_lastIdleTime.QuadPart = 0;
m_lastKernelTime.QuadPart = 0;
m_lastUserTime.QuadPart = 0;
MEMORYSTATUSEX mem;
mem.dwLength = sizeof(mem);
GlobalMemoryStatusEx(&mem);
m_totalMemory = mem.ullTotalPhys;
}
// IUnknown methods
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject)
{
if (riid == __uuidof(IHostMonitor) || riid == __uuidof(IUnknown))
{
*ppvObject = this;
AddRef();
return S_OK;
}
*ppvObject = nullptr;
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return InterlockedIncrement(&m_refCount);
}
ULONG STDMETHODCALLTYPE Release()
{
ULONG count = InterlockedDecrement(&m_refCount);
if (count == 0)
{
delete this;
}
return count;
}
// IHostMonitor methods
HRESULT STDMETHODCALLTYPE GetCpuUsage(double* usage)
{
FILETIME idleTime, kernelTime, userTime;
if (GetSystemTimes(&idleTime, &kernelTime, &userTime))
{
__int64 deltaIdleTime = SubtractTimes(idleTime, m_lastIdleTime);
__int64 deltaKernelTime = SubtractTimes(kernelTime, m_lastKernelTime);
__int64 deltaUserTime = SubtractTimes(userTime, m_lastUserTime);
if (deltaKernelTime + deltaUserTime > 0)
{
*usage = 1.0 - (double)deltaIdleTime / (double)(deltaKernelTime + deltaUserTime);
*usage *= 100;
}
m_lastIdleTime = idleTime;
m_lastKernelTime = kernelTime;
m_lastUserTime = userTime;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE GetMemoryUsage(double* usage)
{
MEMORYSTATUSEX mem;
mem.dwLength = sizeof(mem);
if (GlobalMemoryStatusEx(&mem))
{
*usage = (double)(m_totalMemory - mem.ullAvailPhys) / (double)m_totalMemory;
*usage *= 100;
}
return S_OK;
}
private:
ULONG m_refCount;
FILETIME m_lastIdleTime;
FILETIME m_lastKernelTime;
FILETIME m_lastUserTime;
unsigned long long m_totalMemory;
__int64 SubtractTimes(const FILETIME& ft1, const FILETIME& ft2)
{
ULARGE_INTEGER u1, u2;
u1.LowPart = ft1.dwLowDateTime;
u1.HighPart = ft1.dwHighDateTime;
u2.LowPart = ft2.dwLowDateTime;
u2.HighPart = ft2.dwHighDateTime;
return u1.QuadPart - u2.QuadPart;
}
};
该类实现了IHostMonitor接口,其中GetCpuUsage方法获取CPU使用率,GetMemoryUsage方法获取内存占用情况。在GetCpuUsage方法中,使用GetSystemTimes方法获取了系统的运行时间,计算出CPU使用率。
3. 注册COM组件
与上一个示例类似,需要在注册表中添加以下记录:
[HKEY_CLASSES_ROOT\CLSID\{4589BAC9-B3E9-4BCF-9987-3D5C8CF842BB}]
@="HostMonitor"
[HKEY_CLASSES_ROOT\CLSID\{4589BAC9-B3E9-4BCF-9987-3D5C8CF842BB}\InProcServer32]
@="C:\\host.dll"
"ThreadingModel"="Apartment"
4. 创建COM对象
#include <windows.h>
#include <iostream>
#include "HostMonitor.h"
int main()
{
// 初始化COM
CoInitialize(nullptr);
// 创建COM对象
IHostMonitor* monitor = nullptr;
HRESULT hr = CoCreateInstance(CLSID_HostMonitor, nullptr, CLSCTX_INPROC_SERVER,
IID_IHostMonitor, (LPVOID*)&monitor);
if (SUCCEEDED(hr))
{
double cpuUsage = 0;
monitor->GetCpuUsage(&cpuUsage);
std::cout << "CPU:" << cpuUsage << "%" << std::endl;
double memoryUsage = 0;
monitor->GetMemoryUsage(&memoryUsage);
std::cout << "Memory:" << memoryUsage << "%" << std::endl;
monitor->Release();
}
// 反初始化COM
CoUninitialize();
return 0;
}
在程序中,使用CoCreateInstance方法实例化COM对象,调用其接口方法完成获取CPU使用率和内存占用情况。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++ com编程学习详解 - Python技术站