python अजगर ctypes विभिन्न ओएस पर जारी करता है




python-3.x windows (3)

मैं अजगर के 3.6 उपयोग के लिए सी फ़ंक्शन को बदलने की कोशिश कर रहा हूं।

नीचे के रूप में कोड:

lib = ctypes.WinDLL('ftrScanAPI.dll') # provided by fingerprint scanner
class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
    _fields_ = [
    ("nWidth", ctypes.c_int),
    ("nHeight", ctypes.c_int),
    ("nImageSize", ctypes.c_int)
]

print('Open device and get device handle...')
hDevice = lib.ftrScanOpenDevice()
print('handle is', hDevice)
print('Get image size...')
Image_size = FTRSCAN_IMAGE_SIZE(0, 0, 0)
if lib.ftrScanGetImageSize(hDevice, ctypes.byref(Image_size)):
    print('Get image size succeed...')
    print('  W', Image_size.nWidth)
    print('  H', Image_size.nHeight)
    print('  Size', Image_size.nImageSize)
else:
    print('Get image size failed...')

फ़ंक्शन की परिभाषा:

typedef struct FTR_PACKED __FTRSCAN_IMAGE_SIZE {
    int nWidth;
    int nHeight;
    int nImageSize;
} FTRSCAN_IMAGE_SIZE, *PFTRSCAN_IMAGE_SIZE;
FTRHANDLE ftrScanOpenDevice();  # typedef void *  FTRHANDLE;
BOOL ftrScanGetImageSize(FTRHANDLE ftrHandle, 
    PFTR_SCAN_IMAGE_SIZE pImageSize);

