com學習記錄(三)——在Linux環境下完成com元件程式設計

2020-08-14 19:09:36

參考部落格

​ Linux系統並沒有對應的註冊表和IUnknow介面,所以需要自己編寫。

  • 型別定義 type.h

    /*
    	$file:		type.h
    	$date:		2020年8月13日
    	$author:	hehl
    	$describe:	型別定義
    	$other:
    */
    #ifndef __TYPE_H__
    #define __TYPE_H__
    
    typedef long HRESULT;			// 32位元機爲四位元組,64位元機爲八位元組,和指針的型別長度一致
    typedef unsigned long ULONG;
    
    typedef struct _GUID
    {
    	unsigned long Data1;		// 32位元 0x0000-0x0000
    	unsigned short Data2;		// 16位元 0x0000
    	unsigned short Data3;		// 16位元 0x0000
    	unsigned char Data4[8];		// 64位元	0x0000-0x0000-0x0000-0x0000
    }GUID;	// guid	128位元的全域性唯一識別符號(Globally Unique Identifier)
    
    typedef GUID IID;
    
    #define interface struct	// 定義介面爲結構體
    
    #define E_NOINTERFACE 0x80004002L	// 錯誤碼,先不管他
    #define S_OK 0
    
    #endif
    
  • 介面基礎類別 iunknown.h

/*
	$file:		iunknown.h
	$date:		2020年8月13日
	$author:	hehl
	$describe:	介面基礎類別
	$other:
*/
#ifndef __IUNKNOWN_H__
#define __IUNKNOWN_H__

#include "type.h"

interface IUnknown	// interface相當於struct,c語言風格
{
	virtual HRESULT QueryInterface(const IID& iid, void** ppv) = 0;	// 請求介面指針,相當於查詢一個方法
	virtual ULONG AddRef() = 0;		// 增加參照計數
	virtual ULONG Release() = 0;	// 減少參照計數
};	// windows提供的IUnknown類的三個介面,Linux下需要自己實現,windows這裏爲類

#endif
  • GUID和介面標頭檔案 interface.h
/*
	$file:		interface.h
	$date:		2020年8月13日
	$author:	hehl
	$describe:	介面類 + GUID
	$other:
*/
#ifndef __INTERFACE_H__
#define __INTERFACE_H__

#include "iunknown.h"

interface IX : IUnknown		// 這個總感覺怪怪的,先不管這種寫法了,按照c++的寫法應該是繼承把?
{
	virtual void Fx() = 0;	// 純虛擬函式,由派生類實現具體方法
};

interface IY : IUnknown
{
	virtual void Fy() = 0;	// 純虛擬函式,由派生類實現具體方法
};

interface IZ : IUnknown
{
	virtual void Fz() = 0;	// 純虛擬函式,由派生類實現具體方法
};

// 8 4 4 12
// 9F153BC9-E06F-7B23-F4FC-A96B64ABA9D3
extern "C"
{
	const IID IID_IX = { 0x9F153BC9, 0xE06F , 0x7B23 , \
		{0xF4, 0xFC, 0xA9, 0x6B, 0x64, 0xAB, 0xA9, 0xD3} };
	const IID IID_IY = { 0x9F153BC9, 0xE06F , 0x7B23 , \
		{0xF4, 0xFC, 0xA9, 0x6B, 0x64, 0xAB, 0xA9, 0xD4} };
	const IID IID_IZ = { 0x9F153BC9, 0xE06F , 0x7B23 , \
		{0xF4, 0xFC, 0xA9, 0x6B, 0x64, 0xAB, 0xA9, 0xD5} };
	const IID IID_IUnknown = { 0x9F153BC9, 0xE06F , 0x7B23 , \
		{0xF4, 0xFC, 0xA9, 0x6B, 0x64, 0xAB, 0xA9, 0xD6} };
}

#endif
  • 元件實現檔案 component.cpp
