我正在尝试从软件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
和CDLL
,当我更改为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不存在,您将很快遇到失败。