虽然通过Visual Studio设置运行时DLL加载没有问题,但是在通过Visual Studio CLI工具手动执行时遇到了一些麻烦。
假设我们有以下2个简单的C ++源文件,我们要编译,一个用于二进制可执行文件,另一个用于DLL:
的main.cpp
void say_hello();
int main()
{
say_hello();
return 0;
}
say_hello.cpp
#include <stdio.h>
void say_hello()
{
printf("Hello DLL World!");
}
将say_hello.cpp
文件编译为DLL然后将其与来自main.cpp
的调用动态链接的步骤是什么?
根据我对MSDN文档的阅读,我能够成功编译say_hello.dll
和应用程序,然后运行它并使用以下命令:
cl say_hello.cpp /LD
lib say_hello.obj
cl say_hello.lib main.cpp
不幸的是,这似乎只允许通过say_hello.lib
文件静态链接应用程序(可以通过删除.lib和.dll文件来确认,它仍然允许二进制文件成功运行)。 p>
我必须将哪些命令/参数传递给编译/链接阶段以使main.exe
使用DLL而不是静态库?
答案 0 :(得分:2)
这是一个例子。并非所有事情都是完全必要的(例如DLLMain),但我认为这些是你应该查找的东西; - )
SayHello.cpp
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>
// see https://msdn.microsoft.com/en-us/library/56h2zst2.aspx : Decorated Names
extern "C" { // somehow making it superfluous to put the code in SayHello.cPP ...but anyway ;-)
// see https://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx : dllexport, dllimport
__declspec(dllexport) void say_hello()
{
printf("Hello DLL World!");
}
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms682583%28v=vs.85%29.aspx : (optional) DllMain entry point
BOOL WINAPI DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
}
的main.cpp
extern "C" { __declspec(dllimport) void say_hello(); } // we did this in SayHello.cpp, so we have to do it here too.
// otherwise the name wouldn't match
int main() {
say_hello();
return 0;
}
然后编译/链接
cl /D_USRDLL /D_WINDLL SayHello.cpp /LD /link /OUT:SayHello.dll
/ LD告诉链接器构建DLL 和以使用/ MT,请参阅/MD, /MT, /LD (Use Run-Time Library)。 (通过OUT:参数你可以更改.dll的名称;这里它是默认值,仅用于演示目的。如果你把它遗漏,你也可以跳过/链接参数,因为不再有链接器参数。)
cl.exe /MT main.cpp /link /SUBSYSTEM:CONSOLE "SayHello.lib"
匹配dll的运行时lib设置,创建console application(main.cpp有一个int main()
)并链接SayHello的stub lib(而不是使用LoadLibrary("SayHello.dll") / GetProcAddress(...))
答案 1 :(得分:0)
我将VolkerK的答案标记为正确,因为它包含一些其他重要的Windows DLL API详细信息,绝对值得一读,但我想总结最低更改,可以让它获得基于Igor Tandetnik和VolkerK的评论,动态链接工作在最简单的例子中。
在DLL中导出至少一个函数之前添加宏__declspec(dllexport)
是必不可少的,否则库编译命令将不会创建导入库来指示哪些函数可用于动态链接。
第二个“lib say_hello.obj”完全错误,因为DLL编译命令将正确地生成say_hello.lib(而该lib命令只会生成一个静态库并最终覆盖第一个命令)。
以下是最完整的基本工作示例:
<强>的main.cpp 强>
void say_hello();
int main()
{
say_hello();
return 0;
}
<强> say_hello.cpp 强>
#include <stdio.h>
__declspec(dllexport) void say_hello()
{
printf("Hello DLL World!");
}
编辑命令:
cl say_hello.cpp /LD
cl main.cpp say_hello.lib