com学习记录(四)——在Linux环境下完成com组件编程分离服务端(动态库)客户端(可执行程序)

14 篇文章 1 订阅

com学习记录(一)——基本概念
com学习记录(二)——使用vs2019完成windows下的com组件编程
com学习记录(三)——在Linux环境下完成com组件编程
com学习记录(四)——在Linux环境下完成com组件编程分离服务端(动态库)客户端(可执行程序)

文件结构

同级目录下两个文件夹,一个lib文件夹用于服务端动态库生成,一个client文件夹用于客户端测试编写程序
Linux下没有unknwn.h系统头文件,所以在Linux环境编写com组件时应该自己定义这个类和接口
此项目分为两个文件夹,分别是服务端(生成动态库)和客户端(可执行文件)

**/com
************/lib
************************************base.h
************************************IUnknow.h
************************************interface.h
************************************component.h
************************************component.cpp
************************************Makefile

************/lib
************************************base.h
************************************IUnknow.h
************************************interface.h
************************************create.h
************************************create.cpp
************************************client.cpp
************************************Makefile
在这里插入图片描述

服务端(动态库)

自定义的IUnknown基类:IUnknow.h
/*
	$file:		IUnknow.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	自定义的IUnknown基类
	$other:
*/
#ifndef __IUNKNOW_H__
#define __IUNKNOW_H__

#include "base.h"

class IUnknown
{
public:
	virtual HRESULT QueryInterface(const IID& iid, void** ppv) = 0;	// 第一个是强转,第二是一个指向指针数组的指针
	virtual ULONG AddRef() = 0;		// 增加引用计数
	virtual ULONG Release() = 0;	// 减少引用计数
};

#endif
基本数据类型:base.h
/*
	$file:		base.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	基本数据类型
	$other:
*/
#ifndef __BASE_H__
#define __BASE_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 E_NOINTERFACE 0x80004002L	// 错误码,先不管他
#define S_OK 0

#endif
接口:interface.h
/*
	$file:		interface.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	接口类
	$other:
*/
#ifndef __INTERFACE_H__
#define __INTERFACE_H__

#include "IUnknow.h"

class IA : public IUnknown
{
public:
	virtual void show_A() = 0;
};

const IID g_COM_A_IID = { 0x9F153BC9, 0xE06F , 0x7B23 , \
 		{0xF4, 0xFC, 0xA9, 0x6B, 0x64, 0xAB, 0xA9, 0xD3} };

#endif
组件类定义:component.h
/*
	$file:		component.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	组件类
	$other:
*/
#ifndef __COMPONENT_H__
#define __COMPONENT_H__

#include <iostream>
#include "IUnknow.h"
#include "interface.h"

class com_A : public IA
{
public:
	com_A();
	~com_A();
	
private:
	// IUnknown的接口
	virtual HRESULT QueryInterface(const IID& iid, void** ppv);
	virtual ULONG AddRef();
	virtual ULONG Release();

	// 组件的接口
	virtual void show_A();
	long m_cRef;
};

extern "C"
{
	void test();
 	IUnknown* CreateInstance();
}

// 重载运算符,用于比较IID是否相等
bool operator==(const IID& guid1, const IID& guid2);
#endif
组件实现:component.cpp
/*
	$file:		component.cpp
	$date:		2020年8月17日
	$author:	hehl
	$describe:	组件实现
	$other:
*/
#include "component.h"
using namespace std;

com_A::com_A()
{
	cout << "com_A::com_A()" << endl;
}

com_A::~com_A()
{
	cout << "com_A::~com_A()" << endl;
}

HRESULT com_A::QueryInterface(const IID& iid, void** ppv)
{
	if (iid == g_COM_A_IID)
	{
		cout << "com_A::QueryInterface() to comA" << endl;
		*ppv = static_cast<com_A*>(this);	// 等价于 *ppv = (IX*)this;
	}
	else
	{
		cout << "com_A::QueryInterface() Interface is not support" << endl;
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	reinterpret_cast<IUnknown*>(*ppv)->AddRef();
	return S_OK;
}

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

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

void com_A::show_A()
{
	cout << "-----------------com_A::show_A()-----------------" << endl;
}

void test()
{
	cout << "call test\n";
}

IUnknown* CreateInstance()
{
	cout << "CreateInstance() in 1.2\n";
	//IUnknown* ptr = static_cast<IA*>(new com_A);
	IUnknown* ptr = new com_A();
	if(ptr == NULL)
	{
		cout << "new error\n";
		return NULL;
	}
	ptr->AddRef();
	return ptr;
}


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;
}
生成动态库的Makefile:
all:
	g++ -shared -fPIC  -Xlinker --unresolved-symbols=ignore-in-shared-libs component.cpp -o libcom.so

-shared: 生成动态库
-fPIC: 加载时根据加载到的位置再次重定位
-Xlinker --unresolved-symbols=ignore-in-shared-libs: 检查函数未定义
在生成的.so目录下执行 ldd -r libcom.so 命令查看生成的so是否存在符号未定义的内容

