走进COM组件系列(二)

建立COM组件服务器

 

其他内容请浏览COM+分类

 

首先看下我们的目录结构:生成DLL的Project


 

 

这一节需要我们自己定义接口(发布接口),利用MIDL 接口定义语言

 

COM服务器的三个关键要求:

接口:客户机通过接口与服务器进行通信;

组件类:提供所定义接口的实现方法;

类型库:编译的IDL文件向支持的COM环境传送接口信息。

 

首先在 vs中 建立IDL 文件:

代码如下:

import "oaidl.idl";
import "ocidl.idl";

[ object,
	uuid(19900225-0700-0000-0000-000000000001)
]
interface IY : IUnknown {
	HRESULT Fy();
};

[ object,
	uuid(19900225-0800-0000-0000-000000000001)
]
interface IZ : IUnknown {
	HRESULT Fz();
};

[ uuid(19900225-0900-0000-0000-000000000001),
	version(1.0)
]
library CBLib {
	importlib("stdole32.tlb");

	[ uuid(19900225-0a00-0000-0000-000000000001)
	]
	coclass CB {
		[default] interface IY;
		[source] interface IZ;
	};
};

 

这里需要产生四个GUID,分别对应两个接口ID(IID),类型库ID(LIBID)和CoClassID(CLSID)。

右键点击该文件,选择编译,生成三个文件,


 将 除了划红线的文件, 剩下两个文件加入编译器中,创建Generated文件夹。

注: 若加入划红线的文件,将会产生 很多关于DLL的编译错误。

 

在自动生成的文件CB_i.c 中,我们可以看到系统已经帮我们生成了组件和接口的CSLID。


 

在CB_h.h 中可以看到,已经发布的接口和抽象方法


 

接下来我们需要实现组件的相关方法和类工厂:

组件类: 实现Fy,Fz,QueryInterface,AddRef,Release方法

class CB: public IY, public IZ{
public:
	// IUnknown implementation
	virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
	virtual ULONG __stdcall AddRef();
	virtual ULONG __stdcall Release();

	virtual HRESULT __stdcall Fy();
	virtual HRESULT __stdcall Fz();

	CB();
	~CB();
private:
	long m_cRef;
};

 类工厂: 需要继承IClassFactory

class CFactory : public IClassFactory {
public:
	virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
	virtual ULONG __stdcall AddRef();
	virtual ULONG __stdcall Release();

	virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
																					const IID& IID,
																					void** ppv);
	virtual HRESULT __stdcall LockServer(BOOL block);

	CFactory() : m_cRef(1) {}
	~CFactory() {
		trace("class CFactory: destroyed...");
	}
private:
	long  m_cRef;
};

 

然而,我们仍然需要将其称为合法的DLL COM服务器,要实现的函数包括

DllMain,DllGetClassObject,DllCanUnloadNow,DllRegisterServer,DllUnRegisterServer,

这些都是API式函数,是直接调用,而不是通过COM接口调用

实现如下:

STDAPI DllCanUnloadNow() {
	if((g_cComponents == 0) && (g_cServerLock == 0)) {
		return S_OK;
	}else {
		return S_FALSE;
	}
}

STDAPI DllGetClassObject(const IID &clsid, const IID &riid, void** ppv) {
	trace("DllGetClassObject: create class factory");
	
	if(clsid != CLSID_CB) {
		return CLASS_E_CLASSNOTAVAILABLE;
	}

	CFactory* pFactory = new CFactory;
	if(pFactory == NULL) {
		return E_OUTOFMEMORY;
	}

	HRESULT hr = pFactory->QueryInterface(riid, ppv);
	pFactory->Release();
	return hr;
	
}

STDAPI DllRegisterServer() {
	return S_OK;
}

STDAPI DllUnregisterServer() {
	return S_OK;
}

BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) {
	myHinstance = (HINSTANCE)hinstDLL;
	return TRUE;
}

值得注意的是DllGetClassObject 这个函数,有了这个方法才能在客户端与服务器端的通讯中得到类工厂。

并在CB.DEF中,定义DLL输出:

LIBRARY	"ComTestOne"

EXPORTS
	DllCanUnloadNow		PRIVATE
	DllGetClassObject	PRIVATE
	DllRegisterServer	PRIVATE
	DllUnregisterServer	PRIVATE

 

最后,我们可以手动添加注册表,在注册表编辑器中我们添加组件的CSLID和dll 文件名:


 

至此,我们完成了服务器端。

 

在客户端,我们仅仅需要做的就是连接组件,在组件中得到接口进行调用即可:

