Python Ctypes 异常:访问冲突读取

5 投票
1 回答
16750 浏览
提问于 2025-04-17 19:28

我正在尝试通过一个DLL(这是PLC制造商提供的C语言接口)与PLC进行通信。我使用的是嵌入在其他软件中的Python 3.1(64位 - Windows 7)。

我已经成功让一些DLL函数工作,但现在遇到了一个“访问违规读取”的错误,我不知道该怎么解决。

关于这个DLL函数的信息:

LONG AdsSyncReadReq(
  PAmsAddr  pAddr,
  ULONG     nIndexGroup,
  ULONG     nIndexOffset,
  ULONG     nLength,
  PVOID     pData
);

参数:

  • pAddr: [输入] 包含ADS服务器的网络ID和端口号的结构体。
  • nIndexGroup: [输入] 索引组。
  • nIndexOffset: [输入] 索引偏移量。
  • nLength: [输入] 数据的字节长度。
  • pData: [输出] 指向一个数据缓冲区的指针,用于接收数据。
  • 返回值: 返回函数的错误状态。

结构体 AmsAddr:

typedef struct {
  AmsNetId        netId;
  USHORT          port;
} AmsAddr, *PAmsAddr;

结构体 AmsNetId

typedef struct {
  UCHAR        b[6];
} AmsNetId, *PAmsNetId;

Python 实现:

# -*- coding: utf-8 -*-
from ctypes import *

#I've tried OleDll and windll as wel..
ADS_DLL = CDLL("C:/Program Files/TwinCAT/Ads Api/TcAdsDll/x64/TcAdsDll.dll")

class AmsNetId(Structure):
    _fields_ = [('NetId',  c_ubyte*6)]

class AmsAddr(Structure):
    _fields_=[('AmsNetId',AmsNetId),('port',c_ushort)]

# DLL function working fine
version = ADS_DLL.AdsGetDllVersion()
print(version)

#DLL function working fine
errCode = ADS_DLL.AdsPortOpen()
print(errCode)

#DLL function using the AmsAddr() class, working fine
amsAddress = AmsAddr()
pointer_amsAddress = pointer(amsAddress)
errCode = ADS_DLL.AdsGetLocalAddress(pointer_amsAddress)
print(errCode)
contents_amsAddres = pointer_amsAddress.contents

#Function that doens't work:
errCode = ADS_DLL.AdsSyncReadReq()
print(errCode) # --> errCode = timeout error, normal because I didn't pass any arguments

# Now with arguments:
plcNetId = AmsNetId((c_ubyte*6)(5,18,18,27,1,1)) #correct adress to the PLC
plcAddress = AmsAddr(plcNetId,801) #correct port to the PLC
nIndexGroup = c_ulong(0xF020)
nIndexOffset = c_ulong(0x0) 
nLength = c_ulong(0x4)
data = c_void_p()
pointer_data = pointer(data)

#I tried with an without the following 2 lines, doesn't matters 
ADS_DLL.AdsSyncReadReq.argtypes=[AmsAddr,c_ulong,c_ulong,c_ulong,POINTER(c_void_p)]
ADS_DLL.AdsSyncReadReq.restype=None

#This line crashes
errCode = ADS_DLL.AdsSyncReadReq(plcAddress,nIndexGroup,nIndexOffset,nLength,pointer_data)
print(errCode)


>>>> Error in line 57: exception: access violation reading 0xFFFFFFFFFFFFFFFF

我希望有人能找出问题所在。我在Python编程方面只是个进阶的新手,对C语言完全没有经验。

提前感谢大家!

1 个回答

2

你传递了一个无效的指针,应该提供一个有效的内存缓冲区:

data = create_string_buffer(nLength)

如果 PVOID 代表的是 void *,那么参数应该直接用 c_void_p,而不是 POINTER(c_void_p)。不要把返回类型设置为 None(这个函数返回的是 LONG)。

还要传入 pointer(plcAddress)(在参数类型中指定 POINTER(AmsAddr))。

使用正确的调用约定(在 cdll、windll 和 oledll 中选择一种)。

撰写回答