将库 (DLL) 显式加载到 Legacy 函数指针中

Explicitly Load Library (DLL) into Legacy function pointers

我会尽量具体。

我需要在 运行 时将 PythonXX.dll 显式加载到我的例程中。我使用标称描述 (Python.h) 来描述功能。问题是链接器抱怨这些例程不存在。我无法更改函数定义以使链接器满意,因为 Python #include 代码结构散乱。

此时我的想法是创建存根例程,在 运行 时加载 .dll 时调用要加载的函数指针。存根使链接器满意,并且在 运行 时间内加载 .dll 时它们可以正确运行。 但这也存在一些问题。 [一些函数是其他例程的#defines,varags 难以重定向等]

有更好的方法吗?我不敢相信这以前没有发生过。如果有任何不清楚的地方,我会编辑和清理问题以澄清。

更新:好的,这似乎可行,至少对于某些例程是这样。 (幸运的是,我只需要使用 .dll 的 1000 多个函数中的大约 20 个)

函数指针定义示例:

int (__cdecl *pPy_IsInitialized)(void);

示例存根:

int Py_IsInitialized()
{
  return pPy_IsInitialized();
}

一个示例分配(dll 是 return 来自 LoadLibrary() ):

pPy_IsInitialized = (void *)GetProcAddress(dll,"Py_IsInitialized");

我可能会问你为什么要这样做,但我会尽力回答你的问题:

通常,您 link 要用于图像的 DLL 库(dll、exe 等)。 Windows 加载程序将 自动 在您加载之前加载您的依赖项。 OS' 加载程序还支持延迟加载图像,这是节省资源和加快代码速度的好主意。

如果您不喜欢加载器自动执行操作,您可以使用提供函数指针的模块句柄调用 LoadLibary directly with an image's (dll's) file path manually. That gets the dll loaded into your process. Then you can call GetProcAddress。这是假设 DLL 正确导出了您需要的函数。然后您可以使用函数定义转换函数指针。您可以像通常在代码中使用函数、传递参数等一样使用它。静态转换函数指针不应导致 linker 错误。

退一步说,API 版本控制是一个常见问题。 Windows 过去解决此问题的一种方法是使用 COM,它允许您通过 COM 对象对功能进行版本控制。您可以定义接口的 N 个版本。一个 dll 甚至一个 C++ 对象都可以实现它们,也可以分开实现。当您调用诸如 CoCreateInstance 之类的东西时,COM 基础 splunks 注册表中的对象注册以加载正确的 DLL 并实例化正确版本的 com 对象。

Windows也有很多CAPI。 Windows 使用 API sets 对 Win32 平面 C 风格 API 进行版本控制。您可以 link 特定版本的 API 设置到您的程序,但通常您会 link 像 onecoreuap.lib 这样的伞式库。我知道如何为系统组件执行此操作,但我不确定第 3 方组件是否可以连接到此 OS 功能。

一般来说,这种抽象是组件要实现的东西。组件的客户端这样做有点奇怪。

您最好的选择是使用 delay-loaded DLLs. This feature delays load of DLL (PythonXX.dll in your case) until any of it's functions is called. You can customize the actual library load (e.g. load it from specific location) via delayed-load helper function

附带说明一下,您在问题中提出的解决方案非常有意义,而且很容易实现自动化。延迟加载的 DLLS 为 Windows 实现了它,我的 Implib.so 为 Linux 共享库实现了同样的功能。