views:

726

answers:

2

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
+1  A: 

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?

Vinay Sajip
You were correct.I used the following to discover the "mangled" name:link.exe /dump /exports RingBell.dlland discovered that, in the DLL, the name of the function was"?ringBell@MyClass@MyNamespace@@SAHXZ".Thank you!
I'll also mention that I used Python's getattr function to obtain a reference to the ringBell function:myRingBellFunction = getattr(cdll.RingBell, "?ringBell@MyClass@MyNamespace@@SAHXZ")myRingBellFunction() # invoke the function again
+1  A: 

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

Alex Martelli
My thanks to you, as well!I'll give "extern" a try.
I did give "extern" a try, and it worked! Solution is below for future readers:#include <iostream>extern "C" __declspec(dllexport) int __cdecl ringBell ( void ) { std::cout << "\a" ; return 0 ; }