欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

dll的加载

程序员文章站 2022-03-04 19:07:46
...

[C-C++]DLL之旅1 : 将程序打包成DLL

2017年11月20日 20:25:21 祥知道 阅读数:359 标签: dll matlab 更多
个人分类: C-C++
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/humanking7/article/details/78585004
原创文章,欢迎转载。转载请注明:转载自 祥的博客

原文链接:http://blog.csdn.net/humanking7/article/details/78585004

问题提出

发现Matlab中,在一个Simulink文件里有多个CS-function,而CS-function都会调用共同的自定义函数。这样会mex(Matlab调用编译器编译的一种形式,将源文件编译成Matlab-Simulink可执行的文件)这些源文件成mexw32或mexw64文件,每个CS-function都是单独编译的,如果只是运行,这些mexw32并不冲突,但是如果将整个Simulink文件进行编译(xPC或是其他环境,要将整个Simulink文件编译成目标文件,下载到目标机上),这样就会出现函数重定义的链接错误。

这也是很明显的事情,每个mexw32文件都会共用一些函数,而这些函数编译成的目标文件都会在mexw32中,这些拥有相同函数的的mexw32在Simulink的环境下可以单独运行,但如果合在一起进行编译,就会出现下重定义错误。

解决想法:

共用的函数重命名,虽然功能一样,但是名字不一样(简单粗暴,但是共用的函数多了就相当恶心,治标不治本) ;
将共用的函数打成动态链接库(lib、dll)。
分装DLL步骤

Step1. 新建win32的DLL项目

p1

p2

Step2 代码

就两个文件:

头文件: qShareDll.h
源文件: qShareDll.c
Step2.1 头文件代码

#ifndef _Q_SHARE_DLL_H
#define _Q_SHARE_DLL_H

extern “C” _declspec(dllexport) double qAdd(double a, double b);
extern “C” _declspec(dllexport) double qSub(double a, double b);

// extern “C” 解决函数名由于不同编译器造成的名字匹配问题
// 通常c++编译器编译时会对函数进行改名,而c编译器不会

// _declspec(dllexport)说明该函数为导出函数

/*
如果函数用"_stdcall"进行修饰,在动态引用的时候,要对"函数指针"也要进行"_stdcall"修饰
__stdcall:Windows API默认的函数调用协议
extern “C” _declspec(dllexport) double _stdcall qAdd(double a, double b);
extern “C” _declspec(dllexport) double _stdcall qSub(double a, double b);
*/

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Step2.2 源文件代码

#include “qShareDll.h”

double qAdd(double a, double b)
{
return a + b;
}

double qSub(double a, double b)
{
return a - b;
}
1
2
3
4
5
6
7
8
9
10
11
12
Step2.3 链接库

编译得到qShareDll.dll和qShareDll.lib

b3

Step3. 注意事项

主要就是集中在头文件上:

extern “C” 解决函数名由于不同编译器造成的名字匹配问题
通常C++编译器编译时会对函数进行改名,而C编译器不会
_declspec(dllexport)说明该函数为导出函数
如果函数用_stdcall进行修饰,在动态引用的时候,要对函数指针也要进行_stdcall修饰
Next计划

[C-C++]DLL之旅2 : 调用DLL(静态&动态加载)

接着上文《DLL之旅1 : 将程序打包成DLL》,现在调用动态链接库有两种方法。

1.静态加载

需要文件(一个都不能少):

头文件: qShareDll.h
编译生成的lib文件 : TestDll.lib – 编译需要
编译生成的dll文件 : TestDll.dll – 运行需要
头文件: qShareDll.h

#ifndef _Q_SHARE_DLL_H
#define _Q_SHARE_DLL_H

extern “C” _declspec(dllexport) double qAdd(double a, double b);
extern “C” _declspec(dllexport) double qSub(double a, double b);

// extern “C” 解决函数名由于不同编译器造成的名字匹配问题
// 通常c++编译器编译时会对函数进行改名,而c编译器不会

// _declspec(dllexport)说明该函数为导出函数

/*
如果函数用"_stdcall"进行修饰,在动态引用的时候,要对"函数指针"也要进行"_stdcall"修饰
__stdcall:Windows API默认的函数调用协议
extern “C” _declspec(dllexport) double _stdcall qAdd(double a, double b);
extern “C” _declspec(dllexport) double _stdcall qSub(double a, double b);
*/

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
调用源文件: main.cpp

