Reading double c structures of Dll with Ctypes in Python
Question:
I’v done researched a lot about this problem.. But there’s no where and I couldn’t find it. I’m trying to call double c structure by calling c dll.
My question is, did i right way to declare “Class Structure” in python? I couldn’t think that i’m right on my way. Because even though the Functions that I want to call from dll, It didn’t come output anything.
[Visual C++/C]
I did try to C Syntax code,
typedef sturct {
int nBoardNum;
struct{
char pBoardName[16];
int nBoardID;
}BOARDINDEX[8];
}AAPBOARDINFO, *PAAPBOARDINFO;
HANDLE AcapOpen(char* cpBoardName, int nBoardNo, int nCh)
[Python]
I changed Python Syntax like this.
import ctypes as c
class BOARDINDEX(c.Structure):
_field_ = [("nBoardName", c.c_char_p * 16),("nBoardID", c.c_int)]
class AAPBOARDINFO(c.Structure):
_field_ = [("nBoardNum", c.c_int), ("BOARDINDEX", BOARDINDEX * 8)]
AapLib2 = c.WinDLL("AapLib2.dll")
BoardName = ["ABC","FWD","HGW"]
BoardNo = 0
ch = 1
output = Open(BoardName, BoardNo, ch)
def Open(BoardName, BoardNo, ch)
func = AapLib2.AcapOpen
func.argtypes = [c.POINTER(BOARDINDEX),c.c_int, c.c_int]
func.restype = c.c_int
ref = BOARDINDEX()
res = func(c.byref(ref.nBoardName),BoardNo, ch)
return res
Nothing outcomes when call Open() function…
please consider my request and any answer would be great…
Answers:
Everything you need to know, can be found in the [Python.Docs]: ctypes – A foreign function library for Python.
There are a couple of problems with the code:
-
Structure members are specified in the _fields_ (not _field_) attribute
-
char pBoardName[16]
maps to ctypes.c_char * 16
(not c_char_p)
-
HANDLE should be mapped to wintypes.HANDLE
-
Function prototype differs between C and Python
-
Using globals like AapLib2 is best to be be avoided, but I left them unchanged as they are outside the question scope
#1. and #3. will generate Undefined Behavior! Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati’s answer) for more details.
Here’s a modified version of your code. Needless to say that I didn’t actually test it, as I don’t have the .dll:
#!/usr/bin/env python
import ctypes as cts
import sys
from ctypes import wintypes as wts
class BOARDINDEX(cts.Structure):
_fields_ = [
("nBoardName", cts.c_char * 16),
("nBoardID", cts.c_int),
]
class AAPBOARDINFO(cts.Structure):
_fields_ = [
("nBoardNum", cts.c_int),
("BOARDINDEX", BOARDINDEX * 8),
]
def open_board(board_name, board_no, ch):
AcapOpen = aaplib2.AcapOpen
AcapOpen.argtypes = (cts.c_char_p, cts.c_int, cts.c_int)
AcapOpen.restype = wts.HANDLE
ref = BOARDINDEX(board_name, board_no) # Probably this line should be replaced by the 3 (commented) ones below (AcapGetBoardInfo prototype would have to be specified as well)
#abi = AAPBOARDINFO()
#AcapGetBoardInfo(cts.byref(abi))
#ref = abi.BOARDINDEX[0]
res = AcapOpen(ref.nBoardName, ref.nBoardID, ch)
return res
def main(*argv):
board_names = (
"ABC",
"FWD",
"HGW",
)
board_no = 0
ch = 1
aaplib2 = cts.WinDLL("AapLib2.dll")
output = open_board(board_names[0], board_no, ch)
print(output)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}n".format(" ".join(elem.strip() for elem in sys.version.split("n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("nDone.n")
sys.exit(rc)
Let me know how this works out.
I’v done researched a lot about this problem.. But there’s no where and I couldn’t find it. I’m trying to call double c structure by calling c dll.
My question is, did i right way to declare “Class Structure” in python? I couldn’t think that i’m right on my way. Because even though the Functions that I want to call from dll, It didn’t come output anything.
[Visual C++/C]
I did try to C Syntax code,
typedef sturct {
int nBoardNum;
struct{
char pBoardName[16];
int nBoardID;
}BOARDINDEX[8];
}AAPBOARDINFO, *PAAPBOARDINFO;
HANDLE AcapOpen(char* cpBoardName, int nBoardNo, int nCh)
[Python]
I changed Python Syntax like this.
import ctypes as c
class BOARDINDEX(c.Structure):
_field_ = [("nBoardName", c.c_char_p * 16),("nBoardID", c.c_int)]
class AAPBOARDINFO(c.Structure):
_field_ = [("nBoardNum", c.c_int), ("BOARDINDEX", BOARDINDEX * 8)]
AapLib2 = c.WinDLL("AapLib2.dll")
BoardName = ["ABC","FWD","HGW"]
BoardNo = 0
ch = 1
output = Open(BoardName, BoardNo, ch)
def Open(BoardName, BoardNo, ch)
func = AapLib2.AcapOpen
func.argtypes = [c.POINTER(BOARDINDEX),c.c_int, c.c_int]
func.restype = c.c_int
ref = BOARDINDEX()
res = func(c.byref(ref.nBoardName),BoardNo, ch)
return res
Nothing outcomes when call Open() function…
please consider my request and any answer would be great…
Everything you need to know, can be found in the [Python.Docs]: ctypes – A foreign function library for Python.
There are a couple of problems with the code:
-
Structure members are specified in the _fields_ (not _field_) attribute
-
char pBoardName[16]
maps toctypes.c_char * 16
(not c_char_p) -
HANDLE should be mapped to wintypes.HANDLE
-
Function prototype differs between C and Python
-
Using globals like AapLib2 is best to be be avoided, but I left them unchanged as they are outside the question scope
#1. and #3. will generate Undefined Behavior! Check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati’s answer) for more details.
Here’s a modified version of your code. Needless to say that I didn’t actually test it, as I don’t have the .dll:
#!/usr/bin/env python
import ctypes as cts
import sys
from ctypes import wintypes as wts
class BOARDINDEX(cts.Structure):
_fields_ = [
("nBoardName", cts.c_char * 16),
("nBoardID", cts.c_int),
]
class AAPBOARDINFO(cts.Structure):
_fields_ = [
("nBoardNum", cts.c_int),
("BOARDINDEX", BOARDINDEX * 8),
]
def open_board(board_name, board_no, ch):
AcapOpen = aaplib2.AcapOpen
AcapOpen.argtypes = (cts.c_char_p, cts.c_int, cts.c_int)
AcapOpen.restype = wts.HANDLE
ref = BOARDINDEX(board_name, board_no) # Probably this line should be replaced by the 3 (commented) ones below (AcapGetBoardInfo prototype would have to be specified as well)
#abi = AAPBOARDINFO()
#AcapGetBoardInfo(cts.byref(abi))
#ref = abi.BOARDINDEX[0]
res = AcapOpen(ref.nBoardName, ref.nBoardID, ch)
return res
def main(*argv):
board_names = (
"ABC",
"FWD",
"HGW",
)
board_no = 0
ch = 1
aaplib2 = cts.WinDLL("AapLib2.dll")
output = open_board(board_names[0], board_no, ch)
print(output)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}n".format(" ".join(elem.strip() for elem in sys.version.split("n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("nDone.n")
sys.exit(rc)
Let me know how this works out.