客户端(可执行程序测试)

基本数据类型:base.h(同服务端)
/*
	$file:		base.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	基本数据类型
	$other:
*/
#ifndef __BASE_H__
#define __BASE_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 E_NOINTERFACE 0x80004002L	// 错误码,先不管他
#define S_OK 0

#endif
自定义的IUnknown基类:IUnknow.h(同服务端)
/*
	$file:		IUnknow.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	自定义的IUnknown基类
	$other:
*/
#ifndef __IUNKNOW_H__
#define __IUNKNOW_H__

#include "base.h"

class IUnknown
{
public:
	virtual HRESULT QueryInterface(const IID& iid, void** ppv) = 0;	// 第一个是强转,第二是一个指向指针数组的指针
	virtual ULONG AddRef() = 0;		// 增加引用计数
	virtual ULONG Release() = 0;	// 减少引用计数
};

#endif
接口类:interface.h(同服务端,开发时需要提供此接口文件,并且保证一致性)
/*
	$file:		interface.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	接口类
	$other:
*/
#ifndef __INTERFACE_H__
#define __INTERFACE_H__

#include "IUnknow.h"

class IA : public IUnknown
{
public:
	virtual void show_A() = 0;
};

const IID g_COM_A_IID = { 0x9F153BC9, 0xE06F , 0x7B23 , \
 		{0xF4, 0xFC, 0xA9, 0x6B, 0x64, 0xAB, 0xA9, 0xD3} };

#endif
创建组件接口类:create.h
/*
	$file:		create.h
	$date:		2020年8月17日
	$author:	hehl
	$describe:	创建组件接口类
	$other:
*/
#ifndef __CREATE_H__
#define __CREATE_H__

#include <iostream>
#include <dlfcn.h>
#include <string>
#include "IUnknow.h"
using namespace std;

class CREATE
{
public:
	void* handle;							// 动态库句柄
	IUnknown* CreateIunknownkInstance();	// 创建组件的接口,在动态库中调用函数返回对象指针
	void closeHandle();						// 关闭动态库句柄
};

#endif
创建组件接口实现:create.cpp
/*
	$file:		create.cpp
	$date:		2020年8月17日
	$author:	hehl
	$describe:	创建组件接口实现
	$other:
*/

#include "create.h"
// #define TEST_CALL_LIB

IUnknown* CREATE::CreateIunknownkInstance()
{

#ifdef TEST_CALL_LIB
	void (*pfunTest)();
#endif

	IUnknown* (*pfunIUnknown)();
	IUnknown* pIUnknown;
	char *error;
	handle = dlopen("../lib/libcom.so", RTLD_LAZY); 	// 打开动态库,路径根据动态库实际位置添加
	if(handle == NULL)
	{
		cout << "dlopen error" << endl;
		return NULL;
	}
	cout << "dlopen  success" << endl;

#ifdef TEST_CALL_LIB
	pfunTest = (void(*)())dlsym(handle, "test");
	if((error = dlerror()) != NULL)
	{
		cout << "dlsym error:" << error << endl;
		dlclose(handle);
		return NULL;
	}
	pfunTest();
#endif

	pfunIUnknown = (IUnknown*(*)())dlsym(handle, "CreateInstance");
	if((error = dlerror()) != NULL)
	{
		cout << "dlsym2 error:" << error << endl;
		dlclose(handle);
		return NULL;
	}

	pIUnknown = pfunIUnknown();
	if(NULL == pIUnknown)
	{
		cout << "error" << endl;
		return NULL;
	}
	return pIUnknown;
}

void CREATE::closeHandle()
{
	cout << "CREATE::closeHandle()" << endl;
	dlclose(handle);
}
客户端主函数:client.cpp
/*
	$file:		client.cpp
	$date:		2020年8月17日
	$author:	hehl
	$describe:	客户端主函数
	$other:
*/

#include <iostream>
#include "base.h"
#include "create.h"
#include "IUnknow.h"
#include "interface.h"

int main(int argc, char const *argv[])
{
	HRESULT hr;
	CREATE create;
	IUnknown* pUnknown = create.CreateIunknownkInstance();
	if(pUnknown == NULL)
	{
		cout << "CreateIunknownkInstance error" << endl;
		return -1;
	}

	IA* pCOM_A = NULL;
	hr = pUnknown->QueryInterface(g_COM_A_IID, (void**)&pCOM_A);
	if (hr < 0)
	{
		cout << "Counld not get the IX interface." << endl;
	}
	else
	{
		cout << "Success get the IX interface." << endl;
		pCOM_A->show_A();
		pCOM_A->Release();
	}

	pUnknown->Release();
	create.closeHandle();

	return 0;
}
生成可执行程序client的Makefile
all:
	g++ client.cpp create.cpp -ldl -o client

-ldl 链接动态库函数<dlfcn.h>

测试

在这里插入图片描述
运行成功帮忙点个赞,出问题的留言一起探讨~

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值