Вопрос

I have used a C++ dll using MFC and I would like to call it from python. This dll contains this header in the .h file

LONG CommOpen(BYTE port, LONG baud_rate);

Then I see in the free software dllexp that my function is called ?CommOpen@CFIPcmd@@QAEJEJ@Z in the binary file so no error is reported when I do in python

import ctypes

lib = ctypes.WinDLL('C:\\Users\\toto\\FIProtocol.dll')
prototype = WINFUNCTYPE(c_long, c_byte, c_long)
testPt = ctypes.WINFUNCTYPE (prototype) 
testApi = testPt (("?CommOpen@CFIPcmd@@QAEJEJ@Z", lib))

Until there it seems to work but then I would like to call the in Python the equivalent in C++ of

Long l= CommOpen(5 ,115200);

But I Didn't find know how to proceed. Any help would be really appreciated!!

Это было полезно?

Решение

Given the information presented in the question, the solution is:

import ctypes

lib = ctypes.CDLL(r'C:\Users\toto\FIProtocol.dll')
CommOpen = getattr(lib, "?CommOpen@CFIPcmd@@QAEJEJ@Z")
CommOpen.argtypes = [c_byte, c_long]
CommOpen.restype = c_long

And now it is ready to call:

l = CommOpen(5 ,115200)

Some notes:

  1. Use CDLL rather than WinDLL because the function used the default cdecl calling convention.
  2. Use getattr to be able to specify the mangled name.
  3. It always pays to specify argtypes and restype explicitly.

However, it transpires that you have a much greater problem. The above was written on the basis that your function is a non-member function. Which is a reasonable assumption given that ctypes requires functions to be either non-member, or static.

However, when I put your managed function name into a demanger (for instance http://pear.warosu.org/c++filtjs/) it seems that the function is in fact:

public: long __thiscall CFIPcmd::CommOpen(unsigned char,long)

That is a member function of a C++ object. That cannot be accessed from ctypes. You'll need to create a plain C style wrapper, or find a different method of interop.

Другие советы

According to http://docs.python.org/2/library/ctypes.html#calling-functions "You can call these functions like any other Python callable." I would suggest to run an interactive Python console (like ipython) and check it yourself.

Well, I've just installed python into VirtualBox Win32 and checked the example:

>>> from ctypes import *
>>> f = getattr(cdll.msvcrt, "??2@YAPAXI@Z")
>>> f
<_FuncPtr object at 0x00B7EDC8>
>>> f()
24969248
>>> _

So, yes, you may call those function objects like any other function in the python environment. Just as the documentation claims :)

Likewise _cputws works:

>>> cputws = getattr(cdll.msvcrt, "_cputws")
>>> r = cputws("Hello, World!\n")
Hello, World!
>>> r
0
>>>

Here is my how-to sample. Strange why similar missed here.

import ctypes

def StrArg(pyStr = "") -> ctypes.c_char_p:
    return ctypes.c_char_p(pyStr.encode('utf-8'))

def main():
    testlib = ctypes.CDLL("../bin/Debug/MyCoolLib.dll");

    #int ProcessStr(const char*);
    pyProcessStr = testlib.ProcessStr
    pyProcessStr.restype = ctypes.c_int
    pyProcessStr.argtypes = [ctypes.c_char_p]

    nCount = pyProcessStr(StrArg("aaa,bbb,ccc"))
    print(nCount)

    # int DoWithTwoArgs(int nX, unsigned char ucY, const char* szZ);
    pyDoWithTwoArgs = testlib.DoWithTwoArgs
    pyDoWithTwoArgs.restype = ctypes.c_int
    pyDoWithTwoArgs.argtypes = [ctypes.c_int,ctypes.c_byte, ctypes.c_char_p]
    results = pyDoWithTwoArgs(100, 2, StrArg("Trololo"))
    print(results)

    print("Finsh")


if __name__ == "__main__":
    main()
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top