如何使pyd调用外部C++ dll中的函数?

How to enable the pyd to call functions in external C++ dll?

我正在尝试为我的 python 程序设计一个外部 DLL。现在我可以使用 C++Visual Studio 2010 生成后缀为 ".pyd" 的文件。如果 .pyd 没有附加 C++ 生成的其他 .dll 文件,这个 python 库可以正常工作。

但是,现在我需要设计一个.pyd文件,这样的结构:

A.pyd -> 1.dll -> 2.dll

其中文件1,2是C库。这些库中的函数在生成 A.pyd.

时被调用

虽然这个 .pyd 文件可以通过 VS 2010 无错误地生成,但它不能在 python 3.6 中工作。报错如下:

回溯(最近调用最后): 文件“<code><stdin>”,第 1 行,在 <module> 中 ImportError: DLL 加载失败,找不到目标程序。

即使引用的 1.dll2.dll 存储在 包含 A.pyd 的同一文件夹中,此错误仍然存​​在。我想知道如何启用python-C++库来调用这些基于C的动态link库中的函数.

好的!现在我找到了执行此操作的正确方法!

封装 DLL

首先,如果你需要调用的dll (我称之为dll-A)没有导出任何函数(你可以使用dumpbin在 VS 命令中检查导出的函数),你需要包装原来的 dll-A。使用隐式调用来包含 dll-A。如果在原来的.h/.lib中声明了一个函数,像这样:

int func(int a, int b);

然后你需要创建一个新的dll项目并通过这个包装上面的函数:

.h

extern "C" _declspec(dllexport) int w_func(int a, int b);

.cpp

int w_func(int a, int b){
    return func(a, b);
}

当然,如果dumpbin显示dll-A有可用的导出函数,你可以跳过这一步。

导出这个dll后(我称之为dll-B,你会得到'dll-B'和它的依赖文件(包括dll-Adll-A 的依赖文件)。

编写.pyd文件

使用显式调用来引用 dll-B。使用此方法时,不应包含任何 lib/.h 文件,因为 dll-B 本身可以为您提供足够的接口。您可以通过此方法加载 dll:

.h

typedef int (*func_ptr)(int a, int b);

.cpp(编写 .pyd 项目时名为 Testdll 的函数的一部分)

func_ptr FUNC_API = NULL;
HINSTANCE h = LoadLibraryA("libdll/dllB.dll"); 
//Certainly! you could set the folder of stored dlls!
if (h){
    FUNC_API = (func_ptr)GetProcAddress(h, "w_func");
    //You could load more functions here.
}
else{ // If the dll could not be found
    FreeLibrary(h);
    return 0x100;
}
int errorflag=0;
if (FUNC_API==NULL){ //Check whether the function is valid.
    cout << "Could not find: func" << endl;
    errorflag = errorflag | 0x001;
}
//You could check more functions here.
if (errorflag!=0){ // if any function could not be found.
    FreeLibrary(h);
    return 0x100 | errorflag;
}
//process functions.
int a,b,c;
c = FUNC_API(a,b);
//Free the lib
if (h)
    FreeLibrary(h);

构建自己的 .pyd 后,您可以获得 python 数据库 (我称之为 pyd-C.

Link .pyd 和 Python

在python项目中,您可以通过以下方法测试此文件:

.py

import pydC

if __name__ == '__main__':
    X = pydC.cclass()
    X.Testdll();

然后你会发现这个功能执行的很好

请注意,您的 .pyd 应该与 .py 位于同一文件夹中。因为你在libdll/dllB.dll中设置了dll-B,所以dll-B应该放在名为libdll的文件夹中。但是,因为 dll-B 隐式调用 dll-A 和其他依赖 dll,所以 dll-A 和其他文件应该在您的工作区文件夹中,即与 .py 所在的文件夹相同。

总之,需要进入工作区文件夹,文件夹构成如下:

./
    Test.py
    pydC.pyd
    dllA.dll
    dllA_depended1.dll
    ...
    libdll/
        dllB.dll