mirror of
https://github.com/Sneed-Group/Poodletooth-iLand
synced 2024-12-29 06:32:40 -06:00
172 lines
6 KiB
Python
172 lines
6 KiB
Python
#----------------------------------------------------------------------
|
|
# Name: wx.lib.activex
|
|
# Purpose: The 3rd (and hopefully final) implementation of an
|
|
# ActiveX container for wxPython.
|
|
#
|
|
# Author: Robin Dunn
|
|
#
|
|
# Created: 5-June-2008
|
|
# Copyright: (c) 2008 by Total Control Software
|
|
# Licence: wxWindows license
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
"""
|
|
This module provides a wx.Window that hosts ActiveX Controls using
|
|
just the ctypes and comtypes packages. This provides a light-weight
|
|
COM implementation with full dynamic dispatch support.
|
|
|
|
The only requirements are ctypes (included with Python 2.5 and
|
|
available separately for earlier versions of Python) and the comtypes
|
|
package, which is available from
|
|
http://starship.python.net/crew/theller/comtypes/. Be sure to get at
|
|
least version 0.5, which at the time of this writing is only available
|
|
from SVN. You can fetch it with easy_install with a command like
|
|
this:
|
|
|
|
easy_install http://svn.python.org/projects/ctypes/trunk/comtypes
|
|
|
|
"""
|
|
|
|
import wx
|
|
|
|
import ctypes as ct
|
|
import ctypes.wintypes as wt
|
|
import comtypes
|
|
import comtypes.client as cc
|
|
import comtypes.hresult as hr
|
|
|
|
import sys, os
|
|
if not hasattr(sys, 'frozen'):
|
|
f = os.path.join(os.path.dirname(__file__), 'myole4ax.tlb')
|
|
cc.GetModule(f)
|
|
from comtypes.gen import myole4ax
|
|
|
|
|
|
kernel32 = ct.windll.kernel32
|
|
user32 = ct.windll.user32
|
|
atl = ct.windll.atl
|
|
|
|
WS_CHILD = 0x40000000
|
|
WS_VISIBLE = 0x10000000
|
|
WS_CLIPCHILDREN = 0x2000000
|
|
WS_CLIPSIBLINGS = 0x4000000
|
|
CW_USEDEFAULT = 0x80000000
|
|
WM_KEYDOWN = 256
|
|
WM_DESTROY = 2
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
class ActiveXCtrl(wx.PyAxBaseWindow):
|
|
"""
|
|
A wx.Window for hosting ActiveX controls. The COM interface of
|
|
the ActiveX control is accessible through the ctrl property of
|
|
this class, and this class is also set as the event sink for COM
|
|
events originating from the ActiveX control. In other words, to
|
|
catch the COM events you mearly have to derive from this class and
|
|
provide a method with the correct name. See the comtypes package
|
|
documentation for more details.
|
|
"""
|
|
|
|
def __init__(self, parent, axID, wxid=-1, pos=wx.DefaultPosition,
|
|
size=wx.DefaultSize, style=0, name="activeXCtrl"):
|
|
"""
|
|
All parameters are like those used in normal wx.Windows with
|
|
the addition of axID which is a string that is either a ProgID
|
|
or a CLSID used to identify the ActiveX control.
|
|
"""
|
|
pos = wx.Point(*pos) # in case the arg is a tuple
|
|
size = wx.Size(*size) # ditto
|
|
|
|
x = pos.x
|
|
y = pos.y
|
|
if x == -1: x = CW_USEDEFAULT
|
|
if y == -1: y = 20
|
|
w = size.width
|
|
h = size.height
|
|
if w == -1: w = 20
|
|
if h == -1: h = 20
|
|
|
|
# create the control
|
|
atl.AtlAxWinInit()
|
|
hInstance = kernel32.GetModuleHandleA(None)
|
|
hwnd = user32.CreateWindowExA(0, "AtlAxWin", axID,
|
|
WS_CHILD | WS_VISIBLE
|
|
| WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
|
x,y, w,h, parent.GetHandle(), None,
|
|
hInstance, 0)
|
|
assert hwnd != 0
|
|
|
|
# get the Interface for the Ax control
|
|
unknown = ct.POINTER(comtypes.IUnknown)()
|
|
res = atl.AtlAxGetControl(hwnd, ct.byref(unknown))
|
|
assert res == hr.S_OK
|
|
self._ax = cc.GetBestInterface(unknown)
|
|
|
|
# Fetch the interface for IOleInPlaceActiveObject. We'll use this
|
|
# later to call its TranslateAccelerator method so the AX Control can
|
|
# deal with things like tab traversal and such within itself.
|
|
self.ipao = self._ax.QueryInterface(myole4ax.IOleInPlaceActiveObject)
|
|
|
|
# Use this object as the event sink for the ActiveX events
|
|
self._evt_connections = []
|
|
self.AddEventSink(self)
|
|
|
|
# Turn the window handle into a wx.Window and set this object to be that window
|
|
win = wx.PyAxBaseWindow_FromHWND(parent, hwnd)
|
|
self.PostCreate(win)
|
|
|
|
# Set some wx.Window properties
|
|
if wxid == wx.ID_ANY:
|
|
wxid = wx.Window.NewControlId()
|
|
self.SetId(wxid)
|
|
self.SetName(name)
|
|
self.SetMinSize(size)
|
|
|
|
self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus)
|
|
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
|
|
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroyWindow)
|
|
|
|
def AddEventSink(self, sink, interface=None):
|
|
"""
|
|
Add a new target to search for method names that match the COM
|
|
Event names.
|
|
"""
|
|
self._evt_connections.append(cc.GetEvents(self._ax, sink, interface))
|
|
|
|
def GetCtrl(self):
|
|
"""Easy access to the COM interface for the ActiveX Control"""
|
|
return self._ax
|
|
# And an even easier property
|
|
ctrl = property(GetCtrl)
|
|
|
|
|
|
def MSWTranslateMessage(self, msg):
|
|
# Pass native messages to the IOleInPlaceActiveObject
|
|
# interface before wx processes them, so navigation keys and
|
|
# accelerators can be dealt with the way that the AXControl
|
|
# wants them to be done. MSWTranslateMessage is called before
|
|
# wxWidgets handles and eats the navigation keys itself.
|
|
res = self.ipao.TranslateAccelerator(msg)
|
|
if res == hr.S_OK:
|
|
return True
|
|
else:
|
|
return wx.PyAxBaseWindow.MSWTranslateMessage(self, msg)
|
|
|
|
|
|
# TBD: Are the focus handlers needed?
|
|
def OnSetFocus(self, evt):
|
|
self.ipao.OnFrameWindowActivate(True)
|
|
|
|
def OnKillFocus(self, evt):
|
|
self.ipao.OnFrameWindowActivate(False)
|
|
|
|
def OnDestroyWindow(self, evt):
|
|
# release our event sinks while the window still exists
|
|
self._evt_connections = None
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|