分类: C/C++
2008-03-18 15:00:44
/*@**#---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;
}

#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 客户端//main.cpp文件 #include关于如何调试dll请参阅附录A#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 ; }
|
工程 |
文件 |
作用 |
| 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组件 |
2.2 增加IClassFactory的实现
此次我们将修改的文件如下
|
工程名 |
文件名 |
修改属性 |
| MathCOM | MathCOM.cpp | 修改 |
| MathFactory.h和MathFactory.cpp | 新增 | |
| TestMathCOM | Main.cpp | 修改 |
2.2.1 MathCOM.cpp
#include "math.h"
#include "MathCOM_i.c"
#include "MathFactory.h"
//////////////////////////////////////////////////////
// 服务器锁, 如果标志为S_OK,就可以卸载当前组件的服务器,
// 关于引用计数及服务器跟COM对象的关系,后绪章节再讲解
LONG g_cObjectAndLocks=0;
//standard self-registration table
const char * g_RegTable[][3]={………………….
…………………………
STDAPI DllGetClassObject(REFCLSID rclsid ,REFIID riid,void **ppv)
{
if(rclsid==CLSID_MATHCOM)
{
CMathFactory *pFactory = new CMathFactory; // 创建类厂对象
if(pFactory == NULL)
return E_OUTOFMEMORY;
///////////////////////////////////////////
// 一般情况下COM希望用户只查询IClassFactory,
// IClassFactory2及IUnknow
HRESULT hr = pFactory->QueryInterface(iid, ppv);
return hr;
}
return CLASS_E_CLASSNOTAVAILABLE;
}
STDAPI DllCanUnloadNow(void)
{
return (g_cObjectAndLocks==0)?S_OK:E_FAIL;
}
2.2.2 MathFactory.h // MathFactory.h: interface for the CMathFactory class. // ////////////////////////////////////////////////////////////////////// #ifndef MATHFACTORY_H #define MATHFACTORY_H #include2.2.3 MathFactory.cppclass CMathFactory :public IClassFactory { public: CMathFactory():m_cRef(0){} //IUnknow Method STDMETHODIMP QueryInterface(REFIID,void**); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); //IClassFactory Method STDMETHODIMP CreateInstance(IUnknown * ,REFIID ,void **); STDMETHODIMP LockServer(BOOL fLock); protected: LONG m_cRef; }; #endif
// MathFactory.cpp: implementation of the CMathFactory class.
//
//////////////////////////////////////////////////////////////////////
#include "math.h"
#include "MathFactory.h"
extern LONG g_cObjectAndLocks;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CMathFactory::AddRef(void)
{
return InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG) CMathFactory::Release(void)
{
return ::InterlockedDecrement(&m_cRef);
}
STDMETHODIMP CMathFactory::QueryInterface(REFIID riid,void ** ppv)
{
*ppv=NULL;
if(riid==IID_IUnknown||riid==IID_IClassFactory)
{
*ppv=static_cast(this);
reinterpret_cast(*ppv)->AddRef();
return S_OK;
}
else
return (*ppv=0),E_NOINTERFACE;
}
STDMETHODIMP CMathFactory::CreateInstance(IUnknown * pUnkOuter,REFIID riid,void ** ppv)
{
*ppv=NULL;
// 现在不支持聚合
if(pUnkOuter!=NULL)
return CLASS_E_NOAGGREGATION;
CMath * pMath=new CMath;
if(pMath==NULL)
return E_OUTOFMEMORY;
HRESULT hr=pMath->QueryInterface(riid,ppv);
if(FAILED(hr))
delete pMath;
return hr;
}
STDMETHODIMP CMathFactory::LockServer(BOOL fLock)
{
if(fLock)
::InterlockedIncrement(&g_cObjectAndLocks);
else
::InterlockedDecrement(&g_cObjectAndLocks);
return NOERROR;
}
2.2.4 main.cpp #include2.3 小结#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; //如果还想用CoCreateInstance()得到接口指针,请如下使用先传一个IClassFactory接口 /*************** 这里请注意 *****************/ // 方法一 hr = ::CoCreateInstance(CLSID_MATHCOM, CLSCTX_INPROC, NULL, IID_ISimpleMath, (void*)&pSimpleMath); /////////////////////////////////////////////////////////////////////// // 这个方法的好处是不需要太多的代码, 让COM来处理真正的类厂创建对象的过程. // 同时这个函数的改进版CoCreateInstanceEx在分布式对象应用中可以一次取回多 // 个接口指针. 避免过多的在网络上浪费时间关于这个函数的用法我也会在以后的 // 章节中讲解. 您也可以参考MSDN或相关书藉 // 方法二 IClassFactory * pClassFactory=NULL; // 类厂接口指针 // 获取对象的类厂接口指针 hr=::CoGetClassObject(CLSID_MATHCOM, CLSCTX_INPROC, NULL, IID_IClassFactory, (void**)&pClassFactory); // 真正创建对象 hr = pClassFactory->CreateInstance(NULL,IID_ISimpleMath,(void**)&pSimpleMath); // 此方法的好处在于可以一次创建多个对象, 不需要 // 下面测试 IDispatch 接口 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(); return ; }
关于IDispatch接口请参阅MSND文档或<
3.2 支持派发接口的MathCOM组件
要让我们的MathCOM组件支持双接口,需要修改如下文件
|
工程名 |
文件名 |
| MathCOM | MathCOM.idl |
| Math.h和Math.cpp | |
| TestMathCOM | Main.cpp |
3.2.1修改MathCOM.idl
MathCOM.idl文件需要修改三个地方。
1) 增加daul属性,以便表明我们的接口是双接口。
2) 将接口的基类由IUnknow接口变成IDispatch接口
3) 在接口的每个方法加上序号属性
修改后的MathCOM.idl如下(请自己找出修改的地方)
// MathCOM.idl : IDL source for MathCOM.dll
//
// This file will be processed by the MIDL tool to
// produce the type library (MathCOM.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
uuid(FAEAE6B7-67BE-42a4-A318-3256781E945A),
helpstring("ISimpleMath Interface"),
object,
dual, // 这个标识我们前面没遇到过。
pointer_default(unique)
]
interface ISimpleMath : IDispatch
{
[id(1)] HRESULT Add([in]int nOp1,[in]int nOp2,[out,retval]int * pret);
[id(2)] HRESULT Subtract([in]int nOp1,[in]int nOp2,[out,retval]int * pret);
[id(3)] HRESULT Multiply([in]int nOp1,[in]int nOp2,[out,retval] int * pret);
[id(4)] HRESULT Divide([in]int nOp1,[in]int nOp2,[out,retval]int * pret);
};
[
uuid(01147C39-9DA0-4f7f-B525-D129745AAD1E),
helpstring("IAdvancedMath Interface"),
object,
dual,
pointer_default(unique)
]
interface IAdvancedMath : IDispatch
{
[id(1)] HRESULT Factorial([in]int nOp1,[out,retval]int * pret);
[id(2)] HRESULT Fabonacci([in]int nOp1,[out,retval]int * pret);
};
[
uuid(CA3B37EA-E44A-49b8-9729-6E9222CAE844),
version(1.0),
helpstring("MATHCOM 1.0 Type Library")
]
library MATHCOMLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(3BCFE27E-C88D-453C-8C94-F5F7B97E7841),
helpstring("MATHCOM Class")
]
coclass MATHCOM
{
[default] interface ISimpleMath;
interface IAdvancedMath;
};
};
3.2.2 修改math.h文件//前面相同
CMath();
//IUnknown Method
STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
STDMETHOD_(ULONG, AddRef)();
STDMETHOD_(ULONG, Release)();
//IDispatch Method
STDMETHOD(GetTypeInfoCount)(UINT * pit){ return E_NOTIMPL;}
STDMETHOD(GetTypeInfo)(UINT it,LCID lcid,ITypeInfo **ppti){ return E_NOTIMPL; }
STDMETHOD(GetIDsOfNames)(REFIID riid,
OLECHAR ** pNames,
UINT nNames,
LCID lcid,
DISPID * pdispids){ return E_NOTIMPL; }
STDMETHOD(Invoke)(DISPID id,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pd,
VARIANT * pVarResult,
EXCEPINFO * pe,
UINT *pu);
// 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);
//后面相同
3.2.3 修改math.cpp文件//前面相同
CMath::CMath()
{
m_cRef=0;
}
/*********************************************************************
* Function Declare : CMath::Invoke
* Explain : IDispatch接口的Invoke方法
* Parameters :
* DISPID id -- 方法的调度ID(请与idl中序号相比较)
* REFIID riid -- 接口IID
* LCID lcid -- 语言ID
* WORD wFlags --
* DISPPARAMS * pd -- 传入参数结构(具体结构请参阅MSDN或本质论p294)
* VARIANT * pVarResult -- 出参(VARIANT请参阅MSDN文档或<<深入解析ATL>>p56
* EXCEPINFO * pe -- 异常(一般为NULL)
* UINT * pu --
* Return :
* STDMETHODIMP --
* Author : tulip
* Time : 2003-10-30 15:56:37
*********************************************************************/
STDMETHODIMP CMath::Invoke(DISPID id,
REFIID riid,
LCID lcid,WORD wFlags,
DISPPARAMS * pd,
VARIANT * pVarResult,
EXCEPINFO * pe,
UINT * pu)
{
if(riid==IID_ISimpleMath)
{
if(1==id)
return Add(pd->rgvarg[0].intVal,pd->rgvarg[1].intVal,&pVarResult->intVal);
else if (2==id)
return Subtract(pd->rgvarg[0].intVal,pd->rgvarg[1].intVal,&pVarResult->intVal);
else if (3==id)
return Multiply(pd->rgvarg[0].intVal,pd->rgvarg[1].intVal,&pVarResult->intVal);
else if (4==id)
return Divide(pd->rgvarg[0].intVal,pd->rgvarg[1].intVal,&pVarResult->intVal);
else
return E_FAIL;
}
else if (riid==IID_IAdvancedMath)
{
if(1 == id)
return Factorial(pd->rgvarg[0].intVal,&pVarResult->intVal);
else if (2 == id)
return Fabonacci(pd->rgvarg[0].intVal,&pVarResult->intVal);
else
return E_FAIL;
}
else
return E_NOINTERFACE;
}
#include#include "../MathCOM.h" #include "../MathCOM_i.c" #include using namespace std; #include void main(void) { ///////////////////////////////////////////////// // 初始化COM库,这里的真正含义是把COM加入适当的套间, // 关于套间的概念及其它相关概念会在后绪文章中讲解。 HRESULT hr = ::CoInitialize(NULL); ISimpleMath * pSimpleMath=NULL; IAdvancedMath * pAdvancedMath=NULL; IDispatch * pDispatch=NULL; // 派发接口指针 int nReturnValue=0; hr = ::CoCreateInstance(CLSID_MATHCOM, CLSCTX_INPROC, NULL, IID_ISimpleMath, (void*)&pSimpleMath); ///////////////////////// // 下面测试IDispatch接口 // pSimpleMath->QueryInterface(IID_IDispatch,(void**)&pDispatch); if(SUCCEEDED(hr)) { cout<<"下面进行IDispatch接口"< Invoke(0x1, IID_ISimpleMath, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL); if(SUCCEEDED(hr)) cout << "10 + 4 = " < Invoke(0x2, IID_IAdvancedMath, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult2, NULL, NULL); if(SUCCEEDED(hr)) cout << "10 Fabonacci is " < 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(); pDispatch->Release(); ::CoUninitialize(); return ; }
五 参考资料
COM方面 (在COM方面除潘爱明的作著可以看看外,国内其他作者的东西都是垃圾。)
<
<
<
ATL方面
<<深入解析ATL>> (相当于COM界里的<
MSDN
MSJ 杂志的<
MSDN Dr.GUI online 具体位置在MSND/Welcome to the msnd library/
msnd resource/selected online columns/Dr.GUI online/
MSDN SDK 文档 具体位置 MSDN/Platform SDK Documentation/Component Servies
MSDN 的技术文章 位置 MSDN/Technical Articles/Component Object Model
MSDN BackGrounders 有一些相当于白皮书之类的东西。