Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1351180
  • 博文数量: 946
  • 博客积分: 52360
  • 博客等级: 大将
  • 技术积分: 13080
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-07 17:31
文章分类

全部博文(946)

文章存档

2011年(1)

2008年(945)

我的朋友

分类: C/C++

2008-08-07 17:38:07

下载本文示例代码
下载源代码

一、实现ISmipleMath,IAdvancedMath接口和DllGetClassObject()

1.1 实现ISmipleMath和IAdvancedMath接口

让我们将原来的CMath 类(CMath其实就是"COM技术初探(二)COM基础知识"里的那个CMath类)修改来实现ISmipleMath接口和IAdvancedMath接口。
修改的地方如下:

1) Math.h文件
/*@**#---2003-10-29 21:33:44 (tulip)---#**@



#include "interface.h"*/



#include "MathCOM.h"//新增加的,以替换上面的东东



class CMath : public ISimpleMath,

			  public IAdvancedMath

{

private:

	ULONG m_cRef;



private:

	int calcFactorial(int nOp);

	int calcFabonacci(int nOp);



public:

	CMath();

	//IUnknown Method

	STDMETHOD(QueryInterface)(REFIID riid, void **ppv);

	STDMETHOD_(ULONG, AddRef)();

	STDMETHOD_(ULONG, Release)();



	//	ISimpleMath Method

	STDMETHOD (Add)(int nOp1, int nOp2,int * pret);

	STDMETHOD (Subtract)(int nOp1, int nOp2,int *pret);

	STDMETHOD (Multiply)(int nOp1, int nOp2,int *pret);

	STDMETHOD (Divide)(int nOp1, int nOp2,int * pret);



	//	IAdvancedMath Method

	STDMETHOD (Factorial)(int nOp,int *pret);

	STDMETHOD (Fabonacci)(int nOp,int *pret);

};

2) Math.cpp文件
/*@**#---2003-10-29 21:32:35 (tulip)---#**@

#include "math.h"



STDMETHODIMP CMath::QueryInterface(REFIID riid, void **ppv)

{//	这里这是实现dynamic_cast的功能,但由于dynamic_cast与编译器相关。

	if(riid == IID_ISimpleMath)

		*ppv = static_cast(this);

	else if(riid == IID_IAdvancedMath)

		*ppv = static_cast(this);

	else if(riid == IID_IUnknown)

		*ppv = static_cast(this);

	else {

		*ppv = 0;

		return E_NOINTERFACE;

	}



	//这里要这样是因为引用计数是针对组件的

	reinterpret_cast(*ppv)->AddRef();	

	return S_OK;

}



STDMETHODIMP_(ULONG) CMath::AddRef()

{

	return   m_cRef;

}



STDMETHODIMP_(ULONG) CMath::Release()

{

	// 使用临时变量把修改后的引用计数值缓存起来

	ULONG res = --m_cRef;



	// 因为在对象已经销毁后再引用这个对象的数据将是非法的

	if(res == 0)			

		delete this;

	return res;

}



STDMETHODIMP CMath::Add(int nOp1, int nOp2,int * pret)

{

	 *pret=nOp1 nOp2;

	 return S_OK;

}



STDMETHODIMP CMath::Subtract(int nOp1, int nOp2,int * pret)

{

	*pret= nOp1 - nOp2;

	return S_OK;

}



STDMETHODIMP CMath::Multiply(int nOp1, int nOp2,int * pret)

{

	*pret=nOp1 * nOp2;

	return S_OK;

}



STDMETHODIMP CMath::Divide(int nOp1, int nOp2,int * pret)

{

	*pret= nOp1 / nOp2;

	return S_OK;

}



int CMath::calcFactorial(int nOp)

{

	if(nOp <= 1)

		return 1;



	return nOp * calcFactorial(nOp - 1);

}



STDMETHODIMP CMath::Factorial(int nOp,int * pret)

{

	*pret=calcFactorial(nOp);

	return S_OK;

}



int CMath::calcFabonacci(int nOp)

{

	if(nOp <= 1)

		return 1;



	return calcFabonacci(nOp - 1)   calcFabonacci(nOp - 2);

}



STDMETHODIMP CMath::Fabonacci(int nOp,int * pret)

{

	*pret=calcFabonacci(nOp);

	return S_OK;

}



CMath::CMath()

{

	m_cRef=0;

}


1.2 COM组件调入大致过程

创建过程示意图如下:



1) COM库初始化 使用CoInitialize COM API函数(客户端)使组件加入套间,关于套间的概念我们以后再讲。(客户端)
2)激活COM(客户端)
3) 通过注册表项将对应的DLL调入COM库中(COM运行环境)
4) 调用COM组件内的DllGetClassObject()导出函数(COM组件)
5)通过类厂返回类厂的接口指针(如果客户端是使用CoCreateInstance创建组件时不需要缓存类厂接口指针,则此步在COM运行环境中完成不返回给客户端,同时马上进入第6步。与此相反,客户端会缓存组件类厂接口指针。此方法当客户需要创建多个实例时很有用。)(COM库)
6)通过类厂接口指针调用CreateInstance创建组件实例。

1.3 DllGetClassObject()实现

在MathCOM.cpp里加入下列语句
#include "math.h"

#include "MathCOM_i.c"

并将MathCOM.cpp里的DllGetClassObject()修改成如下:

/*********************************************************************

 * Function Declare : DllGetClassObject

 * Explain : 

 * Parameters : 

 * REFCLSID rclsid  -- 

 * REFIID riid -- 

 * void **ppv -- 

 * Return : 

 * STDAPI  -- 

 * Author : tulip 

 * Time : 2003-10-29 22:03:53 

*********************************************************************/

