如何为DLL库创建Python包装器

时间:2014-10-17 11:24:19

标签: python windows dll wrapper ctypes

我正在尝试从软件SDK获取提供的DLL文件并创建一个python包装器,以便将其与我的其余代码库集成。我在网上关注了不少指南,但仍然没有运气。

我目前使用的Python代码是:

from ctypes import *
from ctypes.wintypes import HWND
import os

class OptistarDLL(object):
    dll_path = 'OSDS142MRT.dll'

    with open(dll_path) as thefile:
        pass

    _dll = WinDLL(dll_path)

    init_library = _dll['OSDS142M_Initialize']
    init_library.restype = c_int
    init_library.argtypes = (c_int, c_bool, HWND, c_bool, c_int)


class OpticstarControl(object):

    def __init__(self):
        err = OptistarDLL.init_library(c_int(0), c_bool(False), HWND(0), c_bool(False), c_int(0))
        if err != 0:
            raise Exception("Doom")

我正在使用的SDK文档将此作为函数的标题提供:

DLLDIR int OSDS142M_Initialize(int iModel, bool bOutVid, HWND hwOutVid, bool bStarView, int iRt);

示例PDF给出:

OSDS142M_Initialize(1, false, 0, true, 0);

初始化目前仅限我

ValueError: Procedure probably called with too many arguments (20 bytes in excess)

我已阅读但未了解WinDLL vs CDLL,并且当我更改为CDLL时,DLL的加载失败。我在所有指南中都看到其中的标题为DLLEXPORT而我的标题为DLLDIR,我不知道这是否是一个问题。

有没有人有任何想法?

1 个答案:

答案 0 :(得分:2)

根据问题中的信息,最可能的解释是DLL使用cdecl而不是stdcall。您对WinDLL的使用与stdcall DLL匹配。请改用CDLL切换到cdecl呼叫约定。

错误消息与此一致。调用约定之间的区别在于stdcall具有被调用者堆栈清理并且cdecl具有调用者清理。这些参数在堆栈上消耗20个字节,是5个大小为4的参数。而ctypes推送这些参数并期望被调用者清理堆栈。这不是因为它是cdecl函数。

你对函数的调用是不必要的复杂。你可以写:

err = OptistarDLL.init_library(0, False, 0, False, 0)

请注意,您引用的示例调用会传递不同的参数。要匹配该电话,您可以写:

err = OptistarDLL.init_library(1, False, 0, True, 0)

您当然应该删除此代码:

with open(dll_path) as thefile:
    pass

除了浪费时间之外没有任何其他目的。如果DLL不存在,您很快就会遇到失败。