带有函数指针的 TypeDef:函数不存在

TypeDef with Function Pointer: Function does not Exist

问题是 运行 旧机器上的代码不存在请求的函数。要检查它,请使用 LoadLibraryGetProcAddress,如 here 所示,但 GetProcAddress 在使用前需要 TypeDef 中的函数地址。
例如,以这两个为例,XP SP2 32 位:

typedef BOOL (__stdcall *LPFN_Wow64RevertWow64FsRedirection) (PVOID OldValue);
typedef BOOL (__stdcall *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
...

...
LPFN_Wow64RevertWow64FsRedirection wowRevert = NULL;
LPFN_Wow64DisableWow64FsRedirection wowDisable = NULL;
HINSTANCE hLib;
if(GetProcAddresses( &hLib, "kernel32.dll", 2, &wowRevert,_ 
"Wow64RevertWow64FsRedirection", &wowDisable, Wow64DisableWow64FsRedirection" ))
{...

此处代码崩溃:

The procedure entry point Wow64RevertWow64FsRedirection could not be located in the dynamic link library Kernel32.dll

使用非 WINAPI typedef 实现我们自己的自定义 Wow64RevertWow64FsRedirection 很容易,但是当函数存在于 kernel32.dll 中时,如何将它们替换为基本类型?

我在理解你的问题时遇到了一些问题。 Wow64RevertWow64FsRedirection 函数显然不会存在于 32 位操作系统上,因此它不会存在于 32 位 Windows XP 上。因此,尝试使用 GetProcAddress 检索指向此函数的指针将失败。您收到无法找到该入口点的合理错误。如果找不到入口点,则该函数不存在,您不应尝试调用它。

您声称可以实现自己的自定义 Wow64RevertWow64FsRedirection 函数,但我完全不明白您为什么要这样做。如果操作系统支持 WOW64 文件系统重定向,那么它将提供 Wow64RevertWow64FsRedirection 功能。如果没有,那么它不提供该功能,但是您不需要这样的功能,因为没有WOW64文件系统重定向这样的东西。您无需启用、禁用或还原它。

看来你把这件事弄得比实际需要的要复杂得多。您甚至不需要首先验证进程是否为 64 位进程。您可以尝试将入口点定位到 Wow64RevertWow64FsRedirection(或 Wow64DisableWow64FsRedirection,根据需要),如果它存在则调用它,或者如果它不存在则忽略失败。

就这么简单:

BOOL RevertWOW64RedirectionIfNecessary(PVOID pOldValue)
{
    typedef BOOL (WINAPI * fnWow64RevertWow64FsRedirection)(PVOID);

    fnWow64RevertWow64FsRedirection pfn =
        reinterpret_cast<fnWow64RevertWow64FsRedirection>(
           reinterpret_cast<void*>(
           GetProcAddress(GetModuleHandle(L"kernel32"),
                          "Wow64RevertWow64FsRedirection")));

    if (pfn)
    {
        // The function exists, so call it through the pointer we obtained.
        return pfn(pOldValue);
    }
    else
    {
        // The function does not exist, so we can't call it.
        // But we don't ever need to call it in such cases,
        // so do nothing and feign success.
        return TRUE;
    }
}

请注意,我正在调用 GetModuleHandle 函数来检索模块 kernel32.dll 的句柄(隐含 .dll 扩展名)。我可以在这里使用 GetModuleHandle 而不是 LoadModule,因为我知道 kernel32.dll 保证始终加载到任何应用程序的进程中。因为我已经使用了 GetModuleHandle,所以我也不需要释放模块句柄。

我将生成的句柄连同包含要检索其地址的 function/procedure 名称的字符串一起传递给 GetProcAddress 函数。此函数尝试检索该函数的地址,如果存在则 returns 它;否则,它将失败并且 returns NULL.

我检查它是否返回了一个有效的指针,如果是,我通过该指针动态调用该函数。否则,它返回 NULL,意味着该函数不可用,但在那种情况下,我们甚至不需要担心它,所以代码就变成了空操作。

至于有趣的演员表,请参阅 my answer here,其中解释了这个技巧。