MSVC 编译 DLL 不能调用问题

编程
Article Directory

MSVC 编译 DLL 不能调用问题

Q:

写一个 DLL ,使用 MinGW 编译,时,在动态加载,使用 GetProcAddress() 获取函数地址调用时,可成功调用。但是如果使用 MSVC 编译,DLL 可成功编译、加载,但,在 GetProcAddress() 获取函数地址,调用时,得到错误码 127 ,错误定义为,为找到相关函数。

A:

MSVC 下有一个工具 dumpbin ,使用该工具可查看 DLL 的导出函数,在使用 MinGW 编译时,我们使用 dumpbin 查看DLL 的导出函数是这样的

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
> dumpbin -exports .\hello.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30141.0
Copyright (C) Microsoft Corporation. All rights reserved.


Dump of file .\hello.dll

File Type: DLL

Section contains the following exports for hello.dll

00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
2 number of functions
2 number of names

ordinal hint RVA name

1 0 00001000 _DllMain@12
2 1 00001040 show

Summary

2000 .data
6000 .rdata
1000 .reloc
C000 .text

使用 MSVC 编译时,函数导出表是这样的

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
> dumpbin -exports .\hellodll\Release\hello.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30141.0
Copyright (C) Microsoft Corporation. All rights reserved.


Dump of file .\hellodll\Release\hello.dll

File Type: DLL

Section contains the following exports for hellodll.dll

00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
2 number of functions
2 number of names

ordinal hint RVA name

1 0 00001030 ?show@@YAXXZ
2 1 00001000 _DllMain@12

Summary

1000 .data
1000 .rdata
1000 .reloc
1000 .rsrc
1000 .text

看到,其中导出的函数名称发生了变化,在 c++ 中,编译器会按照自己的规则,更改函数名字,所以,在不同编译器的不同程序之间调用时,会调用失败。

R:

  • 可在 export 函数前,使用 extern “C” ,使用内嵌 c 语言,不推荐此种方法。
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
#define WIN32_LEAN_AND_MEAN
#include "pch.h"
#include <windows.h>
#pragma comment(lib, "user32.lib")

extern "c" __declspec(dllexport)
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
MessageBox(NULL, TEXT("Hello world!"), TEXT("Hello World!"), 0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

extern "c" __declspec(dllexport)
void show()
{
MessageBox(NULL, TEXT("xsxsxs"), TEXT("xsxsx"), 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
#define WIN32_LEAN_AND_MEAN
#include "pch.h"
#include <windows.h>
#pragma comment(lib, "user32.lib")

BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
MessageBox(NULL, TEXT("Hello world!"), TEXT("Hello World!"), 0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

void show()
{
MessageBox(NULL, TEXT("xsxsxs"), TEXT("xsxsx"), 0);
}

新建一个 .def 后缀的文件,写入以下内容

1
2
3
4
LIBRARY hellodll

EXPORTS
show

在 vs studio 项目属性 / 连接器 / 模块定义文件 /

写入这个 .def 文件,重新编译,使用 dumpbin 查看函数导出表

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
> dumpbin -exports .\hellodll\Release\hellodll.dll
Microsoft (R) COFF/PE Dumper Version 14.29.30141.0
Copyright (C) Microsoft Corporation. All rights reserved.


Dump of file .\hellodll\Release\hellodll.dll

File Type: DLL

Section contains the following exports for hellodll.dll

00000000 characteristics
FFFFFFFF time date stamp
0.00 version
1 ordinal base
2 number of functions
2 number of names

ordinal hint RVA name

2 0 00001000 _DllMain@12 = _DllMain@12
1 1 00001030 show = ?show@@YAXXZ (void __cdecl show(void))

Summary

1000 .data
1000 .rdata
1000 .reloc
1000 .rsrc
1000 .text

即可得到 正确地址调用

若使用命令编译

则可使用以下参数

cl .\dllmain.cpp /LD /link /DEF:hellodll.def 指定 def 文件,

Author: 哒琳

Permalink: http://blog.jieis.cn/2021/e6c9b24f-5757-4e42-b44d-9818678e9c71.html

Comments