/*
	$file:		component.cpp
	$date:		2020年8月13日
	$author:	hehl
	$describe:	元件實現
	$other:
*/
#include <iostream>
#include "type.h"
#include "interface.h"

using namespace std;

bool operator==(const IID& guid1, const IID& guid2)
{
	if (guid1.Data1 != guid2.Data1 || guid1.Data2 != guid2.Data2 || \
		guid1.Data3 != guid2.Data3)
	{
		return false;
	}
	for (int i = 0; i < 8; i++)
	{
		if (guid1.Data4[i] != guid2.Data4[i])
		{
			return false;
		}
	}
	return true;
}

// 額... = =、	類以後還是定義再標頭檔案裏面好點~~先不管了
class CA : public IX
{
private:
	// IUnknown的介面
	virtual HRESULT QueryInterface(const IID& iid, void** ppv);
	virtual ULONG AddRef();
	virtual ULONG Release();

	// IX的介面
	virtual void Fx();

public:
	CA();
	~CA();

private:
	long m_cRef;
};

CA::CA()
{
	cout << "CA::CA()\n";
}

CA::~CA()
{
	cout << "CA::~CA()\n";
}

HRESULT CA::QueryInterface(const IID& iid, void** ppv)
{
	if (iid == IID_IX)
	{
		cout << "CA::QueryInterface() to IX\n";
		*ppv = static_cast<IX*>(this);	// 等價於 *ppv = (IX*)this;
	}
	else if (iid == IID_IUnknown)
	{
		cout << "CA::QueryInterface() to IUnknown\n";
		*ppv = static_cast<IUnknown*>(this);
	}
	else
	{
		cout << "CA::QueryInterface() Interface is not support\n";
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef();
}

ULONG CA::AddRef()
{
	m_cRef++;
	cout << "CA::AddRef() m_cRef:" + m_cRef << endl;
}

ULONG CA::Release()
{
	if (0 == (--m_cRef))
	{
		delete this;
		return 0;
	}
	return m_cRef;
}

void CA::Fx()
{
	cout << "CA::Fx() called\n";
}

// 由動態庫指向此函數
extern "C" IUnknown * CreateInstance()
{
	IUnknown* pI = static_cast<IX*>(new CA);
	pI->AddRef();
	return pI;
}
  • 用戶端 client.cpp
/*
	$file:		client.cpp
	$date:		2020年8月13日
	$author:	hehl
	$describe:	元件實現
	$other:
*/
#include <iostream>
#include "interface.h"
#include "create.h"

int main(int argc, char** argv)
{
	HRESULT hr;
	char name[40] = { 0 };
	CREATE create;

	cout << "Enter the file name of a component to use[lib***.so]:";
	cin >> name;
	cout << "Get an IUnknown pointer." << endl;
	
	IUnknown* pUnknown = create.CallCreateInstance(name);
	if (pUnknown == NULL)
	{
		cout << "CallCreateInstance fail!\n";
		exit(1);
	}
	
	cout << "Get Interface IX.\n";
	IX* pIX = NULL;
	hr = pUnknown->QueryInterface(IID_IX, (void**)&pIX);
	if (hr < 0)
	{
		cout << "Counld not get the IX interface.\n";
	}
	else
	{
		cout << "Success get the IX interface.\n";
		pIX->Fx();
		pIX->Release();
	}
	
	cout << "Release the IUnknown interface.\n";
	pUnknown->Release();
	
	create.closeHandle();
	return 0;

}
  • Makefile
objects=component.o client.o create.o

all : libcmpnt client

libcmpnt:component.o
        g++ -shared -Wl,-soname -O3 -o libcmpnt.so component.o

cmpnt.o : interface.h  iunknown.h  type.h
        g++ -c -fPIC component.cpp  -O3 -o component.o

client : client.o create.o
        g++ -g -rdynamic  -Wl,--no-as-needed -ldl -o client client.o create.o

client.o :
        g++ -g -c client.cpp

create.o :
        g++ -g -c create.cpp

.PYTHON : clean
clean :
        rm -f ${objects}

編譯、執行