int main() {

	CoInitialize(NULL);

	IY* iy = NULL;
	HRESULT hr = CoCreateInstance(CLSID_CB, NULL, CLSCTX_INPROC_SERVER, IID_IY, (void**)&iy);

	if(FAILED(hr)) {
		MessageBox(NULL, L"could not create instance", L"hello", MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
	} else {
		iy->Fy();
		iy->Release();
	}

	cout << "--------------------------------------------------" << endl;

	IY* iy1 = NULL;
	HRESULT hr2 = CoCreateInstance(CLSID_CB, NULL, CLSCTX_INPROC_SERVER, IID_IY, (void**)&iy1);

	if(FAILED(hr2)) {
		MessageBox(NULL, L"could not create instance", L"hello", MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
	} else {
		iy1->Fy();
		iy1->Release();
	}

	CoUninitialize();

	getchar();
	return 0;
}

 

CoCreateInstance(CLSID_CB, NULL, CLSCTX_INPROC_SERVER, IID_IY, (void**)&iy);

是最为重要的,我们必须了解其内部的工作原理,请参考:

http://benworld.iteye.com/blog/1988445

 

另外,需要把生成的ComTestOne.dll文件 拷贝到 客户端的DEBUG目录下。

 

运行效果如下:


 

在构建第一个实例时,会有划红线的重复现象出现,而构建第二个时则没有。

 

上传了 项目实例代码供参考。

 

附代码:CB.cpp

#include "CB.h"
#include <iostream>

static long g_cServerLock = 0;
static long g_cComponents = 0;
static HINSTANCE myHinstance;

CB::CB() : m_cRef(1){
	InterlockedIncrement(&g_cComponents);
}

CB::~CB() {
	InterlockedDecrement(&g_cComponents);
	trace("class CB: destroyed...");
}

HRESULT __stdcall CB::QueryInterface(const IID& iid, void** ppv) {
	if(iid == IID_IUnknown){
		trace("QueryInterface: Return pointer to IUnknown");
		*ppv = static_cast<IY *>(this);
	} 
	
	else if(iid == IID_IY) {
		trace("QueryInterface: Return pointer to IY");
		*ppv = static_cast<IY *>(this);
	} 
	
	else if(iid == IID_IZ) {
		trace("QueryInterface: Return pointer to IZ");
		*ppv = static_cast<IZ *>(this);
	}

	else {
		trace("QueryInterface: Return pointer to IUnknown");
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	reinterpret_cast<IUnknown *> (*ppv)->AddRef();
	return S_OK;
}

ULONG __stdcall CB::AddRef() {
	std::cout << "CB: m_Ref + 1 " << std::endl;
	return InterlockedIncrement(&m_cRef);
}

ULONG __stdcall CB::Release() {
	std::cout << "CB: m_Ref - 1 " << std::endl;
	if(InterlockedDecrement(&m_cRef) == 0) {
		delete this;
		return 0;
	}
	return m_cRef;
}

HRESULT __stdcall CB::Fy() {
	std::cout << "Fy" << std::endl;
	return S_OK;
}

HRESULT __stdcall CB::Fz() {
	std::cout << "Fz" << std::endl;
	return S_OK;
}

// class Factory IUnknown implementation
HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv) {
	if((iid == IID_IUnknown) || (iid == IID_IClassFactory)) {
		// 将CFactory 转化为 ClassFactory
		*ppv = static_cast<IClassFactory*>(this);
	} else {
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef();
	return S_OK;
}

ULONG __stdcall CFactory::AddRef() {
	std::cout << "CFactory: m_Ref + 1 " << std::endl;
	return InterlockedIncrement(&m_cRef);
}

ULONG __stdcall CFactory::Release() {
	std::cout << "CFactory: m_Ref - 1 " << std::endl;
	if(InterlockedDecrement(&m_cRef) == 0) {
		delete this;
		return 0;
	}
	return m_cRef;
}

HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter,
																					const IID& IID,
																					void** ppv)
{
	trace("class factory : create component");
	if(pUnknownOuter != NULL) {
		return CLASS_E_NOAGGREGATION;
	}

	CB * pa = new CB;
	if(pa == NULL) {
		return E_OUTOFMEMORY;
	}

	HRESULT hr = pa->QueryInterface(IID, ppv);
	pa->Release();
	return hr;
}

HRESULT __stdcall CFactory::LockServer(BOOL bLock) {
	if(bLock) {
		InterlockedIncrement(&g_cServerLock);
	} else {
		InterlockedDecrement(&g_cServerLock);
	}
	return S_OK;
}


STDAPI DllCanUnloadNow() {
	if((g_cComponents == 0) && (g_cServerLock == 0)) {
		return S_OK;
	}else {
		return S_FALSE;
	}
}

STDAPI DllGetClassObject(const IID &clsid, const IID &riid, void** ppv) {
	trace("DllGetClassObject: create class factory");
	
	if(clsid != CLSID_CB) {
		return CLASS_E_CLASSNOTAVAILABLE;
	}

	CFactory* pFactory = new CFactory;
	if(pFactory == NULL) {
		return E_OUTOFMEMORY;
	}

	HRESULT hr = pFactory->QueryInterface(riid, ppv);
	pFactory->Release();
	return hr;
	
}

STDAPI DllRegisterServer() {
	return S_OK;
}

STDAPI DllUnregisterServer() {
	return S_OK;
}

BOOL WINAPI DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) {
	myHinstance = (HINSTANCE)hinstDLL;
	return TRUE;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值