Python: accessing DLL function using ctypes — acce

2019-02-16 22:12发布

myPythonClient (below) wants to invoke a ringBell function (loaded from a DLL using ctypes). However, attempting to access ringBell via its name results in an AttributeError. Why?

RingBell.h contains

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

RingBell.cpp contains

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

myPythonClient.py contains

from ctypes import *
cdll.RingBell[1]() # this invocation works fine
cdll.RingBell.ringBell() # however, this invocation errors out
# AttributeError: function 'ringBell' not found

3条回答
爷的心禁止访问
2楼-- · 2019-02-16 22:29

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?

查看更多
男人必须洒脱
3楼-- · 2019-02-16 22:34

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).

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).

查看更多
够拽才男人
4楼-- · 2019-02-16 22:47

All is working now :) To summarize your posts:

Write DLL in C++:

// 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:

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:

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
查看更多
登录 后发表回答