如果您想记录到 dll 的调用,最好的方法是编写代理 dll(dll 重定向)。但是对于那个你必须知道你要重写的函数的签名(语法),即参数的确切数量、它们的类型和返回类型等。如果我可以假设您可以通过某种方式找出 ftd2xx.dll 中所有函数的签名,那么完成它只是简单的。
获取 dll 函数和序数:
为此只需使用 Visual Studio 附带的 dumpbin.exe(通过运行 Visual Studio 命令提示符使用它)
dumpbin.exe /exports {你的路径}\ftd2xx.dll > ftd2xx.txt
现在您的 ftd2xx.txt 具有 ftd2xx.dll 的所有函数名称和序号。你甚至可以使用你的依赖遍历器来导出和获取这个列表。
创建您自己的名为 ftd2xx.dll 的 dll:
打开 Visual Studio,选择 VC++ >> Win32 >> Win32 Project >> Dll(带有导出符号选项),最后使用#pragma 指令在 dll 代码中声明所有导出的原始 dll 函数,如下所示,
//#pragma comment (linker, "/export:<function>=<origdll_name>.<function>,@<ordinal_number>")
#pragma comment (linker, "/export:FT_Open=ftd2xx_.FT_Open,@1")
#pragma comment (linker, "/export:FT_Close=ftd2xx_.FT_Close,@2")
// :
// :
// :
// delcare all your exported functions here with ordinal number
// :
// :
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
}
现在,您需要编写自己的函数,该函数可以伪装成 ftd2xx.dll 的原始函数,当应用程序调用 ftd2xx.dll 的原始函数时,该函数将被调用。下面的代码只是为了解释它是如何工作的。正如我之前所说,您需要知道要覆盖(重定向)的 dll 函数的确切签名。另外请记住,您需要在执行任何操作后调用原始函数,否则您的应用程序可能会出现意外行为。
假设 FT_Close() 函数不带参数并返回 void,我只是举例说明,我用代理 NewFT_Close() 函数覆盖 ftd2xx.dll 的 FT_Close() 函数。请注意,如果您覆盖一个函数,则将其从 #pragma 指令中删除并将其添加到一个 .def 文件中(将一个新的 ftd2xx.def 文件添加到您的项目并声明您的新函数,如下所示)。
DEF 文件示例
LIBRARY ftd2xx.dll
EXPORTS
FT_Close = NewFT_Close @2
Dll 代码示例
HINSTANCE hInstance = NULL; // handle to ftd2xx.dll
FARPROC fpFTClose = {NULL}; // function pointer to hold original function address
extern "C" void __stdcall NewFT_Close()
{
// This is our proxy function for FT_Close()
// Do whatever you want to do here and the
// finally call the original FT_Close() using
// the function pointer we got from GetProcAddress()
typedef void (__stdcall *PFTCLOSE)();
PFTCLOSE pFc = (PFTCLOSE)fpFTClose;
if(pFc) pFc();
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
// Load the original dll in to the memory and get the handle
hInstance = LoadLibraryA("ftd2xx_.dll");
if(!hInstance) return FALSE;
// Get the address of the function to be overriden
fpFTClose = GetProcAddress(hInstance,"FT_Close");
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
// Our dll is getting unloaded from the application, unload original as well
FreeLibrary(hInstance);
break;
}
return TRUE;
}
请注意,原始 dll 在 LoadLibraryA() 调用中称为 ftd2xx_.dll。因此,将原始 dll 重命名为 ftd2xx_.dll 或任意命名。构建您的代理 dll 代码并将您的代理 dll (ftd2xx.dll) 带到原始 ftd2xx.dll 所在的路径。现在,您的应用程序将照常调用 ftd2xx.dll(代理),但 ftd2xx.dll 将在内部调用原始 dll ftd2xx_.dll。
更新 #1:
我一直提到你需要知道你试图覆盖的函数的签名,幸运的是我刚刚在 linux 版本的驱动程序中找到了 ftd2xx.h 文件。
Linux version of ftd2xx
从上面的链接下载 libftd2xx-i386-1.3.6.tgz 文件并将其解压到一个文件夹(我使用的是 7zip),进一步解压 .tar 文件以获取发布文件夹,您将找到 ftd2xx.h 文件在“发布”文件夹中。好了,现在您已经获得了 dll 的完整函数签名,并且您知道如何编写代理 dll。祝你好运。