本文由导学宝转自:http://blog.csdn.net/chenspnjupt1234/article/details/5923672
好久没有写代码啦,今天翻到大学时候写的COM组件,当时那个叫崇拜COM技术啊。不过发现,工作中根本没啥用处。反正没事干,想想把COM组件在Linux环境下,实现一下。
COM组件是一种编程规范,它规定了软件编程的一般方法,虽然它由Microsoft公司制定和提出,但是它的规则也可以在Linux下使用,下面是在Linux下实现COM组件的方法。
----参考《COM技术内幕》一书。
COM实现的技术,主要是C++的虚函数、多继承以及动态链接库(DLL)技术。
COM组件的实现:
--类型定义文件type.h
#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
--GUID定义文件guids.cpp
#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
#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
--接口定义头文件iface.h
#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
--组件实现文件cmpnt1.cpp
#include <iostream>
#include "type.h"
#include "iface.h"
#include "guids.cpp"
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
#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.cpp
#include "create.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
#include <iostream>
#include "iface.h"
#include "create.h"
#include "guids.cpp"
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;
}
--Makefile
objects=cmpnt1.o client1.o create.o
all : libcmpnt1 client1
libcmpnt1 : cmpnt1.o
g++ -shared -W1,-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
client1.o :
g++ -g -c client1.cpp
create.o :
g++ -g -c create.cpp
.PYTHON : clean
clean :
rm -f ${objects}
运行时注意:需要保证当前的环境下环境变量LD_LIBRARY_PATH已经设置。
具体运行方法如下:
[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!