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,如需转载请自行联系原作者   

相关文章
|
2月前
|
C#
Delphi可不可以制作出像c#那样的dll类库?
在Delphi中,创建DLL项目(如dll.dpr)并定义一个类TMyCls后,在另一个项目(如test.dpr)中可以引入此DLL并直接实例化和调用类的方法。然而,Delphi目前主要支持两种DLL形式:动态链接库(需显式声明exports,仅支持函数调用)和ActiveX DLL(需定义IDL接口)。这两种方式都较为繁琐。相比之下,C# 的DLL类库更为便捷,编写并编译后即可在其他项目中直接使用。
|
API 调度 开发工具
03 MFC - 入门程序
03 MFC - 入门程序
61 0
|
容器
COM组件开发实践(一)
   Preface       因为项目需要,开始从事ActiveX方面的工作,看了一些资料,可惜都是些COM原理方面的,没有切合实际动手的东西,在CodeProject上读完David Marcionek的文章【1】后,收获良多,但也遇到一些恼人的小问题,因此在其基础上就一些易错点做些小注解。
1199 0