#include
using namespace std;

#include “qShareDll.h”
#pragma comment(lib,“TestDll.lib”) //

int main()
{
double a, b;
cout << “静态加载” << endl;
while (true)
{
cout << "input Number a: ";
cin >> a;
cout << "input Number b: ";
cin >> b;
cout << "a + b = " << qAdd(a, b) << endl;
cout << "a - b = " << qSub(a, b) << endl << endl;
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2.动态加载

需要文件: 就一个DLL,需要用Depend工具,查看函数名(但这是不够的),还需要知道函数是怎么声明的(不然无法定义函数指针)。

调用源文件: main.cpp

#include
using namespace std;

#include <Windows.h>

int main()
{
double a, b;
cout << “动态加载” << endl;
HINSTANCE handle = LoadLibraryA(“TestDll.dll”); //用于加载dll

//如果当初头文件中有 "_stdcall" 修饰
//typedef double(_stdcall *ADDPROC)(double, double);
//typedef double(_stdcall *SUBPROC)(double, double);
typedef double(*ADDPROC)(double, double);
typedef double(*SUBPROC)(double, double);

// GetProcAddress第二个参数有两种方法:  
// 1、通过DLL中的函数名  
// 2、通过Depend工具中Ordinal索引值来查看 - 编译不通过放弃(而且确实不好用)
ADDPROC MyAdd = (ADDPROC)GetProcAddress(handle, "qAdd");
SUBPROC MySub = (SUBPROC)GetProcAddress(handle, "qSub");  
//SUBPROC MySub = (ADDPROC)GetProcAddress(handle, MAKEINTRESOURCE(2));  //编译不通过-放弃


cout << "input Number a: ";
cin >> a;
cout << "input Number b: ";
cin >> b;
cout << "a + b = " << MyAdd(a, b) << endl;
cout << "a - b = " << MySub(a, b) << endl << endl;

FreeLibrary(handle);
return 0;

}
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
方便的代码

条件编译,方便。

#include
using namespace std;

//#define FLG_CMP_STATIC

#ifdef FLG_CMP_STATIC //静态加载DLL-Lib
#include “qShareDll.h”
#pragma comment(lib,“TestDll.lib”)
int main()
{
double a, b;
cout << “静态加载” << endl;
while (true)
{
cout << "input Number a: ";
cin >> a;
cout << "input Number b: ";
cin >> b;
cout << "a + b = " << qAdd(a, b) << endl;
cout << "a - b = " << qSub(a, b) << endl << endl;
}
return 0;
}
#else //动态加载DLL

#include <Windows.h>

int main()
{
    double a, b;
    cout << "动态加载" << endl;
    HINSTANCE handle = LoadLibraryA("TestDll.dll");                    //用于加载dll

    //typedef double(_stdcall *ADDPROC)(double, double);
    //typedef double(_stdcall *SUBPROC)(double, double);
    typedef double(*ADDPROC)(double, double);
    typedef double(*SUBPROC)(double, double);
    // GetProcAddress第二个参数有两种方法:  
    // 1、通过DLL中的函数名  
    // 2、通过Depend工具中Ordinal索引值来查看  
    ADDPROC MyAdd = (ADDPROC)GetProcAddress(handle, "qAdd");
    //SUBPROC MySub = (ADDPROC)GetProcAddress(handle, MAKEINTRESOURCE(2));  // MAKEINTRESOURCE LPCSTR
    SUBPROC MySub = (SUBPROC)GetProcAddress(handle, "qSub");  // MAKEINTRESOURCE LPCSTR
    while (true)
    {
        cout << "input Number a: ";
        cin >> a;
        cout << "input Number b: ";
        cin >> b;
        cout << "a + b = " << MyAdd(a, b) << endl;
        cout << "a - b = " << MySub(a, b) << endl << endl;
    }
    FreeLibrary(handle);
    return 0;
}

#endif // FLG_CMP_STATIC

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
Next计划

用Matlab的CS-function 去调用DLL,实现xPC可以编译多个共用的mexw文件

to be continu

作者:祥知道
来源:CSDN
原文:https://blog.csdn.net/humanking7/article/details/78586478
版权声明:本文为博主原创文章,转载请附上博文链接!

相关标签: dll