STDAPI DllGetClassObject(REFCLSID rclsid ,REFIID riid,void **ppv)

{

	if(rclsid == CLSID_MathCom)

{

	

	return pm_math->QueryInterface(riid,ppv);

}

	return CLASS_E_CLASSNOTAVAILABLE;

}

1.4 客户端

接下来我们写个客户端程序对此COM进行测试。
新建空的名为TestMathCOM一个win32 Console工程加入到MathCOM workspace中。
在TestMathCOM工程里添加一个名为main.cpp的文件,此文件的内容如下:
//main.cpp文件

#include 

#include "../MathCOM.h"//这里请注意路径

#include "../MathCOM_i.c"//这里请注意路径

#include 

using namespace std;



void main(void)

{

	//初始化COM库

	HRESULT hr=::CoInitialize(0);

	ISimpleMath * pSimpleMath=NULL;

	IAdvancedMath * pAdvancedMath=NULL;



	int nReturnValue=0;



	hr=::CoGetClassObject(CLSID_MATHCOM,

				CLSCTX_INPROC,

				NULL,

				IID_ISimpleMath,

				(void **)&pSimpleMath);



	if(SUCCEEDED(hr))

	{

		hr=pSimpleMath->Add(10,4,&nReturnValue);

		if(SUCCEEDED(hr))

			cout << "10   4 = " <QueryInterface(IID_IAdvancedMath, (void **)&pAdvancedMath);

	if(SUCCEEDED(hr))

	{

		hr=pAdvancedMath->Fabonacci(10,&nReturnValue);

		if(SUCCEEDED(hr))

			cout << "10 Fabonacci is " << nReturnValue << endl;	

	}

	pAdvancedMath->Release();

	pSimpleMath->Release();

	::CoUninitialize();

	::system("pause");

	return ;

}
关于如何调试dll请参阅附录A

1.5 小结

到现在我们应该有2个工程和8个文件,具体如下
下载本文示例代码
工程
文件
作用
MathCOM Stdafx.h和stdafx.cpp 预编译文件
  MathCOM.cpp Dll入口函数及其他重要函数定义的地方
  MathCOM.def 模块定义文件
  MathCOM.idl 接口定义文件(在1.2后如果编译的话应该还有四个文件)
  math.h和math.cpp ISmipleMath,IadvancedMath接口的实现类
TestMathCOM Main.cpp MathCOM的客户端,用于测试MathCOM组件
阅读(135) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~