如何使用python ctypes模拟VB6命令按钮_Click事件

时间:2018-08-16 08:14:25

标签: python winapi vb6 ctypes

大图:

我有一个用于进程间通信的旧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?

0 个答案:

没有答案