大图:
我有一个用于进程间通信的旧DLL(没有可用的C源代码)-基于编号管道。 DLL使用四个主要功能:
有一些使用此DLL的VB6应用程序,我想粘合Python 3.6.3来替换行过时的通信模块的多个末端。管道通过允许最多两个订户进入同一端口来工作。每个订户必须先打通电话,然后当一个订户写另一个时读,反之亦然。
具体细节:
我想在Python中创建类似于VB6命令按钮句柄的事件侦听器对象。然后,将此win32句柄传递给dll中的open函数,以“注册”一个用于调用read函数的入口点(类似于回调概念,但不太完全)。
旧版DLL使用以下VB6声明:
text
VB6应用程序具有专用格式的命令按钮。此按钮的句柄将传递给开放管道功能,然后用作事件驱动系统,以使数据尽快可用(请参见下面的 myRx.hWnd ):
<%= f.input :message, input_html: {cols: 40, rows: 20} %>
对于Python端(3.6.6)的工作,我使用了ctypes库。首先,声明函数原型:
'************************************************************************************************
' Function OpenPipe/SIOOPEN
' return value: Id of channel (0,1,2,..)
' parameters:
' CommPort - port number.
' MaxTxBuff - max number of Tx buffers
' MaxRxBuff - max number of Rx buffers
' hwndTxIO - Command key handler no. (Null for no handler)
' hwndRxIO - Command key handler no. (Null for no handler),
' HsemTxIO - 0 allways
' HsemRxIO - 0 allways
' BuffSize - max number of bytes per message
' Log - Log TX and RX
'************************************************************************************************
Public Declare Function OpenPipe Lib "CommPipe" _
Alias "_SIOOPEN@36" (ByVal CommPort As Long, _
ByVal MaxTxBuff As Long, _
ByVal MaxRxBuff As Long, _
ByVal hwndTxIO As Long, _
ByVal hwndRxIO As Long, _
ByVal HsemTxIO As Long, _
ByVal HsemRxIO As Long, _
ByVal BuffSize As Long, _
ByVal Log As Boolean) As Long
'************************************************************************************************
' Function ClosePipe/SIOKILL
' return value: true - succeded, false - failed
' parameter: CommChannel - channel no, (use this number to react with open comm ports).
'************************************************************************************************
Public Declare Function ClosePipe Lib "CommPipe" _
Alias "_SIOKILL@4" (ByVal CommChannel As Long) As Boolean
'************************************************************************************************
' Function ReadPipe/SIOREAD
' return value: true - succeded, false - failed
' parameters:
' CommChannel - channel no.
' ReadBuff - address of read buffer
' BuffLen - address of variable contains len of message
'************************************************************************************************
Public Declare Function ReadPipe Lib "CommPipe" _
Alias "_SIOREAD@16" (ByVal CommChannel As Long, _
ByRef ReadBuff As Byte, _
ByRef BuffLen As Long, _
ByRef CmsApStamp As Long) As Boolean
'************************************************************************************************
' Function WritePipe/SIOWRITE
' return value: true - succeded, false - failed
' parameters:
' CommChannel - channel no.
' WriteBuff - address of writeread buffer
' BuffLen - len of message
'************************************************************************************************
Public Declare Function WritePipe Lib "CommPipe" _
Alias "_SIOWRITE@12" (ByVal CommChannel As Long, _
ByRef WriteBuff As Byte, _
ByVal BuffLen As Long) As Boolean
我可以通过运行以下代码来打开通信管道(但是我将hwndRxIO设置为0表示没有句柄):
'CreateConnection FUNCTION
'=====================
'1. establish a connection to the vision computer on a Pipe
'2. establish a connection to the IO card
'If a successful then the function returns 'True'
Private Function CreateConnection(ByVal vPort As Long, _
Optional ByRef vName As String = "", _
Optional vIsMasterPipe As Boolean _
= False) As Boolean
CreateConnection = False
myName = vName
myChannelNo = OpenPipe(vPort, _
MAX_OUT_BUFFERS, _
MAX_IN_BUFFERS, _
0, myRx.hWnd, _
0, 0, _
MAX_PIPE_BUFFER, _
False)
If (myChannelNo >= 0) Then
CreateConnection = True
Call GPipeTrap("CreateConnection OK", myName, "Port", vPort, "Handle", myChannelNo)
Else 'unsuccessful opening
Call GPipeTrap("CreateConnection KO", myName, "Port", vPort)
' MsgBox "Could not open COM port " & CNTPORTNO, key_Critical, "Vision Pipe Error"
End If
End Function
通过在python脚本中进行懒惰轮询,我能够从在该行的“另一”端运行的应用程序接收数据:
self.hllDll =ctypes.WinDLL(str(dll_target))
#Open pipe
self.hllOpenPipeProto = ctypes.WINFUNCTYPE (
ctypes.c_long, # Return type - ID of channel
ctypes.c_long, # CommPort
ctypes.c_long, # MaxTXBuff
ctypes.c_long, # MaxRXBuff
ctypes.c_long, # hwndTxIO
ctypes.c_long, # hwndRxIO
ctypes.c_long, # HsemTxIO
ctypes.c_long, # HsemRxIO
ctypes.c_long, # BuffSize
ctypes.c_bool) # Log
self.hllOpenPipeParams = (
(1, "CommPort", 0),
(1, "MaxTXBuff", 0),
(1, "MaxRXBuff", 0),
(1, "hwndTxIO", 0),
(1, "hwndRxIO", 0),
(1, "HsemTxIO", 0),
(1, "HsemRxIO", 0),
(1, "BuffSize", 0),
(1, "Log", 0),)
self.hllOpenPipe = self.hllOpenPipeProto (("_SIOOPEN@36", self.hllDll), self.hllOpenPipeParams)
#Close pipe
self.hllClosePipeProto = ctypes.WINFUNCTYPE (
ctypes.c_bool, # Return type - succeded
ctypes.c_long) # Channel number
self.hllClosePipeParams = (1, "ChannelNumber", 0),
self.hllClosePipe = self.hllClosePipeProto (("_SIOKILL@4", self.hllDll), self.hllClosePipeParams)
#Read pipe
self.hllReadPipeProto = ctypes.WINFUNCTYPE (
ctypes.c_bool, # Return type - Succed or failed
ctypes.c_long, # Channel number
ctypes.c_void_p, # Read buffer
ctypes.c_void_p, # Buffer length
ctypes.c_void_p) # CmsApStamp ?
self.hllReadPipeParams = (
(1, "ChannelNo", 0),
(1, "ReadBuffer", 0),
(1, "BufferLength", 0),
(1, "CmsApStamp", 0),)
self.hllReadPipe = self.hllReadPipeProto (("_SIOREAD@16", self.hllDll), self.hllReadPipeParams)
最后一次重述:如何在Python中创建一个事件侦听器对象,这实际上是调用我已经在惰性轮询循环中实现的读取管道函数的起点。
编辑:在丹尼尔的要求下,Spy ++输出显示以下消息:
def __open_pipe(self):
#Open pipe based on settings
port=str(self.settings['PORT'])
self.logger.debug('Opening pipe on port ['+port+']..')
CommPort = ctypes.c_long (int(port))
MaxTXBuff = ctypes.c_long (self.MAX_OUT_BUFFERS)
MaxRXBuff = ctypes.c_long (self.MAX_IN_BUFFERS)
hwndTxIO = ctypes.c_long (0)
hwndRxIO = ctypes.c_long (0)
HsemTxIO = ctypes.c_long (0)
HsemRxIO = ctypes.c_long (0)
BuffSize = ctypes.c_long (self.MAX_PIPE_BUFFER)
Log = ctypes.c_bool (0)
result=self.hllOpenPipe(
CommPort,
MaxTXBuff,
MaxRXBuff,
hwndTxIO,
hwndRxIO,
HsemTxIO,
HsemRxIO,
BuffSize,
Log)
self.logger.debug('Result is ['+str(result)+']')
self.comm_channel=result
if self.comm_channel<0:
self.logger.critical('Could not open pipe on port ['+port+']!')
else:
self.logger.info('Pipe ['+str(port)+'] open OK, comm channel ['+str(self.comm_channel)+']')
如何使用ctypes获取我可以链接到Python函数的hwndCtl?