COM组件入门(一)

简介:

近期须要用到COM组件的知识,看了看COM编程指南,感觉还不错。把我的学习心得记录下来。这是我依据教程写的demo

StopWatch接口实现部分,接口部分我的项目是动态库,主要源代码例如以下:

完整demo见:http://download.csdn.net/detail/davidsu33/7750101

stopwatch.h

#pragma once

#include <Windows.h>
#include <MMSystem.h>
#include <Unknwn.h>
#include <WinBase.h>
#include "timer_i.h"

class stopwatcher
{
public:
	stopwatcher(void);
	~stopwatcher(void);
};

class IStopWatch : public IUnknown
{
public:
	//virtual unsigned long _stdcall Release() = 0;
	virtual HRESULT _stdcall Start() = 0;
	virtual HRESULT _stdcall ElaspedTime(float *elaspedtime) = 0;
};

class CStopWatch : public IStopWatch
{
public:
	CStopWatch()
	{
		m_nRefValue = 0;
		m_nFreq.QuadPart = 0;
		QueryPerformanceFrequency(&m_nFreq);
		AddRef();
	}
public:
	//virtual unsigned long _stdcall Release()
	//{
	//	delete this;
	//	return 0;
	//};

	//创建相应的接口对象
	virtual HRESULT STDMETHODCALLTYPE QueryInterface( 
        /* [in] */ REFIID riid,
        /* [iid_is][out] */ __RPC__deref_out void __RPC_FAR *__RPC_FAR *ppvObject)
	{
		if(riid == IID_IStopWatch)
		{
			*ppvObject = static_cast<IStopWatch*>(this);
			return S_OK;
		}
		else if(riid == IID_IUnknown)
		{
			*ppvObject = static_cast<IUnknown*>(this);
			return S_OK;
		}

		*ppvObject = NULL;
		return E_NOINTERFACE;
	};

	//添加引用
    virtual ULONG STDMETHODCALLTYPE AddRef( void) 
	{
		InterlockedIncrement(&m_nRefValue);
		return m_nRefValue;
	};

	//解除引用
    virtual ULONG STDMETHODCALLTYPE Release( void)
	{
		InterlockedDecrement(&m_nRefValue);
		if(m_nRefValue == 0)
			delete this;
		return m_nRefValue;
	};

	virtual HRESULT _stdcall Start()
	{
		BOOL bOK = QueryPerformanceCounter(&m_nStartTime);
		if(!bOK)
			return S_FALSE;
		return S_OK;
	};

	virtual HRESULT _stdcall ElaspedTime(float *elaspedtime)
	{
		LARGE_INTEGER nStopTime;
		BOOL bOK = QueryPerformanceCounter(&nStopTime);
		if(!bOK)
			return S_FALSE;

		*elaspedtime = ((float)(nStopTime.QuadPart - m_nStartTime.QuadPart))/m_nFreq.QuadPart;

		return S_OK;
	};

private:
	LARGE_INTEGER m_nFreq;
	LARGE_INTEGER m_nStartTime;
	volatile unsigned long m_nRefValue;
};

//return IStopWatch interface object
extern "C" HRESULT _stdcall DllGetClassObject(REFCLSID rcsid, REFIID rid, LPVOID* lpvoid)
{
	if(rcsid == CLSID_CStopWatch)
	{
		*lpvoid = static_cast<IStopWatch*>(new CStopWatch);
		return S_OK;
	}
	
	*lpvoid = NULL;
	return CLASS_E_CLASSNOTAVAILABLE;
}



client的调用代码

#include "../stopwatch/stopwatcher.h"
#include "../stopwatch/timer_i.h"

#include <iostream>
#include <cstring>
#include <cassert>

#define TIMERDLL L"../Debug/stopwatch.dll"
#define PROCNAME "DllGetClassObject"

typedef HRESULT  (_stdcall*  GETOBJFUNC)(REFCLSID , REFIID , LPVOID* );

using namespace std;
void trace(const char *str)
{
	cout<<str<<endl;
}

void trace(const string& s)
{
	cout<<s.c_str()<<endl;
}

HRESULT CreateInstance(void **p, HMODULE *rhMod)
{
	HMODULE hMod = LoadLibrary(TIMERDLL);
	if(!hMod)
		return E_FAIL;

	GETOBJFUNC proc = 
		(GETOBJFUNC)GetProcAddress(hMod, PROCNAME);

	if(!proc)
		return E_FAIL;

	*p = proc;
	*rhMod = hMod;

	return S_OK;
}

void FreeInstance(HMODULE hMod)
{
	assert(FreeLibrary(hMod));
}

