【cmake实战十一】com组件方法的简单实现
【cmake实战十一】com组件的简单实现
- 一、com组件(com方法)
- 二、类图
- 三、代码目录
- 四、构建、编译、运行
- 五、相关知识讲解
- 本文主要是dll使用的深入介绍,文中介绍的也基本和cmake知识没有太多关系,用到的cmake知识之前也都有介绍。
- 本文用到的demo和类图下载地址为:https://download.csdn.net/download/junxuezheng/86733649
一、com组件(com方法)
- com组件相关知识网上介绍的比较多,后来做了一些了解,发现com也是开发软件的一种方法,网上资料我就不搬砖了,简单来说,COM也是一种组织软件的方法。
- 1.组件必须动态连接;
- 2.组件必须隐藏(或封装)其内部实现细节。
这样理解COM组件
二、类图
- 本人水平有限,画的类图若有问题,欢迎大家指正。
- 比如,addClass和subClass两个在注册到进程中时,是调用了ibaseMangaer.h中导出的函数的,这点本人暂时不清楚怎么在类图中体现,后续清楚了再回来补上。
三、代码目录
1.main.cpp
//main.cpp
#include<iostream>
#include<windows.h>
#include "base/ibaseManger.h"
#include "add/i_add.h"
#include"sub/i_sub.h"
using namespace std;
int main()
{
// 第0:失败。addPtr0应该是空指针,因为LoadLibrary时才注册到baseMap中。
ibaseManger* ibaseMng = getbaseManager();
std::shared_ptr<IaddClass> addPtr0 = getBase<IaddClass>();
if (nullptr == addPtr0)
{
cout << "addPtr0 is nullptr" << endl;
}
// 第一.加载dll,在加载dll的过程中把addClass注册到baseManger的map中
HMODULE handle_add = (HMODULE)::LoadLibrary("C:\\Users\\Administrator\\Desktop\\test11\\lib\\Debug\\add.dll");
HMODULE handle_sub = (HMODULE)::LoadLibrary("C:\\Users\\Administrator\\Desktop\\test11\\lib\\Debug\\sub.dll");
if (NULL == handle_add || NULL == handle_sub)
{
cout << "load dll faile" << endl;
}
//int id = 123;
//std::shared_ptr<IaddClass> addPtr = getBase<IaddClass>(id);//第一版是按照通过id获取的,但是后面发现没有必要再传id进去
//第二:成功获取addClass
std::shared_ptr<IaddClass> addPtr = getBase<IaddClass>();
if (nullptr == addPtr)
{
cout << "addPtr is nullptr" << endl;
}
int sum = addPtr->add(1, 9);
cout << "1+9="<<sum<<endl;
//第三:成功获取subClass
std::shared_ptr<IsubClass> subPtr = getBase<IsubClass>();
if (nullptr == subPtr)
{
cout << "addPtr is nullptr" << endl;
}
int sub = subPtr->sub(1,9);
cout << "1-9="<<sub<<endl;
return 0;
}
2.CmakeList.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)
PROJECT(COMPUTER)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
ADD_EXECUTABLE(computer main.cpp)
ADD_SUBDIRECTORY(base)
ADD_SUBDIRECTORY(add)
ADD_SUBDIRECTORY(sub)
INCLUDE_DIRECTORIES("${PROJECT_SOURCE_DIR}/base") #要到haha目录,否则找不到
TARGET_LINK_LIBRARIES(computer base)
SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")
3.base
//ibaseManger.h
#pragma once
#include<iostream>
#include"base.h"
#include<map>
#include<Windows.h>
using namespace std;
#ifndef DLL_EXPORT
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
class API ibaseManger
{
public:
ibaseManger() {};
virtual ~ibaseManger() {};
virtual int registerBase(const int id, std::shared_ptr<base> basePtr) = 0;
virtual int getBase(const int& id, std::shared_ptr<base>& basePtr) =0;
//void init();
};
API ibaseManger* getbaseManager();
//template<typename T>
API int registers(std::shared_ptr<base> basePtr)
{
int id = basePtr->getGUID();
ibaseManger* baseMg = getbaseManager();
int ret = baseMg->registerBase(id, basePtr);
return 0;
}
template<typename T>
std::shared_ptr<T> getBase()
{
ibaseManger* baseMg = getbaseManager();
std::shared_ptr<base> basePtr;
int id = T::getID();
int ret = baseMg->getBase(id, basePtr);
if (0 != ret)
{
return nullptr;
}
std::shared_ptr<T> svr = std::dynamic_pointer_cast<T>(basePtr);
return svr;
}
//baseManger.h
#pragma once
#include<iostream>
#include"ibaseManger.h"
#include<map>
#include<Windows.h>
using namespace std;
class baseManger : public ibaseManger
{
public:
baseManger();
~baseManger();
int registerBase(const int id, std::shared_ptr<base> basePtr) ;
int getBase(const int& id, std::shared_ptr<base>& basePtr);
void init();
private:
map<int, std::shared_ptr<base>> baseMap;
};
int API createBaseManger(baseManger* baseMng)
{
//baseMng = new baseManger();
//baseMng->init();
return 0;
}
//base.h
#pragma once
#include<iostream>
#include<Windows.h>
class base
{
public:
virtual int getGUID() = 0;
static const int getID()
{
return 000;
}
};
//baseManger.cpp
#include "baseManger.h"
using namespace std;
API ibaseManger* getbaseManager()
{
static baseManger m_baseManager;
return &m_baseManager;
}
baseManger::baseManger()
{
}
baseManger::~baseManger()
{
}
int baseManger::registerBase(const int id, std::shared_ptr<base> basePtr)
{
baseMap.insert(pair<int, std::shared_ptr<base>>(id, basePtr));
return 0;
}
int baseManger::getBase(const int& id, std::shared_ptr<base>& basePtr)
{
auto iter = baseMap.find(id);
if (iter == baseMap.end())
{
return -1;
}
basePtr = iter->second;
return 0;
}
void baseManger::init()
{
//LoadLibrary("C:\\Users\\jx\\Desktop\\test10\\lib\\Debug\\baseManager.dll");
}
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)
SET(TARGET "base")
ADD_LIBRARY(base SHARED baseManger.cpp baseManger.h base.h ibaseManger.h)
set_target_properties(${TARGET} PROPERTIES FOLDER "base")
SET(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")
4.add
//i_add.h
#pragma once
#include<iostream>
#include"../base/base.h"
#ifndef DLL_EXPORT
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif
//register(123, IaddClass);
class IaddClass :public base
{
public:
IaddClass() {};
virtual ~IaddClass() {};
virtual int add(int a, int b) =0;
virtual int getGUID() =0;
static int getID()
{
return 123;
}
};
//add.h
#pragma once
#include<iostream>
#include"i_add.h"
class addClass :public IaddClass
{
public:
addClass();
~addClass();
virtual int add(int a, int b) override;
virtual int getGUID() override;
};
//add.cpp
#include "add.h"
#include <memory>
#include"../base/ibaseManger.h"
using namespace std;
//REGISTERBASE(addClass);
//addClass* g_addClass = new addClass;
//std::shared_ptr<addClass> g_addClass = make_shared(new addClass());
std::shared_ptr<addClass> g_addClass(new addClass());
int ret = registers(g_addClass);
addClass::addClass()
{
}
addClass::~addClass()
{
}
int addClass::add(int a,int b)
{
return a+b;
}
int addClass::getGUID()
{
return 123;
}
CMAKE_MINIMUM_REQUIRED(VERSION 3.8.0)
SET(TARGET "add")
ADD_LIBRARY(add SHARED add.cpp i_add.h add.h)
INCLUDE_DIRECTORIES("${PROJECT_SOURCE_DIR}/base")
TARGET_LINK_LIBRARIES(add base)
set_target_properties(${TARGET} PROPERTIES FOLDER "com")
SET(LIBRARY_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/lib")
5.sub
同add只有方法不一样,其他一致。
四、构建、编译、运行
- 1、构建
cmake -B build
- 2、编译
cmake --build build
- 3、运行
五、相关知识讲解
- 正常情况应该使用guid,本文为了方便理解,id使用了int类型的数据。(guid使用visual studio就可以生成)
- add.dll和sub.dlll内部都是可以通过main.cpp中的方法调用彼此的,本文没有写相应的例子。(在dll加载到内存中后)
- 注册dll:
LoadLibrary时,add.dll的add.cpp调用ibaseManager的方法注册到了进程中,存储到了baseMap中 - iaddClass和isubClass两个类只有接口的定义,而接口的实现封装起来了,实现了接口的定义和实现的分离。
- baseMap中存放的是智能指针。
- 基类智能指针转换为派生类的智能指针使用dynamic_pointer_cast
std::shared_ptr<T> svr = std::dynamic_pointer_cast<T>(basePtr);
- 智能指针赋值
std::shared_ptr<addClass> g_addClass(new addClass());
- 获取注册的dll,采用了模板函数
template<typename T>
std::shared_ptr<T> getBase()