【问题标题】:Checking for existence of Windows API Functions检查是否存在 Windows API 函数
【发布时间】:2010-11-10 21:20:42
【问题描述】:

我是 Windows 编程新手,我正在尝试寻找检查 Windows Shell API 函数是否存在的最佳方法。我想使用 Windows7 中的一些新任务栏功能。

https://msdn.microsoft.com/en-us/library/dd378460%28VS.85%29.aspx#custom_jump_lists

但我仍然希望我的程序能够被以前版本的 Windows 使用。有没有一种简单的方法可以知道这些函数是否可以在最终用户系统中调用。我正在用 C++ 编程。

【问题讨论】:

    标签: c++ winapi windows-7


    【解决方案1】:

    这取决于函数的种类。

    对于普通(非 COM)函数,唯一的方法是使用 LoadLibraryGetProcAddress。如果其中任何一个失败,您就知道操作系统缺少该功能。为复制现有函数签名的函数指针编写函数指针类型声明可能很乏味,但在 VC++2010 中,您可以使用 decltype。例如:

    HMODULE user32 = LoadLibraryW(L"user32");
    if (user32 != NULL)
    {
        auto messageBoxW = reinterpret_cast<decltype(MessageBoxW)*>(GetProcAddress(user32, "MessageBoxW"));
        if (messageBoxW != NULL)
        {
            messageBoxW(HWND_DESKTOP, L"Hello!", NULL, MB_OK);
        }
    }
    

    但是,许多 Shell API 都是通过 COM 组件和接口公开的。这些情况是不同的。有时您需要处理全新的组件;例如IApplicationDestinations是Win7中的一个新接口,实现它的coclass也是新的。在这些情况下,您只需执行 CoCreateInstance,并检查 REGDB_E_CLASSNOTREG 的返回值 - 这意味着此类 coclass 未在系统上注册(实际上不支持)。

    不过,有时新的操作系统版本会在现有的 coclass 上引入新的接口。一个例子是 ITaskbarList3,它是 Win7 中的新功能,但在实现 ITaskbarList 的现有 coclass 上提供,并且可以追溯到 Win95。在这种情况下,您应该首先为最基本的接口实例化 coclass,然后使用QueryInterface 获取新的接口版本,并通过检查E_NOINTERFACE 的返回值来检测它们不受支持。

    【讨论】:

    • “对于普通(非 COM)函数,唯一的方法是使用 LoadLibraryGetProcAddress。” - 不是唯一的方法。实际上有一个更清洁的解决方案:使用Linker Support for Delay-Loaded DLLs
    • 如何优雅地处理函数(或库)不存在的情况,延迟加载?
    • 这在Error Handling and Notification下有解释。
    【解决方案2】:

    LoadLibraryGetProcAddress 将成为你的朋友。

    另外,请查看this tutorial

    【讨论】:

      【解决方案3】:

      我相信 MSDN 是您最好的选择。函数文档的每个 MSDN 页面最后都包含一个部分,说明哪个版本的 Windows 支持此函数。

      例如,检查GetModuleHandle 的文档。这包含一个名为 Requirements 的部分,其中有一个字段 Minimum Supported ClientMinimum Supported Server

      但是,如果您想动态检查函数是否存在,则可以通过LoadLibraryGetProcAddress 进行。

      【讨论】:

      • 不幸的是,MSDN 没有记录,哪个系统引入了任何特定的 Windows API 调用。它仅记录受支持的 Windows 版本提供特定的 API 调用。除非最近根本没有更新文档,否则受支持的客户端不会比 Windows Vista 更进一步,即使 API 已经存在了几十年。
      【解决方案4】:

      我不同意当前的解决方案。你最终会得到很多不可读的代码。

      更好的选择是将功能包装在自定义的仅限 Windows 7 的 DLL 中。对于其他系统,请提供实现相同功能的另一个版本的 DLL。这通常是无操作的。例如。设置任务栏扩展的功能在旧 Windows 版本上是无操作的。

      这些 DLL 之间的动态切换是通过使用 MSVC 的延迟加载功能完成的。当调用 DLL 中的第一个函数时,您可以在 EXE 中使用自定义挂钩来选择正确的 DLL 版本,此时您就知道自己是否在 Windows 7 上运行。

      【讨论】:

        【解决方案5】:

        您应该使用 LoadLibrary 和 GetProcAddress 来动态加载和调用新功能。

        【讨论】:

          【解决方案6】:

          是的,您始终可以在运行时检查库中是否存在函数并采取适当的措施。 检查 LoadLibrary 和 GetProcAddress API。 http://msdn.microsoft.com/en-us/library/ms683212(VS.85).aspx

          【讨论】:

            【解决方案7】:

            如果您想在编译时发现该功能在您所针对的操作系统(例如 Win 95)上不可用时获得构建中断,那么您可以定义一些宏,记录在 here:NTDDI_VERSION , _WIN32_WINNT, WINVER。

            如果您希望您的应用在功能不可用时正常运行(例如,Win7 之前的操作系统上的 JumpLists),那么您应该结合使用 LoadLibrary/GetProcAddress 来确定您正在寻找的功能是否可用。

            【讨论】:

              【解决方案8】:

              使用LoadLibarary 获取库句柄,使用GerProcAddress 获取指向函数的指针。对于当前操作系统不支持的功能,您将收到来自GetLastErrorERROR_CALL_NOT_IMPLEMENTED 错误。

              【讨论】:

                猜你喜欢
                • 2012-11-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-05-22
                • 2011-10-23
                • 2014-02-18
                • 2015-07-24
                • 1970-01-01
                相关资源
                最近更新 更多