void testInstance()
{
	void *fptr = NULL;
	HMODULE hMod = NULL;
	HRESULT hr = CreateInstance(&fptr, &hMod);
	if(FAILED(hr))
	{
		trace("CreateInstace failed");
		return;
	}

	GETOBJFUNC proc = (GETOBJFUNC)(fptr);
	IUnknown *ptr = NULL;
	
	//首先得到类实例
	//然后依据类实例得到IUnknown
	//最后通过IUnknown调取QueryInterface接口来得到其子类的接口对象
	//调用子类的接口对象
	hr = proc(CLSID_CStopWatch, IID_IUnknown, (LPVOID*)&ptr);
	if(FAILED(hr))
	{
		trace("GetObject failed");
		return;
	}

	if(!ptr)
	{
		trace("ptr is null");
		return;
	}

	IStopWatch *ptrSW = NULL;
	hr = ptr->QueryInterface(IID_IStopWatch, (void**)&ptrSW);
	assert(SUCCEEDED(hr));

	hr = ptrSW->Start();
	assert(SUCCEEDED(hr));

	int m=0;
	for(int i=0; i<10000000; ++i)
		++m;

	float elaspedtime = 0;
	hr = ptrSW->ElaspedTime(&elaspedtime);
	assert(SUCCEEDED(hr));

	cout<<"ElaspedTime:"<<elaspedtime<<endl;

	//释放对象本身
	ptrSW->Release();

	FreeInstance(hMod);
}

int main(int argc, char *argv[])
{
	testInstance();
	getchar();
	return 0;
}





本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5368254.html,如需转载请自行联系原作者   

相关文章
QT实现雷达图和摇杆图
小伙伴们大家好,之前我上传了一个资源(骗积分用的),但是没有效果图和博文与之对应,所以大家应该是都不敢下载的吧, 先上资源链接 : 一个雷达图和一个摇杆图(方向可以根据你自己的需要增加)资源 再上效果图。
901 1
QT实现雷达图和摇杆图
|
传感器 监控 物联网
FastBond2阶段2——基于ESP32C3开发的简易IO调试设备
FastBond2阶段2——基于ESP32C3开发的简易IO调试设备
405 0
|
9月前
|
人工智能 监控 API
狂揽22.6k星!这个开源工具让你一键调用100+大模型,开发效率直接起飞!
LiteLLM是由BerriAI团队开发的开源项目,通过标准化OpenAI格式API接口,支持调用100+主流大语言模型(如OpenAI、Azure、Anthropic等)。其核心功能包括统一调用方式、企业级智能路由、异步流式响应及环境变量管理。项目适用于企业AI中台搭建、多模型对比测试、教育科研实验等场景。技术架构涵盖接口层、路由层、管理层与监控层,提供高效稳定的服务。相比LangChain、LlamaIndex等项目,LiteLLM在多平台混合开发方面优势显著。项目地址:https://github.com/BerriAI/litellm。
1183 2
|
4月前
|
存储 搜索推荐 数据库
🚀 RAGFlow Docker 部署全流程教程
RAGFlow是开源的下一代RAG系统,融合向量数据库与大模型,支持全文检索、插件化引擎切换,适用于企业知识库、智能客服等场景。支持Docker一键部署,提供轻量与完整版本,助力高效搭建私有化AI问答平台。
3348 8
|
存储 弹性计算 分布式计算
阿里云服务器租用价格:包年包月收费标准与月付、1年、3年活动价格
租用阿里云服务器3个月、6个月、1年、3年多少钱?云服务器收费标准是怎样的?根据目前的价格信息,阿里云特价云服务器价格38元、99元、199元、298元,本文分享阿里云服务器最新的租用费用,包括包年包月的收费标准和月付3个月和6个月以及1年、3年活动价格表。
|
存储 安全 前端开发
端到端加密:确保数据传输安全的最佳实践
【10月更文挑战第12天】端到端加密(E2EE)是确保数据传输安全的重要手段,通过加密技术保障数据在传输过程中的隐私与完整性,防止第三方窃听和篡改。本文介绍E2EE的工作原理、核心优势及实施步骤,并探讨其在即时通讯、文件共享和金融服务等领域的应用,强调了选择加密协议、密钥管理、数据加密及安全接口设计的重要性,旨在帮助企业和开发者有效保护用户数据,满足数据保护法规要求。
|
运维 算法 jenkins
做一个可通过jenkins定时任务Cron表达式设置的python定时函数
用python代码,来解析jenkins定时任务表达式,并获取最近的执行任务时间戳
|
数据采集 存储 算法
ScrapySharp框架:小红书视频数据采集的API集成与应用
ScrapySharp框架:小红书视频数据采集的API集成与应用
|
编译器 C++
Visual Studio 2022中创建的C++项目无法使用万能头<bits/stdc++.h>解决方案
Visual Studio 2022中创建的C++项目无法使用万能头<bits/stdc++.h>解决方案
1152 0
Visual Studio 2022中创建的C++项目无法使用万能头<bits/stdc++.h>解决方案