我正在尝试从软件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)

我已经阅读但不了解WinDLLCDLL,当我更改为CDLL时,DLL的加载失败。在所有指南中,我还看到其中的 header 包含DLLEXPORT,而我的 header 包含DLLDIR,我不知道这是否值得关注。

有人有什么想法吗?

最佳答案

给定问题中的信息,最可能的解释是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不存在,您将很快遇到失败。

10-06 06:29