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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 21:26:52  来源:igfitidea点击:

Python: accessing DLL function using ctypes -- access by function *name* fails

pythondllctypesattributeerror

提问by Vit Bernatik

myPythonClient(below) wants to invoke a ringBellfunction (loaded from a DLL using ctypes). However, attempting to access ringBellvia its nameresults in an AttributeError. Why?

myPythonClient(下面)想要调用一个ringBell函数(使用 DLL 从 DLL 加载ctypes)。但是,尝试ringBell通过其名称访问会导致AttributeError. 为什么?

RingBell.hcontains

RingBell.h包含

namespace MyNamespace
    {
    class MyClass
        {
        public:
            static __declspec(dllexport) int ringBell ( void ) ;
        } ;
    }

RingBell.cppcontains

RingBell.cpp包含

#include <iostream>
#include "RingBell.h"
namespace MyNamespace
    {
    int __cdecl MyClass::ringBell ( void )
        {
        std::cout << "\a" ;
        return 0 ;
        }
    }

myPythonClient.pycontains

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:

然后你可以使用程序li​​nk.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