COM组件是一种编程规范,它规定了软件编程的一般方法,虽然它由Microsoft公司制定和提出,但是它的规则也可以在Linux下使用,下面是在Linux下实现COM组件的方法。
—-参考《COM技术内幕》一书。
COM实现的技术,主要是C++的虚函数、多继承以及动态链接库(DLL)技术。
COM组件的实现:
类型定义文件type.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#ifndef TYPE_H #define TYPE_H typedef long HRESULT; typedef unsigned long ULONG; typedef struct _GUID { unsigned long Data1; unsigned short Data2; unsigned short Data3; unsigned char Data4[8]; } GUID; typedef GUID IID; #define interface struct #define E_NOINTERFACE 0x80004002L #define S_OK 0 #endif // TYPE_H |
GUID定义文件guids.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include "type.h" extern "C" { extern const IID IID_IX = {0x32bb8320, 0xb41b, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}}; extern const IID IID_IY = {0x32bb8321, 0xb41b, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}}; extern const IID IID_IZ = {0x32bb8322, 0xb41b, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}}; extern const IID IID_IUnknown = {0x32bb8323, 0xb41b, 0x11cf, {0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}}; } |
接口基类:IUnknown.h
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#ifndef IUNKNOWN_H #define IUNKNOWN_H #include "type.h" interface IUnknown { virtual HRESULT QueryInterface(const IID& iid, void** ppv)=0; virtual ULONG AddRef()=0; virtual ULONG Release()=0; }; #endif // IUNKNOWN_H |
接口定义头文件iface.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#ifndef IFACE_H #define IFACE_H #include "IUnknown.h" interface IX:IUnknown { virtual void Fx()=0; }; interface IY:IUnknown { virtual void Fy()=0; }; interface IZ:IUnknown { virtual void Fz()=0; }; extern "C" { extern const IID IID_IX; extern const IID IID_IY; extern const IID IID_IZ; } #endif // IFACE_H |
组件实现文件cmpnt1.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#include <iostream> #include "type.h" #include "iface.h" #include "guids.h" using namespace std; bool operator==(const IID& guid1, const IID& guid2) { if(guid1.Data1 != guid2.Data1) return false; if(guid1.Data2 != guid2.Data2) return false; if(guid1.Data3 != guid2.Data3) return false; for(int i = 0; i < 8; i++) { if(guid1.Data4[i] != guid2.Data4[i]) return false; } return true; } void trace1(const char* msg) { cout << "Component1:\t" << msg << endl; } class CA:public IX { private: //IUnknown interface virtual HRESULT QueryInterface(const IID& iid, void** ppv); virtual ULONG AddRef(); virtual ULONG Release(); //IX interface virtual void Fx() { cout << "FX" << endl; } public: //Constructor CA():m_cRef(0){} //Destructor ~CA(){ trace1("CA Destoryed by itself!"); } private: long m_cRef; }; HRESULT CA::QueryInterface(const IID& iid, void** ppv) { if(iid == IID_IX) { trace1("Return Pointer to IX"); *ppv = static_cast<IX*>(this); } else if(iid == IID_IUnknown) { trace1("Return Pointer to IUnknown"); *ppv = static_cast<IUnknown*>(this); } else { trace1("Interface is not surpport!"); *ppv = NULL; return E_NOINTERFACE; } reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK; } ULONG CA::AddRef() { m_cRef++; } ULONG CA::Release() { if((--m_cRef) == 0) { delete this; return 0; } return m_cRef; } extern "C" IUnknown* CreateInstance() { IUnknown* pI = static_cast<IX*>(new CA); pI->AddRef(); return pI; } |
创建组件
create.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#ifndef CREATE_H #define CREATE_H #include <iostream> #include "IUnknown.h" #include <dlfcn.h> using namespace std; struct CREATE { void* handle; IUnknown* CallCreateInstance(char *name); void closeHandle(); }; #endif // CREATE_H |
create.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#include "create.h" #include <stdlib.h> typedef IUnknown* (*CREATEFUNCPTR)(); IUnknown* CREATE::CallCreateInstance(char* name) { CREATEFUNCPTR CreateInstance; char* error; IUnknown* pUnknown; handle = dlopen(name , RTLD_LAZY); if(!handle) { cout << "Load lib " << name << " fail!" << endl; exit(1); } dlerror(); *(void**)(&CreateInstance) = dlsym(handle, "CreateInstance"); if ((error = dlerror()) != NULL) { cout << error << endl; exit(1); } pUnknown = CreateInstance(); // dlclose(handle); return pUnknown; } void CREATE::closeHandle() { dlclose(handle); } bool operator==(const IID& guid1, const IID& guid2) { if(guid1.Data1 != guid2.Data1) return false; if(guid1.Data2 != guid2.Data2) return false; if(guid1.Data3 != guid2.Data3) return false; for(int i = 0; i < 8; i++) { if(guid1.Data4[i] != guid2.Data4[i]) return false; } return true; } |
客户端实现client1.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
#include <iostream> #include <stdlib.h> #include "iface.h" #include "create.h" #include "guids.h" void trace(const char* msg) { cout << "Client1:\t" << msg << endl; } int main(int argc, char** argv) { HRESULT hr; char name[40]; CREATE create; cout << "Enter the file name of a component to use[lib***.so]:"; cin >> name; cout << endl; trace("Get an IUnknown pointer."); IUnknown* pUnknown = create.CallCreateInstance(name); if(pUnknown == NULL) { trace("CallCreateInstance fail!"); exit(1); } trace("Get Interface IX."); IX* pIX = NULL; hr = pUnknown->QueryInterface(IID_IX, (void**)&pIX); if(hr >= 0) { trace("Success get the IX."); pIX->Fx(); pIX->Release(); } else { trace("Counld not get the IX interface."); } trace("Release the IUnknown interface."); pUnknown->Release(); create.closeHandle(); return 0; } |
CMakeLists.txt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
cmake_minimum_required(VERSION 2.6) set(SRC_CLIENT client1.cpp create.cpp ) add_executable(com_client ${SRC_CLIENT}) set_target_properties(com_client PROPERTIES INSTALL_RPATH "./libs") #include_directories() target_link_libraries(com_client dl ) install(TARGETS com_client RUNTIME DESTINATION bin) set(SRC_COM cmpnt1.cpp ) add_library(cmpnt1 SHARED ${SRC_COM}) install(TARGETS cmpnt1 LIBRARY DESTINATION bin/libs) |
也可以使用Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
objects=cmpnt1.o client1.o create.o all : libcmpnt1 client1 libcmpnt1 : cmpnt1.o g++ -shared -Wl,-soname -O3 -o libcmpnt1.so cmpnt1.o cmpnt1.o : guids.cpp iface.h IUnknown.h type.h g++ -c -fPIC cmpnt1.cpp -O3 -o cmpnt1.o client1 : client1.o create.o g++ -g -rdynamic -ldl -o client1 client1.o create.o -Wl,-rpath,. client1.o : g++ -g -c client1.cpp create.o : g++ -g -c create.cpp .PYTHON : clean clean : rm -f ${objects} |
运行时注意:需要保证当前的环境下环境变量LD_LIBRARY_PATH已经设置。
具体运行方法如下:
1 2 3 4 5 6 7 8 9 10 11 |
[root@localhost cust_comp]# export LD_LIBRARY_PATH=. [root@localhost cust_comp]# ./client1 Enter the file name of a component to use[lib***.so]:libcmpnt1.so Client1: Get an IUnknown pointer. Client1: Get Interface IX. Component1: Return Pointer to IX Client1: Success get the IX. FX Client1: Release the IUnknown interface. Component1: CA Destoryed by itself! |
发表评论
要发表评论,您必须先登录。