【问题标题】:TypeDef with Function Pointer: Function does not Exist带有函数指针的 TypeDef:函数不存在
【发布时间】:2017-04-18 02:34:12
【问题描述】:

问题是在不存在所请求功能的旧机器上运行代码。要检查它,请使用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" ))
{...

代码在此处崩溃:

程序入口点 Wow64RevertWow64FsRedirection 在动态链接库 Kernel32.dll 中找不到

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

【问题讨论】:

  • 但 GetProcAddress 需要函数的地址 -- 这不是真的。 GetProcAddress 只需要模块句柄和一个字符串。
  • @Paul:帮帮我。回头看你的answer:这仍然适用吗?
  • GetProcAddress 返回一个指向函数的指针。调用函数不需要函数指针(字符串名称的指针除外)。

标签: c++ function typedef stdcall


【解决方案1】:

我在理解您的问题时遇到了一些问题。 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,所以我也不需要释放模块句柄。

我将生成的句柄传递给GetProcAddress 函数,以及一个包含要检索其地址的函数/过程的名称的字符串。此函数尝试检索该函数的地址,如果存在则返回它;否则,它会失败并返回 NULL。

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

至于有趣的选角,请参阅my answer here,它解释了这个技巧。

【讨论】:

  • 哎呀!谷歌搜索了几个小时才发现this。但是谢谢,问题是代码在执行任何 WOW64 语句之前就崩溃了。所以假设这与 LPFN_ISWOW64PROCESS 是唯一的全局声明有关,最初。
  • 看来Codeproject的方法没用吧?
  • 它在我看来确实设计过度了。在您无法保证要从中加载的模块已加载的情况下,它可能会更有用。这意味着您不能使用GetModuleHandle,而必须调用LoadLibrary。这意味着调用FreeLibrary。当我必须进行大量动态加载时,我会使用一系列相当复杂的包装宏,主要是因为它简化了我必须编写的代码量并减少了出错的机会。但在像这样的简单场景中不需要它。
猜你喜欢
  • 1970-01-01
  • 2011-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
相关资源
最近更新 更多