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