Attachment 'WndProcHookMixinCtypes.py'

Download

   1 ##########################################################################
   2 ##
   3 ##  This is a modification of the original WndProcHookMixin by Kevin Moore,
   4 ##  modified to use ctypes only instead of pywin32, so it can be used
   5 ##  with no additional dependencies in Python 2.5
   6 ##
   7 ##########################################################################
   8 
   9 import ctypes
  10 from ctypes import c_long, c_int
  11 
  12 import wx
  13 
  14 ## It's probably not neccesary to make this distinction, but it never hurts to be safe
  15 if 'unicode' in wx.PlatformInfo:
  16     SetWindowLong = ctypes.windll.user32.SetWindowLongW
  17     CallWindowProc = ctypes.windll.user32.CallWindowProcW
  18 else:
  19     SetWindowLong = ctypes.windll.user32.SetWindowLongA
  20     CallWindowProc = ctypes.windll.user32.CallWindowProcA
  21     
  22 GWL_WNDPROC = -4
  23 WM_DESTROY  = 2
  24 
  25 ## Create a type that will be used to cast a python callable to a c callback function
  26 ## first arg is return type, the rest are the arguments
  27 WndProcType = ctypes.WINFUNCTYPE(c_int, c_long, c_int, c_int, c_int)
  28 
  29 class WndProcHookMixin:
  30     """
  31     This class can be mixed in with any wxWindows window class in order to hook it's WndProc function. 
  32     You supply a set of message handler functions with the function addMsgHandler. When the window receives that
  33     message, the specified handler function is invoked. If the handler explicitly returns False then the standard 
  34     WindowProc will not be invoked with the message. You can really screw things up this way, so be careful. 
  35     This is not the correct way to deal with standard windows messages in wxPython (i.e. button click, paint, etc) 
  36     use the standard wxWindows method of binding events for that. This is really for capturing custom windows messages
  37     or windows messages that are outside of the wxWindows world.
  38     """
  39     def __init__(self):
  40         self.__msgDict = {}
  41         ## We need to maintain a reference to the WndProcType wrapper
  42         ## because ctypes doesn't
  43         self.__localWndProcWrapped = None 
  44         
  45     def hookWndProc(self):
  46         self.__localWndProcWrapped = WndProcType(self.localWndProc)
  47         self.__oldWndProc = SetWindowLong(self.GetHandle(),
  48                                         GWL_WNDPROC,
  49                                         self.__localWndProcWrapped)
  50     def unhookWndProc(self):
  51         SetWindowLong(self.GetHandle(),
  52                         GWL_WNDPROC,
  53                         self.__oldWndProc)
  54         
  55         ## Allow the ctypes wrapper to be garbage collected
  56         self.__localWndProcWrapped = None
  57 
  58     def addMsgHandler(self,messageNumber,handler):
  59         self.__msgDict[messageNumber] = handler
  60 
  61     def localWndProc(self, hWnd, msg, wParam, lParam):
  62         # call the handler if one exists
  63         # performance note: has_key is the fastest way to check for a key
  64         # when the key is unlikely to be found
  65         # (which is the case here, since most messages will not have handlers).
  66         # This is called via a ctypes shim for every single windows message 
  67         # so dispatch speed is important
  68         if self.__msgDict.has_key(msg):
  69             # if the handler returns false, we terminate the message here
  70             # Note that we don't pass the hwnd or the message along
  71             # Handlers should be really, really careful about returning false here
  72             if self.__msgDict[msg](wParam,lParam) == False:
  73                 return
  74 
  75         # Restore the old WndProc on Destroy.
  76         if msg == WM_DESTROY: self.unhookWndProc()
  77 
  78         return CallWindowProc(self.__oldWndProc,
  79                                 hWnd, msg, wParam, lParam)
  80 
  81 # a simple example
  82 if __name__ == "__main__":
  83     
  84     class MyFrame(wx.Frame,WndProcHookMixin):
  85         def __init__(self,parent):
  86             WndProcHookMixin.__init__(self)
  87             frameSize = wx.Size(640,480)
  88             wx.Frame.__init__(self,parent,-1,"Change my size and watch stdout",size=frameSize)
  89             # this is for demo purposes only, use the wxPython method for getting events 
  90             # on window size changes and other standard windowing messages
  91             WM_SIZE = 5
  92             self.addMsgHandler(WM_SIZE, self.onHookedSize)
  93             self.hookWndProc()
  94         
  95         def onHookedSize(self,wParam,lParam):
  96             print "WM_SIZE [WPARAM:%i][LPARAM:%i]"%(wParam,lParam)
  97             return True
  98 
  99     app = wx.App(False)
 100     frame = MyFrame(None)
 101     frame.Show()
 102     app.MainLoop()

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2009-10-04 09:16:03, 3.1 KB) [[attachment:WndProcHookMixin.py]]
  • [get | view] (2009-10-04 09:16:03, 4.4 KB) [[attachment:WndProcHookMixinCtypes.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.