1#----------------------------------------------------------------------
2# Name:        wx.lib.activexwrapper
3# Purpose:     a wxWindow derived class that can hold an ActiveX control
4#
5# Author:      Robin Dunn
6#
7# Copyright:   (c) 2000-2018 by Total Control Software
8# Licence:     wxWindows license
9#----------------------------------------------------------------------
10# 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net)
11#
12# o Updated for wx namespace
13# o Tested with updated demo
14#
15
16import  wx
17
18try:
19    import win32ui
20    import pywin.mfc.activex
21    import win32com.client
22except ImportError:
23    import sys
24    if hasattr(sys, "frozen"):
25        import os, win32api
26        dllpath = os.path.join(win32api.GetSystemDirectory(), 'MFC71.DLL')
27        if sys.version[:3] >= '2.4' and not os.path.exists(dllpath):
28            message = "%s not found" % dllpath
29        else:
30            raise       # original error message
31    else:
32        message = "ActiveXWrapper requires PythonWin. Please install the PyWin32 package."
33    raise ImportError(message)
34
35##from win32con import WS_TABSTOP, WS_VISIBLE
36WS_TABSTOP = 0x00010000
37WS_VISIBLE = 0x10000000
38
39#----------------------------------------------------------------------
40
41
42def MakeActiveXClass(CoClass, eventClass=None, eventObj=None):
43    """
44    Dynamically construct a new class that derives from wxWindow, the
45    ActiveX control and the appropriate COM classes.  This new class
46    can be used just like the wxWindow class, but will also respond
47    appropriately to the methods and properties of the COM object.  If
48    this class, a derived class or a mix-in class has method names
49    that match the COM object's event names, they will be called
50    automatically.
51
52    CoClass -- A COM control class from a module generated by
53            makepy.py from a COM TypeLibrary.  Can also accept a
54            CLSID.
55
56    eventClass -- If given, this class will be added to the set of
57            base classes that the new class is drived from.  It is
58            good for mix-in classes for catching events.
59
60    eventObj -- If given, this object will be searched for attributes
61            by the new class's __getattr__ method, (like a mix-in
62            object.)  This is useful if you want to catch COM
63            callbacks in an existing object, (such as the parent
64            window.)
65
66    """
67
68
69    if type(CoClass) == type(""):
70        # use the CLSID to get the real class
71        CoClass = win32com.client.CLSIDToClass(CoClass)
72
73    # determine the base classes
74    axEventClass = CoClass.default_source
75    baseClasses = [pywin.mfc.activex.Control, wx.Window, CoClass, axEventClass]
76    if eventClass:
77        baseClasses.append(eventClass)
78    baseClasses = tuple(baseClasses)
79
80    # define the class attributes
81    className = 'AXControl_'+CoClass.__name__
82    classDict = { '__init__'    : axw__init__,
83                  '__getattr__' : axw__getattr__,
84                  'axw_OnSize'  : axw_OnSize,
85                  'axw_OEB'     : axw_OEB,
86                  '_name'       : className,
87                  '_eventBase'  : axEventClass,
88                  '_eventObj'   : eventObj,
89                  'Cleanup'     : axw_Cleanup,
90                  }
91
92    # make a new class object
93    classObj = type(className, baseClasses, classDict)
94    return classObj
95
96
97
98
99# These functions will be used as methods in the new class
100def axw__init__(self, parent, ID=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0):
101
102    # init base classes
103    pywin.mfc.activex.Control.__init__(self)
104    wx.Window.__init__( self, parent, -1, pos, size, style|wx.NO_FULL_REPAINT_ON_RESIZE)
105    #self.this.own(False)  # this should be set in wx.Window.__init__ when it calls _setOORInfo, but...
106
107    win32ui.EnableControlContainer()
108    self._eventObj = self._eventObj  # move from class to instance
109
110    # create a pythonwin wrapper around this wxWindow
111    handle = self.GetHandle()
112    self._wnd = win32ui.CreateWindowFromHandle(handle)
113
114    # create the control
115    sz = self.GetSize()
116    self.CreateControl(self._name, WS_TABSTOP | WS_VISIBLE,
117                       (0, 0, sz.width, sz.height), self._wnd, ID)
118
119    # init the ax events part of the object
120    self._eventBase.__init__(self, self._dispobj_)
121
122    # hook some wx events
123    self.Bind(wx.EVT_SIZE, self.axw_OnSize)
124
125def axw__getattr__(self, attr):
126    try:
127        return pywin.mfc.activex.Control.__getattr__(self, attr)
128    except (AttributeError, win32ui.error):
129        try:
130            eo = self.__dict__['_eventObj']
131            return getattr(eo, attr)
132        except AttributeError:
133            raise AttributeError('Attribute not found: %s' % attr)
134
135
136def axw_OnSize(self, event):
137    sz = self.GetClientSize()                        # get wxWindow size
138    self.MoveWindow((0, 0, sz.width, sz.height), 1)  # move the AXControl
139
140
141def axw_OEB(self, event):
142    pass
143
144
145def axw_Cleanup(self):
146    #del self._wnd
147    self.close()
148    pass
149
150
151
152
153
154