建立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; }
相关推荐
射频芯片的关键组件包括RF收发器、功率放大器、低噪声放大器、滤波器、射频开关、天线调谐开关等。 在4G通信技术中,一个典型的手机需要支持多达40个频段,每个频段均需对应的射频前端器件,例如滤波器、功率放大器...
射频芯片作为移动通信设备中不可或缺的核心组件,近年来随着5G技术的不断推广和应用,其市场规模和战略意义愈发凸显。射频芯片是能够处理射频信号与数字信号转换的电子元件,主要用于无线通信设备中,涵盖了包括RF...
而驱动这些显示设备的关键组件——显示驱动芯片,是整个面板产业链的核心所在。本文将深入探讨显示驱动芯片,特别是国内面板国产化的关键环节,面板国产化最后1公里。 显示驱动芯片市场正面临着需求与供应的双重...
光模块产业链梳理系列二:光芯片环节 本文档对光模块产业链梳理系列二:光芯片环节进行了详细的分析和介绍,涵盖了光芯片的定义、分类、应用场景、市场需求、主要公司、技术水平、投资建议等方面。 光芯片是光模块...
LCD显示驱动IC行业分析:LCD显示驱动IC是大尺寸显示面板的关键组件。在LCD驱动IC中,低温多晶硅(LTPS)TFT-LCD技术是目前主流的技术。 OLED显示驱动IC行业分析:OLED驱动IC作为中小尺寸平板显示的主流,目前正面临...
这篇“走进芯时代系列深度之六十九射频国产化——射频国产化迈向纵深,供应格局优化进行时”的报告,深入剖析了中国射频产业的发展现状与未来趋势。报告的36页内容可能涵盖了以下几个核心知识点: 1. 射频技术简介...
Access 2003是微软公司开发的一款关系型数据库管理系统,是Office 2003套件中的重要组件。这款软件以其用户友好的界面、强大的数据处理能力以及灵活的自定义功能,深受广大用户喜爱。在"走进Access 2003中文版"这本...
它包含了多个关键组件,如功率放大器(PA)、低噪声放大器(LNA)、混频器(Mixer)、滤波器(Filter)以及射频开关(RF Switch)等。这些组件共同协作,确保无线信号的高效传输和接收,实现清晰、稳定的通信质量。 ...
根据《走进“芯”时代系列深度之四十六“新能源芯”:乘碳中和之风,基础元件腾飞》报告,预计到2050年,新能源如光伏和风电将占国内发电总量的一半以上。这不仅意味着传统能源的比重下降,还预示着对电力电子设备,...
在深入分析这份标题为“走进‘芯’时代系列深度之四十三‘显示驱动’:显示驱动芯—面板国产化最后1公里”的报告之前,我们需要先理解报告中所涉及的几个重要概念和知识点。 1. 显示驱动芯与面板国产化 显示驱动...
手册中硬件部分首先从CPU的物理构造着手,带领用户走进Q系列CPU的内部世界。这包括了详细阐述多核架构的设计理念,及其带来的并行处理优势。每个核心所配备的独立缓存系统,不仅能提升CPU的处理速度,还能在多任务...
Oracle服务是指在安装过程中创建的一系列服务组件,用于支持Oracle数据库的运行。主要包括: 1. **Oracle数据库服务**:负责管理数据库实例,提供数据存储和检索服务。 2. **监听器服务**:监听网络连接请求,转发...
总之,ASP.NET AJAX入门系列教程将带你走进AJAX的世界,通过一系列实例和讲解,让你掌握使用ASP.NET AJAX构建动态Web应用程序的技巧,为后续的Web开发打下坚实基础。无论是对于初学者还是有经验的开发者,这都是一个...
【走进J2ME移动开发】 J2ME,全称Java 2 Micro Edition,是Java平台的一个子集,专为资源有限的嵌入式设备和移动设备设计,如手机、PDA和数字电视等。J2ME由Java社区组织(JCP)制定一系列规范,包括Java ...
这个行业的核心在于光伏组件的制造,包括硅料提炼、硅片切割、电池片生产以及组件组装等环节。近年来,随着技术进步和成本降低,光伏产业在全球范围内得到了快速发展。 【政策影响】 政策是光伏产业发展的重要驱动...
### 走进FPGA SoC设计:京微雅格FPGA芯片及开发板使用剖析 #### 第一章 不可阻挡的SoC趋势 ##### 1.1 什么是SoC? System on Chip(SoC)是指将计算机系统的主要组件集成在一块芯片上的技术。它包含了中央处理器...
它包含了一系列预先设计并优化的容器(如vector、list、set等)、迭代器、算法和函数对象,这些组件可以无缝集成到C++程序中,提供高效且可复用的代码。STL的另一个关键特性是其跨平台兼容性,同一段STL代码在不同的...
射频前端主要包括发射端模组、接收端模组、滤波器、传导开关、天线开关和低噪声放大器等组件。发射端模组市场规模最大,预计达122亿美元,而接收端模组、滤波器等也有显著的市场份额。这些组件的数量和复杂性随着...
随着智能手机支持的通信频段的增多和下载速率的提升,手机天线已经从单一的功能性器件演变为由多个元器件和零组件构成的完整天线系统。天线数量的增加成为5G进程中的一个趋势。在4G时代,主流手机采用2天线设计,而...