COM组件入门(一)

news/2024/7/3 20:56:38

近期须要用到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;
}




http://www.niftyadmin.cn/n/1275820.html

相关文章

dubbo 协议

dubbo:// Dubbo缺省协议采用单一长连接和NIO异步通讯&#xff0c;适合于小数据量大并发的服务调用&#xff0c;以及服务消费者机器远大于服务提供者机器数的情况。 设置默认协议&#xff1a; <dubbo:provider protocol"dubbo"/> 为服务设置协议&#xff1a;…

解决软件开发中常见的问题

互联网行业火吗?火。火到了什么地步?大概已经到了让大家已经离不开的程度了。在前端时在网上就看到一个话题&#xff0c;很多人在谈论互联网的是绑架人类还是帮助了人类。我就不由想起前段时间&#xff0c;人们在家里隔离&#xff0c;只能靠着互联网娱乐、购物、社交、工作、…

在2021年, Python是否会全面超越 Java?

第一&#xff0c;简单地看 Python是否比 Java更受欢迎并没有多大意义&#xff0c;事实上&#xff0c;尽管 Java和 Python都是非常受欢迎的全场景编程语言&#xff0c;但 Python和 Java仍然各有侧重。 在IT互联网行业的生产环境下&#xff0c;Java的应用还是非常普遍的&#xf…

程序员编程入门一定知道!程序员需要学什么?

编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码&#xff0c;并最终得到结果的过程。在信息时代的背景下&#xff0c;计算机的应用扮演着重要的角色&#xff0c;而对于巨大的市场需求来说&#xff0c;精通计算机的人才仍然稀缺&#xff0c;所以计算机行业的…

day1 学习历程

day1 我是一个在校大三学生&#xff0c;一个依然迷茫不知前景的大学混子 &#xff0c;可以这么说吧 大学混子 真正开始决定好好学习大概在去年的12月份 那时经老师的提醒 开始正式接触软件开发 于是 从头开始学习语言 下了很大的决心 开始从C学习开始 然后学习了不到一个星期 听…

dubbo 并发控制 和 连接控制

并发控制 &#xff08;1&#xff09;服务端并发执行&#xff08;或占用线程池线程数&#xff09;不能超过10个。 <dubbo:service interface"com.foo.BarService" executes"10" /> &#xff08;2&#xff09;限制到方法 <dubbo:service interfac…

运动APP软件开发具有什么好处?

人的身体健康离不开有效的运动&#xff0c;为了满足用户在运动方面的需求&#xff0c;健身运动 APP开发也开始出现&#xff0c;通过方便的手机平台为用户提供一条龙的运动服务。 运动APP软件开发具有什么好处&#xff1f; 对经营者来说&#xff1a; 降低用户管理的难度&…