Python:使用 ctypes 访问 DLL 函数——按函数 *name* 访问失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1088085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python: accessing DLL function using ctypes -- access by function *name* fails
提问by Vit Bernatik
myPythonClient
(below) wants to invoke a ringBell
function (loaded from a DLL using ctypes
). However, attempting to access ringBell
via its nameresults in an AttributeError
. Why?
myPythonClient
(下面)想要调用一个ringBell
函数(使用 DLL 从 DLL 加载ctypes
)。但是,尝试ringBell
通过其名称访问会导致AttributeError
. 为什么?
RingBell.h
contains
RingBell.h
包含
namespace MyNamespace
{
class MyClass
{
public:
static __declspec(dllexport) int ringBell ( void ) ;
} ;
}
RingBell.cpp
contains
RingBell.cpp
包含
#include <iostream>
#include "RingBell.h"
namespace MyNamespace
{
int __cdecl MyClass::ringBell ( void )
{
std::cout << "\a" ;
return 0 ;
}
}
myPythonClient.py
contains
myPythonClient.py
包含
from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found
采纳答案by Vinay Sajip
Perhaps because the C++ name is mangled by the compiler and not exported from the DLL as RingBell
. Have you checked that it appears in the exported names exactly like that?
也许是因为 C++ 名称被编译器修改过,而不是从 DLL 中导出为RingBell
. 您是否检查过它是否完全像那样出现在导出的名称中?
回答by Alex Martelli
Your C++ compiler is mangling the names of all externally visible objects to reflect (as well as their underlying names) their namespaces, classes, and signatures (that's how overloading becomes possible).
您的 C++ 编译器正在修改所有外部可见对象的名称以反映(以及它们的底层名称)它们的命名空间、类和签名(这就是重载成为可能的方式)。
In order to avoid this mangling, you need an extern "C"
on externally visible names that you want to be visible from non-C++ code (and therefore such names cannot be overloaded, nor in C++ standard can they be inline, within namespaces, or within classes, though some C++ compilers extend the standard in some of these directions).
为了避免这种修改,您需要一个extern "C"
外部可见的名称,您希望在非 C++ 代码中看到这些名称(因此此类名称不能重载,在 C++ 标准中,它们也不能内联、在名称空间内或在类内,尽管一些 C++ 编译器在其中一些方向上扩展了标准)。
回答by Vit Bernatik
All is working now :) To summarize your posts:
现在一切正常:) 总结你的帖子:
Write DLL in C++:
用 C++ 编写 DLL:
// Header
extern "C"
{ // Name in DLL will be "MyAdd" - but you won't be able to find parameters etc...
__declspec(dllexport) int MyAdd(int a, int b);
}
// Name will be with lot of prefixes but some other info is provided - IMHO better approach
__declspec(dllexport) int MyAdd2(int a, int b);
//.cpp Code
__declspec(dllexport) int MyAdd(int a, int b)
{ return a+b;
}
__declspec(dllexport) int MyAdd2(int a, int b)
{ return a+b;
}
Then you can use program link.exe to see real function name in dll. link.exe is for example in MSVC2010 here:
然后你可以使用程序link.exe查看dll中的真实函数名。link.exe 例如在 MSVC2010 中:
c:\program files\microsoft visual studio 10.0\VC\bin\link.exe
use:
利用:
link /dump /exports yourFileName.dll
you see Something like:
你会看到类似的东西:
ordinal hint RVA name
1 0 00001040 ?MyAdd2@@YAHHH@Z = ?MyAdd2@@YAHHH@Z (int __cdecl MyAdd2(int,int))
2 1 00001030 MyAdd = _MyAdd
Then in python you can import it as:
然后在python中,您可以将其导入为:
import ctypes
mc = ctypes.CDLL('C:\testDll3.dll')
#mc.MyAdd2(1,2) # this Won't Work - name is different in dll
myAdd2 = getattr(mc,"?MyAdd2@@YAHHH@Z") #to find name use: link.exe /dump /exports fileName.dll
print myAdd2(1,2)
#p1 = ctypes.c_int (1) #use rather c types
print mc[1](2,3) # use indexing - can be provided using link.exe
print mc.MyAdd(4,5)
print mc[2](6,7) # use indexing - can be provided using link.exe