如何使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.dll
和 2.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-A
和dll-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
我正在尝试为我的 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.dll
和 2.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-A
和dll-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