ctypes, python3.8 : OSError: exception: access violation writing 0x00000000

ctypes, python3.8 : OSError: exception: access violation writing 0x00000000

我想通过 python 3.8 运行 一个 dll 我的 dll 部分有一个函数:

void DLLAPI __stdcall GenerateReport (
    int             SeqContext,
    char*           szHost,
    char*           szDBName,
    char*           szUser,
    char*           szPasswd,
    const char*     szUut_Result_Id,
    char            szStylesheet[MAX_PATHNAME_LEN],
    char            szDestinationDir[MAX_DIRNAME_LEN],
    char            szPrefix[MAX_FILENAME_LEN],
    char            szFileName[MAX_PATHNAME_LEN],
    char            szPathName[MAX_PATHNAME_LEN],
    short*          psErrorOccurred,
    long*           plErrorCode,
    char            szErrorMessage[1024]
    );

对于 python 部分,我是这样做的:

def PrintReport():
    szNom_PV_Court = ''
    szErrormessage = ''
    sErrorok = 0
    lErrorcode = 0

    worker_ = cdll.LoadLibrary("D:\users\Worker.dll")

    if (worker_ == 0):
        print( " Could not open file DLL")

    worker_.GenerateReport( 0, "localhost" ,  "backend" , "user" , "test12", str( Uut_Result_Id ) , "D:\users\py\ResourceFiles\Gen.xsl" , "D:\users\py","" ,szNom_PV_Court , "D:\users\py" ,sErrorok ,lErrorcode ,szErrormessage )

当我执行我的代码时出现错误:OSError:异常:访问冲突写入 0x0000000

我不明白这个错误,请帮助

您没有为 DLL 填充所有字符串,因此它们被初始化为零。您的 dll 正试图从地址 0x0(零)读取并为此被 OS 击中。用正确的值填写所有必填字段。

Python 3 中的 "localhost" 等字符串是 Unicode 字符串,由 ctypes 翻译为 wchar_t*。将 b'localhost' 用于转换为 char*.

的字节字符串

此外,为您的函数定义 .argtypes.restype,以便 ctypes 正确编组您的参数:

worker_.argtypes = c_int,c_char_p,c_char_p,c_char_p,c_char_p,c_char_p,c_char_p,c_char_p,c_char_p,c_char_p,c_char_p,POINTER(c_short),POINTER(c_long),c_char_p
worker_.restype = None

您的调用中也只有 13 个参数,但为函数定义了 14 个。

short*long* 使用以下内容来创建可以传递给调用的实例。现在您传递一个零作为默认值 c_int,这可能是空指针异常的来源。

sErrorok = c_short()
lErrorcode = c_long()

调用使用 byref(sErrorok)byref(lErrorcode) 作为指针传递给调用。

这是一个完整的例子。我跳过了很多输入字符串,只显示一个供参考:

test.c

#include <stdio.h>
#include <string.h>

#define DLLAPI __declspec(dllexport)

void DLLAPI __stdcall GenerateReport (
    int             SeqContext,
    char*           szHost,
    short*          psErrorOccurred,
    long*           plErrorCode,
    char            szErrorMessage[1024]
    )
{
    printf("SeqContext = %d szHost = %s\n",SeqContext,szHost);
    *psErrorOccurred = 5;
    *plErrorCode = 123;
    strcpy_s(szErrorMessage,1024,"error message");
}

test.py

from ctypes import *

szNom_PV_Court = ''
szErrormessage = ''
sErrorok = 0
lErrorcode = 0

dll = WinDLL('./test.dll')
dll.GenerateReport.argtypes = c_int,c_char_p,POINTER(c_short),POINTER(c_long),c_char_p
dll.GenerateReport.restype = None

err_occurred = c_short()
errcode = c_long()
errmsg = create_string_buffer(1024)

dll.GenerateReport(7,b'localhost',byref(err_occurred),byref(errcode),errmsg)
print(err_occurred.value,errcode.value,errmsg.value.decode())

输出:

SeqContext = 7 szHost = localhost
5 123 error message