लेकिन एक ही कोड वाले अलग OS का अलग परिणाम दिखता है:

  • विंडोज 7 64 बिट पर

  • विंडोज 10 64 बिट पर
    मैं प्रिंट नहीं करता "हैंडल यहाँ है"

    मैंने क्या कोशिश की है:
    स्टैक ओवरफ्लो पर कुछ उत्तरों के अनुसार, यह फ़ंक्शन argtypes को निर्दिष्ट नहीं करने और स्पष्ट रूप से पुनर्स्थापित करने के कारण हो सकता है, इसलिए मैंने कोशिश की और असफल रहा।


  • 99% मामलों में, तर्कों के बीच असंगतता (और / या वापसी) प्रकार की असंगति का कारण होता है ( .com/questions/52268294/… ऐसा ही एक उदाहरण)।

    हमेशा [पायथन 3. डॉक्स]: ctypes - ctypes के साथ काम करने पर पायथन के लिए एक विदेशी फंक्शन लाइब्रेरी खुली।

    मैंने पाया [GitHub]: erikssm / futronics-फिंगरप्रिंट-रीडर - (मास्टर) futronics-फिंगरप्रिंट-रीडर / ftrScanAPI.h (मुझे नहीं पता कि यह वर्तमान में आपके पास कितने अलग है, लेकिन आपके द्वारा पोस्ट की गई चीजें अब तक मेल खाती हैं। ), और मैंने आपके कोड में कुछ बदलाव किए हैं:

    • Argtypes को परिभाषित करें और कार्यों के लिए पुनर्स्थापित करें
    • लापता प्रकार को परिभाषित करें (केवल स्पष्टता के लिए)
    • कुछ अन्य महत्वहीन परिवर्तन (नाम)
    • एक अन्य चीज़ जो मैंने उपरोक्त फ़ाइल में देखी है, वह एक #pragma pack(push, 1) मैक्रो (चेक [MS.Docs]: अधिक विवरण के लिए पैक ) है। इस संरचना के लिए इससे कोई अंतर नहीं पड़ता है (धन्यवाद @ संकेत के लिए @AnttiHaapala), जैसा कि 3 int ( 4 बाइट) सदस्यों के संरेखण में बदलाव नहीं होता है, लेकिन अन्य संरचनाओं के लिए ("छोटे" सदस्य प्रकारों (जैसे चार , लघु ) के साथ) जोड़ना चाह सकते हैं: _pack_ = 1

    आपका संशोधित कोड (कहने की जरूरत नहीं है, मैंने इसे नहीं चलाया क्योंकि मेरे पास .dll नहीं है):

    from ctypes import wintypes
    
    # ...
    
    lib = ctypes.WinDLL('ftrScanAPI.dll') # provided by fingerprint scanner
    class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
        # _pack_ = 1
        _fields_ = [
            ("nWidth", ctypes.c_int),
            ("nHeight", ctypes.c_int),
            ("nImageSize", ctypes.c_int),
        ]
    
    PFTRSCAN_IMAGE_SIZE = ctypes.POINTER(FTRSCAN_IMAGE_SIZE)
    FTRHANDLE = ctypes.c_void_p
    
    print('Open device and get device handle...')
    
    lib.ftrScanOpenDevice.argtypes = []
    lib.ftrScanOpenDevice.restype = FTRHANDLE
    
    h_device = lib.ftrScanOpenDevice()
    print('handle is', h_device)
    print('Get image size...')
    image_size = FTRSCAN_IMAGE_SIZE(0, 0, 0)
    
    lib.ftrScanGetImageSize.argtypes = [FTRHANDLE, PFTRSCAN_IMAGE_SIZE]
    lib.ftrScanGetImageSize.restype = wintypes.BOOL
    
    if lib.ftrScanGetImageSize(h_device, ctypes.byref(image_size)):
        print('Get image size succeed...')
        print('  W', image_size.nWidth)
        print('  H', image_size.nHeight)
        print('  Size', image_size.nImageSize)
    else:
        print('Get image size failed...')

    आपको अपने .argtypes और .restype प्रयास दिखाने चाहिए, लेकिन इसे आज़माएँ:

    from ctypes import wintypes as w
    
    class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
        _fields_ = [('nWidth', ctypes.c_int),
                    ('nHeight', ctypes.c_int),
                    ('nImageSize', ctypes.c_int)]
    
    FTRHANDLE = ctypes.c_void_p
    
    lib = ctypes.WinDLL('ftrScanAPI.dll')
    lib.ftrScanOpenDevice.argtypes = None
    lib.ftrScanOpenDevice.restype = FTRHANDLE
    lib.ftrScanGetImageSize.argtypes = FTRHANDLE,ctypes.POINTER(FTRSCAN_IMAGE_SIZE)
    lib.ftrScanGetImageSize.restype = w.BOOL

    WinDLL बनाम CDLL के उपयोग की जाँच करें। यह मायने नहीं रखेगा कि आपका पायथन 64-बिट है, लेकिन यह 32-बिट पायथन पर फर्क करता है। अगर फ़ंक्शन C __stdcall कॉलिंग कन्वेंशन का उपयोग करते हैं, तो फ़ंक्शन C C कन्वेंशन (__cdecl) और WinDLL उपयोग करते हैं, तो CDLL उपयोग करें। यदि हेडर फ़ाइल स्पष्ट नहीं है, तो डिफ़ॉल्ट आमतौर पर __cdecl है। संपादित करें: दूसरे लिंक में एपीआई लिंक से, यह __stdcall और WinDLL का उपयोग किया जाना चाहिए।


    समस्या केवल यह प्रतीत होती है कि डिवाइस हैंडल 64-बिट इकाई है (टाइप करने के लिए एक टाइप्डिफ़ीड सूचक)। यह आपके विंडोज 7 में काम करता है सिर्फ एक अस्थायी था, क्योंकि हैंडल के ऊपरी 33 बिट्स सही ढंग से शून्य थे।

    Ctypes में सभी फ़ंक्शंस का रिटर्न प्रकार 32-बिट int डिफॉल्ट करता है। अब विंडोज 10 में ऐसा लगता है कि 32 वां बिट (साइन बिट) सेट किया गया था, जो फ़ंक्शन कॉल के लिए 64-बिट स्टैक पर हैंडल-कोर्डेड-टू-इंट को धक्का दिए जाने पर कहीं न कहीं एक साइन एक्सटेंशन का कारण बनता है। परिणामी पते में सभी ऊपरी बिट्स सेट हैं (0xFFFFFFFFA ...) जो कर्नेल स्थान को इंगित करता है और उपयोगकर्ता स्थान में नहीं।

    इस प्रकार शायद आप अपना कोड "काम" बस के साथ प्राप्त कर सकते हैं

    lib.ftrScanOpenDevice.restype = c_void_p

    यह कहने के लिए नहीं है कि आप सभी कार्यों के लिए तर्क और वापसी प्रकारों को परिभाषित नहीं करना चाहिए - आपको करना चाहिए, अन्यथा वे सी भाषा के डिफ़ॉल्ट तर्क पदोन्नति नियमों का पालन करेंगे, और काम करेंगे ... या पूरी तरह से काम करने में विफल रहेंगे, निर्भर करता है क्या फ़ंक्शन का प्रोटोटाइप स्वयं डिफ़ॉल्ट तर्क पदोन्नति के साथ संगत है। उदाहरण के लिए कोई भी फ़ंक्शन जो float s को स्वीकार करता है क्योंकि प्रोटोटाइप को परिभाषित किए बिना तर्क को सही ढंग से नहीं कहा जा सकता है।





    ctypes