我的代码是:
HINSTANCE hDll;
hDll = LoadLibrary("FibAsmLib");
myCppProc = GetProcAddress(hDll, "GetFive");
库是corectly加载的,但GetProcAddress返回NULL值。
这就是我的看法:
fibAsm.asm
.486
.model flat, stdcall
.code
GetFive proc
ret 5
GetFive endp
end
asmLib.h
#ifdef FIBASMLIB_EXPORTS
#define FIBASMLIB_API __declspec(dllexport)
#else
#define FIBASMLIB_API __declspec(dllimport)
#endif
FIBASMLIB_API int GetFive();
和asmLib.def
LIBRARY "FibAsmLib"
EXPORTS
GetFive
我找不到问题出在哪里,你有什么线索吗?
//修改
当我在DependencyWalker中运行dll时出现错误:
Error: At least one module has an unresolved import due to a missing export function in an implicitly dependent module.
Error: Modules with different CPU types were found.
现在我确定它的dll错误,但我仍然无法找出问题所在
// EDIT2 我有切入点:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
BOOL APIENTRY 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;
}
// edit3 啊,我没有将.def文件设置为模块定义文件,但现在我无法编译库cus
error LNK2001: unresolved external symbol GetFive ...FibAsmLib.def
答案 0 :(得分:2)
您的代码有几个问题。首先,DLL需要一个带有12个字节参数的入口点(传统上称为DllMain
),因此您需要为此添加至少一个函数。
其次,至少就我能够找到/得到的东西而言,要导出未破坏的名称,你需要在{{1}中使用external=internal
语法}语句,所以你的.def文件应该是这样的:
exports
如果不这样,带有LIBRARY "FibAsmLib"
EXPORTS
GetFive = _GetFive@0
DllMain = _DllMain@12
的.def文件会找到您编写的GetFive函数,但会导出它的错位名称(exports GetFive
)。这很好,但是如果你这样做,你需要在调用_GetFive@0
时指定受损的名称:
GetProcAddress
无论如何,当您进行链接时,您还需要指定入口点,例如:
myCppProc = GetProcAddress(hDll, "_GetFive@0");
顺便说一句,当/如果你想看到从DLL导出的名称时,最简单的方法通常是使用link fibAsm.obj /def:asmLib.def /entry:DllMain
(显然用实际DLL文件的名称替换dumpbin /exports YouDll.dll
想看看)。警告:对于大型DLL,输出可能非常庞大,因此您经常需要将输出管道输出到YourDll.dll
之类的内容。
您实际上并不需要导出入口点(事实上,我认为至少某些版本的链接器会发出警告),因此整体文件可能如下所示:
fibasm.asm
less
asmlib.def:
.486
.model flat, stdcall
.code
Entry PROC Inst : DWORD, reason : DWORD, reserved : DWORD
ret 12
Entry ENDP
GetFive PROC
ret 5
GetFive ENDP
end
生成文件:
LIBRARY "FibAsmLib"
EXPORTS
GetFive = _GetFive@0
至少对我来说,有了这三个,fibasmlib.dll: fibasm.obj asmlib.def
link fibAsm.obj /def:asmLib.def /entry:Entry
.asm.obj:
ml /c $<
成功构建了DLL。
答案 1 :(得分:0)
“LoadLibrary”似乎不会返回NULL - 如果我理解正确的话。
这意味着“DllMain”不是问题;否则LoadLibrary将返回NULL。
许多连接器需要函数名称中的下划线;如果在.DEF文件中命名函数“GetFive”,那么链接器将期望一个实际命名为“_GetFive”的函数,因为所有C编译器都会在每个函数中添加该下划线。
汇编程序代码中的“stdcall”可能就是问题所在。这可能会告诉汇编程序自动生成符号名称。这意味着:汇编程序将“GetFive”重命名为“_GetFive @ 0”(在这种情况下,函数可能必须命名为“GetFive @ 0”而不包含.DEF文件中的下划线)。
为了避免这种情况,我会在汇编程序中使用“cdecl”而不是“stdcall”,尽管函数实际上是一个stdcall函数!这样做将无法从DLL中的汇编程序调用C代码,反之亦然。 (EXE文件中的C代码可以调用DLL中的汇编代码。)
GNU C编译器附带的“objdump”工具可用于检查对象和DLL文件中函数的名称:
此命令将列出目标文件中的所有符号名称(函数和变量):
objdump -t FibAsmLib.obj
您可以看到您的函数是否命名为“GetFive”,“_ GetFive”或“_GetFive @ 0”。
此命令将列出DLL文件中的所有Windows特定信息:
objdump -p FibAsmLib.dll
这个工具输出很长。在输出中间的某个位置,您将找到所有导出的列表(可以使用“GetProcAddress”访问的所有函数)。此列表如下所示:
[Ordinal/Name Pointer] Table
[ 0] GetFive
顺便说一下:“ret 5”没有任何意义!我认为指令应该是“退20”。但是这会导致保护错误,而不是“GetProcAddress”的问题。