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;
}

客户端的调用代码

#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;
}

COM组件入门(一)

时间: 2024-10-09 11:36:25

COM组件入门(一)的相关文章

Android笔记二十七.Service组件入门(一).什么是Service?

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.Service 1.Service简介 Service为Android四大组件之一,Service与Activity组件相似,都代表可执行的程序且有自己的生命周期,唯一的区别是Activity组件提供界面方便人机交互而Service只在后台运行且没有交互界面.Service是android 系统中的一种组件,它们都是从Context派生出来的,但是它不能自己运行,只能在后台运行,并且可以和其

Android学习笔记二十三.Service组件入门(一).什么是Service?

什么是Service? 一.Service 1.Service简介 Service为Android四大组件之一,Service与Activity组件相似,都代表可执行的程序且有自己的生命周期,唯一的区别是Activity组件提供界面方便人机交互而Service只在后台运行且没有交互界面.需要注意的是,Service不是一个单独的进程或为了防止应用出现无反应错误单独的线程,它像其他应用对象一样运行在其托管进程的主线程中.当然,如果我们希望自己的Service能够在后台运行MP3或者网络下载,我们可

Android学习笔记二十五.Service组件入门(三)使用IntentService

使用IntentService 1.Service缺陷 由于Service本身存在以下两个问题: (1)Service不会专门启动一条单独的进程,Service与他所在应用位于同一进程中: (2)Service也不是专门一条新的线程,如果我们在Service中直接处理耗时的任务,那么就会导致应用程序出现假性"卡死".如果我们需要在Service处理耗时任务,也可以在Service的onCreate()方法中启动一条新线程来处理该耗时任务(如上例).但是,问题来了,启动Service的A

es6+react.js组件入门初探

React是一个用于构建用户见面的javascript库. React主要用于构建UI,许多人认为React是MVC中的V(视图) React起源于Facebook的内部项目,用来架设Instagram的网站,并于2013年5月开源. React拥有较高的性能,越来越多的人开始关注和使用它. 例如简单的计数器实现: react.min.js 详解:react的核心库 react-dom.min.js 详解:提供与DOM相关的功能 ReactDOM类库 1.渲染ReactElement:React

Vue.js 实例和内置组件 入门

首先来看看实例的概述: 实例就是在构造器外部操作操作构造器内部的属性和方法. 实例的作用就是给Vue提供与其它js及其框架结合使用的接口. 进入实例阶段: 首先来看 Vue.js 搭配 jQuery 使用: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Early Examples Demo</title&g

转:ECharts图表组件入门教程之Theme:ECharts图表的皮肤是什么?如何给图表换主题(皮肤)Theme?

一.什么是ECharts图表的皮肤(主题)? 针对这个问题我只能这样回答,ECharts图表的主题(皮肤)就犹如人的衣服一样,是用来衬托和渲染主体,使其变得更加美观好看的目的.你去过ECharts图表组件的官网应该都看到每一个示例都支持皮肤切换的.我们更深入的理解,皮肤其实就是一些样式的定义集合. 图表有很多部分组成,比如:标题.坐标轴.Series数据.Legend图例等.每一个部分我们可以为其设置style样式,形如:字体颜色.字体大小.旋转角度.背景图片.背景颜色.是否渐变等. 二.如何将

原创教程之——reactjs 组件入门教程

在学习react之前,希望你有以下准备: react的安装ECMAScript 6基础 本文不讲解react的安装步骤,若需了解请移步官方网站(https://reactjs.org/),那里讲解非常清楚,也很简单.至于ECMAScript 6,大家可以去阮一峰老师的官网(http://www.ruanyifeng.com)学习. 这篇文章主要解决一下几个要点, 这几个要点也可能是大家在学习react时非常迷惑的地方. 要点一: 什么是组件? 要点二: 如何编写组件? 要点三: 组件之间如何组合

vue.js快速入门(三)~组件入门~

组件系统是vue的一个重要的概念.他可以让我们使用独立的,可复用的小组件来构建大的复杂的应用,任何应用都可以看作是组件树.组件可以看做是自定义的Html代码.可扩展的html,封装可重用的html. 使用组件的使用分为三步 创建组件构造器,调用Vue.extend()创建,这是Vue构造器的扩展.他有个选项对象.选项对象有个template属性,定义组件要渲染的html 注册组件 ,Vue.compontent()注册 使用组件(在Vue实例的作用范围内使用组件,必须挂载在实例下,否则不生效)

Vue2入门路线及资源

前言:最近在学习Vue,感觉对vue+vuex+vue-router算是小小地入门了.想起前期最苦恼也是最费时的事,就是在每个阶段找到合适当前水平的资源或者demo,所以本文我根据我自己的体验,整理了一些资源,每个阶段跨度都较平缓,应该能比较顺畅地入门. (以下链接后标明vue1的,表示博文及其demo是基于vue1,但原理基本是一样的,可以根据对博文的理解,将其demo由vue1改写为vue2,这样正好也可加深理解.) 基础入门 将官方文档的基础部分过一遍,不用太究细节,但也最好每个例子都自己