ctypes,python3.8:OSError:异常:访问冲突写入0x00000000

Posted

技术标签:

【中文标题】ctypes,python3.8:OSError:异常:访问冲突写入0x00000000【英文标题】:ctypes, python3.8 : OSError: exception: access violation writing 0x00000000 【发布时间】:2020-06-15 23:26:02 【问题描述】:

我想通过 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

我不明白这个错误请帮忙

【问题讨论】:

【参考方案1】:

像 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

【讨论】:

感谢您的回答,但是当我想打印消息时 szErrormessage 仍然为空。我认为这与声明变量有关。我确实喜欢这个 szErrormessage = "" 并且对于 generateReport 函数我做了 c_char_p( szErrormessage.encode('utf-8') ) 但是当我想打印 print( szErrormessage.encode('utf-8') ) 答案仍然是空的 是不是 : szErrormessage = c_char_p() 用于声明,就像您为 sErrorok 和 lErrorcode 所做的那样? @TheRight szErrormessage = create_string_buffer(1024) 将为返回字符串分配一个缓冲区。 szErrormessage = c_char_p() 将分配一个初始化为 NULL 的指针。任何其他输出字符串也应该为其分配内存。 对于声明我确实像你说的那样:szErrormessage = create_string_buffer(1024) 和对于 generateReport 方法我让像 GenerateReport(....,szErrormessage)。但是当我打印(szErrormessage)时,输出是:。它需要消息解码或如何解码? @TheRight 用一个例子更新了答案。【参考方案2】:

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

【讨论】:

以上是关于ctypes,python3.8:OSError:异常:访问冲突写入0x00000000的主要内容,如果未能解决你的问题,请参考以下文章

Python Ctypes OSError:异常:访问冲突读取0x00000000

ctypes,python3.5,OSError:异常:访问冲突写入 0x00000000

PYTHON - Ctypes:OSError:异常:访问冲突写入0xFFFFFFFFFA1C001B

python3.8 load dll OSError: [WinError 127] The specified procedure could not be found

OSError:Windows 10 中的 [WinError 10013] 错误

Linux上使用pip 安装mysqlclient,pip install mysqlclient==2.0.1遇到的问题:OSError: mysql_config not found