MFC应用程序和共享库

MFC app and shared libs

本文关键字:共享 应用程序 MFC      更新时间:2023-10-16

我有一个应用程序,似乎已经写在MFC(进程黑客和DependencyWalker显示链接到MFC90)。

另外,在安装路径中有一个库(FTD2XX)。但是DependencyWalker不会显示lib的MFC90链接并显示:

SetupAPI.dll
KERNEL32.dll
USER32.dll
ADVAPI32.dll

lib是在什么框架下构建的?我没有MFC方面的经验。我没有信息在它的编译器,如果vc++库可以用来链接与MFC应用程序。

如果你想记录对dll的调用,最好的方法是编写一个代理dll (dll重定向)。但是对于,你必须知道你要覆盖的函数的签名(语法),即参数的确切数量,它们的类型和返回类型等。如果我能假设你能以某种方式找到ftd2xx.dll中所有函数的签名,那么完成它就很简单了。

获取dll函数和序数:为此,只需使用Visual Studio自带的dumpbin.exe(通过运行Visual Studio命令提示符使用它)

dumpbin.exe/exports {yourpath}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;
}

注意,在LoadLibraryA()调用中,原始dll被称为ftd2xx_.dll。因此,将原始dll重命名为ftd2xx_.dll或您想要的任何名称。构建代理dll代码并将代理dll (ftd2xx.dll)带到原始ftd2xx.dll所在的路径。现在,您的应用程序将像往常一样调用ftd2xx.dll(代理),但ftd2xx.dll将在内部调用原始dll ftd2xx_.dll。

Update # 1: 我一直提到你需要知道你试图覆盖的函数的签名,幸运的是,我刚刚在linux版本的驱动程序中找到了ftd2xx.h文件。

ftd2xx Linux版本

下载libftd2xx-i386-1.3.6从上面的链接中提取ftd2xx.h文件并将其解压缩到一个文件夹(我使用的是7zip),进一步提取.tar文件以获得发布文件夹,您将在"发布"文件夹中找到ftd2xx.h文件。好了,现在你得到了dll的完整函数签名,并且知道如何编写代理dll。好运。