简体   繁体   English

我的 Python Ctypes 结构有什么问题?

[英]What is wrong with my Python Ctypes structures?

I'm having a problem with my structure generation to allow the use of a c Library within Python - I'm hoping someone can point out the errors in my code.我的结构生成出现问题,以允许在 Python 中使用 c 库 - 我希望有人能指出我的代码中的错误。

C Prototype: C 原型:

const char *DSpotterVerInfo(char *lpchLicenseFile, VerInfo *lpVerInfo, INT *lpnErr);

C Struct Definition: C 结构定义:

typedef struct _VerInfo
{
    const char *SDKName;
    const char *SDKVersion;
    const char *SDKType;
    const char *Date;
    const char *LType;
    BOOL  bTrialVersion;
} VerInfo;

My code:我的代码:

class DSVerInfo(ctypes.Structure):
  # This works (at least no ugly errors, but I can't get to the structure data..)
  #_fields_ = [('Name',ctypes.c_char_p)]


  # This defintion causes an error and a segdump
  _fields_ = [ \
                 ('Name', ctypes.c_char_p), \
                 ('Version', ctypes.c_char_p), \
                 ('SDKType', ctypes.c_char_p), \
                 ('Date', ctypes.c_char_p), \
                 ('LicType', ctypes.c_char_p), \
                 ('Trial', ctypes.c_bool) \
              ]

  def __init__(self):
    self.Name = cast(ctypes.create_string_buffer(str.encode("")),ctypes.c_char_p)
    self.Version = cast(ctypes.create_string_buffer(str.encode("")),ctypes.c_char_p)
    self.SDKType = cast(ctypes.create_string_buffer(str.encode("")),ctypes.c_char_p)
    self.Date = cast(ctypes.create_string_buffer(str.encode("")),ctypes.c_char_p)
    self.LicType = cast(ctypes.create_string_buffer(str.encode("")),ctypes.c_char_p)
    self.Trial = c_bool()


libc.MyLibVerInfo.argtypes = (ctypes.c_char_p,DSVerInfo,ctypes.POINTER(c_int))

err_no = ctypes.c_int()
Lic_ct = ctypes.create_string_buffer(str.encode(License_file))
VerInfo = DSVerInfo()

result = libc.DSpotterVerInfo(Lic_ct,VerInfo,err_no)

print("Result:\n",result.decode('utf-8'),"Error No:", err_no.value)
print("Version Size: ", sizeof(VerInfo))
print(VerInfo)  #Not really any use.. just an object until I can use VerInfo.x

Here is a sample of the output when it fails (from the print of the errorNo):这是 output 失败时的示例(来自 errorNo 的打印):

 Error No: 155394711
-155394711
Version Size:  48
<__main__.DSVerInfo object at 0x1093287c0>

Done
Segmentation fault: 11
f01898e9b5db0000:Test rpm$

This is probably what you need.这可能是您需要的。 Here's a sample implementation of the function call:这是 function 调用的示例实现:

test.c测试.c

#include <windows.h>
#include <stdio.h>

typedef struct _VerInfo
{
    const char *SDKName;
    const char *SDKVersion;
    const char *SDKType;
    const char *Date;
    const char *LType;
    BOOL  bTrialVersion;
} VerInfo;

__declspec(dllexport)
const char *DSpotterVerInfo(char *lpchLicenseFile, VerInfo *lpVerInfo, INT *lpnErr) {
    printf("LicenseFile = %s\n", lpchLicenseFile);
    lpVerInfo->SDKName = "SDKName";
    lpVerInfo->SDKVersion = "SDKVersion";
    lpVerInfo->SDKType = "SDKType";
    lpVerInfo->Date = "Date";
    lpVerInfo->LType = "LType";
    lpVerInfo->bTrialVersion = TRUE;
    *lpnErr = 123;
    return "something";
}

To call it:调用它:

test.py测试.py

import ctypes as ct
from ctypes import wintypes as w

class DSVerInfo(ct.Structure):
    _fields_ = [('Name', ct.c_char_p),
                ('Version', ct.c_char_p),
                ('SDKType', ct.c_char_p),
                ('Date', ct.c_char_p),
                ('LicType', ct.c_char_p),
                ('Trial', w.BOOL)]     # c_bool is only 1 byte, Windows BOOL is 4 bytes.

    # Your __init__ is unnecessary.  ctypes inits to null/zero by default
    # and create_string_buffer is only needed if the C function needs
    # pre-allocated buffer to write to.  Since your structure had const
    # char* parameters that wasn't required and pointers to null strings
    # wouldn't be a very big buffer anyway :^)

    # Helper function to print this structure.
    def __repr__(self):
        return f'DSVerInfo({self.Name!r}, {self.Version!r}, {self.SDKType!r}, {self.Date!r}, {self.LicType!r}, {self.Trial!r})'
    
dll = ct.CDLL('./test')

# Make sure to use the correct function name and declare both .argtypes and .restype.
dll.DSpotterVerInfo.argtypes = ct.c_char_p,ct.POINTER(DSVerInfo),ct.POINTER(ct.c_int)
dll.DSpotterVerInfo.restype = ct.c_char_p

err_no = ct.c_int()
Lic_ct = b'licensefile'
VerInfo = DSVerInfo()

result = dll.DSpotterVerInfo(Lic_ct, ct.byref(VerInfo), ct.byref(err_no))

print('Result:', result.decode())
print('Error No:', err_no.value)
print('Version Size: ', ct.sizeof(VerInfo))
print(VerInfo)

Output: Output:

LicenseFile = licensefile
Result: something
Error No: 123
Version Size:  48
DSVerInfo(b'SDKName', b'SDKVersion', b'SDKType', b'Date', b'LType', 1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM