1 /////////////////////////////////////////////////////////////////////////////
 
   3 // Purpose:     ActiveX controls (such as Internet Explorer) in a wxWindow
 
   7 // Created:     18-Mar-2004
 
   9 // Copyright:   (c) 2004 by Total Control Software
 
  10 // Licence:     wxWindows license
 
  11 /////////////////////////////////////////////////////////////////////////////
 
  14 %module(package="wx") activex
 
  17 #include "wx/wxPython/wxPython.h"
 
  18 #include "wx/wxPython/pyclasses.h"
 
  19 #include "wx/wxPython/pyistream.h"
 
  21 #include "wxactivex.h"
 
  24 //---------------------------------------------------------------------------
 
  27 %pythoncode { wx = _core }
 
  28 %pythoncode { __docfilter__ = wx.__DocFilter(globals()) }
 
  30 MAKE_CONST_WXSTRING_NOSWIG(PanelNameStr);
 
  32 %include _activex_rename.i
 
  35 //---------------------------------------------------------------------------
 
  37 typedef unsigned short  USHORT;
 
  39 typedef long            MEMBERID;
 
  40 typedef unsigned short  VARTYPE;
 
  44 // Since SWIG doesn't support nested classes, we need to fool it a bit
 
  45 // and make them look like global classes.  These defines make the C++ code
 
  46 // know what we are doing.
 
  47 #define wxParamX        wxActiveX::ParamX
 
  48 #define wxFuncX         wxActiveX::FuncX
 
  49 #define wxPropX         wxActiveX::PropX
 
  50 #define wxParamXArray   wxActiveX::ParamXArray
 
  51 #define wxFuncXArray    wxActiveX::FuncXArray
 
  52 #define wxPropXArray    wxActiveX::PropXArray
 
  57 // Some conversion helpers
 
  58 static wxVariant _PyObj2Variant(PyObject* value);
 
  59 static bool  _PyObj2Variant(PyObject* value, wxVariant& wv);
 
  60 static PyObject* _Variant2PyObj(wxVariant& value, bool useNone=false);
 
  61 static wxString  _VARTYPEname(VARTYPE vt);
 
  63 // Check if an exception has been raised  (blocking threads)
 
  64 inline bool wxPyErr_Occurred()
 
  67     bool blocked = wxPyBeginBlockThreads();
 
  68     rval = PyErr_Occurred() != NULL;
 
  69     wxPyEndBlockThreads(blocked);
 
  75 //---------------------------------------------------------------------------
 
  79 "This class wraps the Windows CLSID structure and is used to
 
  80 specify the class of the ActiveX object that is to be created.  A
 
  81 CLSID can be constructed from either a ProgID string, (such as
 
  82 'WordPad.Document.1') or a classID string, (such as
 
  83 '{CA8A9783-280D-11CF-A24D-444553540000}').", "");
 
  88         CLSID(const wxString& id)
 
  91             CLSID* self = new CLSID;
 
  92             memset(self, 0, sizeof(CLSID));
 
  94             if (id[0] == _T('{')) {
 
  95                 // Looks like a classID string
 
  98                         (LPOLESTR)(const wchar_t *)id.wc_str(wxConvUTF8),
 
 104                         (LPOLESTR)(const wchar_t *)id.wc_str(wxConvUTF8),
 
 107             if (result != NOERROR) {
 
 108                 wxPyErr_SetString(PyExc_ValueError, "Not a recognized classID or progID");
 
 115         ~CLSID() { delete self; }
 
 117         wxString GetCLSIDString()
 
 121             if (StringFromCLSID(*self, &s) == S_OK) {
 
 126                 str = _T("Error!");  // TODO: raise exception?
 
 130         wxString GetProgIDString()
 
 134             if (ProgIDFromCLSID(*self, &s) == S_OK) {
 
 139                 str = _T("Error!"); // TODO: raise exception?
 
 144     %pythoncode { def __str__(self):   return self.GetCLSIDString() }
 
 148 //---------------------------------------------------------------------------
 
 151 %define MAKE_ARRAY_WRAPPER(basetype, arrayname)
 
 156         bool __nonzero__()          { return self->size() > 0; }
 
 157         int  __len__()              { return self->size(); }
 
 159         const basetype& __getitem__(int idx) {
 
 160             if ( idx >= 0 && idx < self->size() )
 
 163                 static basetype BadVal;
 
 164                 wxPyErr_SetString(PyExc_IndexError, "Index out of range");
 
 173 //---------------------------------------------------------------------------
 
 187     %feature("shadow") vt_type_get "vt_type = property(_activex.ParamX_vt_type_get)";
 
 188     %extend { wxString vt_type_get() { return _VARTYPEname(self->vt); } }
 
 190     %feature("shadow") IsIn     "isIn = property(_activex.ParamX_IsIn)";
 
 191     %feature("shadow") IsOut    "isOut = property(_activex.ParamX_IsOut)";
 
 192     %feature("shadow") IsRetVal "isRetVal = property(_activex.ParamX_IsRetVal)";
 
 195     bool IsRetVal() const;
 
 208     wxParamXArray params;
 
 221     %feature("shadow") CanGet "canGet = property(_activex.PropX_CanGet)";
 
 222     %feature("shadow") CanSet "canSet = property(_activex.PropX_CanSet)";
 
 229 MAKE_ARRAY_WRAPPER(wxParamX, wxParamXArray);
 
 230 MAKE_ARRAY_WRAPPER(wxFuncX, wxFuncXArray);
 
 231 MAKE_ARRAY_WRAPPER(wxPropX, wxPropXArray);
 
 234 //---------------------------------------------------------------------------
 
 238 // C++ version of a Python-aware wxActiveX    
 
 239 class wxActiveXWindow : public wxActiveX
 
 244     wxActiveXWindow( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
 
 245                      const wxPoint& pos = wxDefaultPosition,
 
 246                      const wxSize& size = wxDefaultSize,
 
 248                      const wxString& name = wxPyPanelNameStr)
 
 249         : wxActiveX(parent, clsId, id, pos, size, style, name)
 
 254     const CLSID& GetCLSID() const { return m_CLSID; }
 
 257     // Renamed versions of some base class methods that delegate
 
 258     // to the base where appropriate, and raise Python exceptions
 
 260     int GetAXEventCount() const  { return wxActiveX::GetEventCount(); }
 
 261     int GetAXPropCount() const   { return wxActiveX::GetPropCount(); }
 
 262     int GetAXMethodCount() const { return wxActiveX::GetMethodCount(); }
 
 264     const wxFuncX& GetAXEventDesc(int idx) const
 
 266         static wxFuncX BadVal;
 
 267         if (idx < 0 || idx >= GetAXEventCount()) {
 
 268             wxPyErr_SetString(PyExc_IndexError, "Index out of range");
 
 271         return m_events[idx];
 
 273     const wxFuncX& GetAXMethodDesc(int idx) const
 
 275         static wxFuncX BadVal;
 
 276         if (idx < 0 || idx >= GetAXMethodCount()) {
 
 277             wxPyErr_SetString(PyExc_IndexError, "Index out of range");
 
 280         return m_methods[idx];
 
 282     const wxPropX& GetAXPropDesc(int idx) const
 
 284         static wxPropX BadVal;
 
 285         if (idx < 0 || idx >= GetAXPropCount()) {
 
 286             wxPyErr_SetString(PyExc_IndexError, "Index out of range");
 
 292     const wxFuncX& GetAXMethodDesc(const wxString& name) const
 
 294         NameMap::const_iterator it = m_methodNames.find(name);
 
 295         if (it == m_methodNames.end())     {
 
 297             msg << _T("method <") << name << _T("> not found");
 
 298             wxPyErr_SetString(PyExc_KeyError, msg.mb_str());
 
 299             static wxFuncX BadVal;
 
 302         return GetAXMethodDesc(it->second);
 
 304     const wxPropX& GetAXPropDesc(const wxString& name) const
 
 306         NameMap::const_iterator it = m_propNames.find(name);
 
 307         if (it == m_propNames.end())     {
 
 309             msg << _T("property <") << name << _T("> not found");
 
 310             wxPyErr_SetString(PyExc_KeyError, msg.mb_str());
 
 311             static wxPropX BadVal;
 
 314         return GetAXPropDesc(it->second);
 
 317     // Accessors for the internal vectors of events, methods and
 
 318     // proprties.  Can be used as sequence like objects from
 
 320     const wxFuncXArray& GetAXEvents()      { return m_events; }
 
 321     const wxFuncXArray& GetAXMethods()     { return m_methods; }
 
 322     const wxPropXArray& GetAXProperties()  { return m_props; }
 
 325     // Set a property from a Python object
 
 326     void SetAXProp(const wxString& name, PyObject* value)
 
 328         const wxPropX& prop = GetAXPropDesc(name);
 
 329         bool blocked = wxPyBeginBlockThreads();
 
 330         if (! PyErr_Occurred() ) {
 
 331             if (! prop.CanSet()) {
 
 333                 msg << _T("property <") << name << _T("> is readonly");
 
 334                 PyErr_SetString(PyExc_TypeError, msg.mb_str());
 
 337                 wxVariant wxV = _PyObj2Variant(value);
 
 338                 if (PyErr_Occurred())
 
 340                 VARIANT v = {prop.arg.vt};
 
 341                 if (!VariantToMSWVariant(wxV, v) || PyErr_Occurred()) {
 
 343                     msg << _T("Unable to convert value to expected type: (")
 
 344                         << _VARTYPEname(prop.arg.vt) << _T(") for property <")
 
 346                     PyErr_SetString(PyExc_TypeError, msg.mb_str());
 
 349                 PyThreadState* tstate = wxPyBeginAllowThreads();
 
 350                 SetProp(prop.memid, v);
 
 352                 wxPyEndAllowThreads(tstate);
 
 356         wxPyEndBlockThreads(blocked);
 
 360     // Get a property and convert it to a Python object
 
 361     PyObject* GetAXProp(const wxString& name)
 
 363         PyObject* rval = NULL;
 
 364         const wxPropX& prop = GetAXPropDesc(name);
 
 365         bool blocked = wxPyBeginBlockThreads();
 
 366         if (! PyErr_Occurred() ) {
 
 367             if (! prop.CanGet()) {
 
 369                 msg << _T("property <") << name << _T("> is writeonly");
 
 370                 PyErr_SetString(PyExc_TypeError, msg.mb_str());
 
 373                 PyThreadState* tstate = wxPyBeginAllowThreads();
 
 374                 VARIANT v = GetPropAsVariant(prop.memid);
 
 375                 wxPyEndAllowThreads(tstate);
 
 377                 if (!MSWVariantToVariant(v, wv) || PyErr_Occurred()) {
 
 379                     msg << _T("Unable to convert value to expected type: (")
 
 380                         << _VARTYPEname(prop.arg.vt) << _T(") for property <")
 
 382                     PyErr_SetString(PyExc_TypeError, msg.mb_str());
 
 385                 rval = _Variant2PyObj(wv);
 
 390         wxPyEndBlockThreads(blocked);
 
 395     // If both IsIn and isOut are false, assume it is actually an
 
 397     bool paramIsIn(const wxParamX& p)
 
 399         return p.IsIn() || (!p.IsIn() && !p.IsOut());
 
 403     // Call a method of the ActiveX object
 
 404     PyObject* _CallAXMethod(const wxString& name, PyObject* args)
 
 406         VARIANTARG *vargs = NULL;
 
 408         PyObject* rval = NULL;
 
 409         const wxFuncX& func = GetAXMethodDesc(name);
 
 411         bool blocked = wxPyBeginBlockThreads();
 
 412         if (! PyErr_Occurred() ) {
 
 413             nargs = func.params.size();
 
 415                 vargs = new VARIANTARG[nargs];
 
 418                 // init type of vargs, in reverse order
 
 420                 for (i = 0; i < nargs; i++)
 
 421                     vargs[nargs - i - 1].vt = func.params[i].vt;
 
 423                 // Map the args coming from Python to the input parameters in vargs
 
 426                 while ( i<nargs && pi<PyTuple_Size(args) ) {
 
 427                     // Move to the next input param. 
 
 428                     if (! paramIsIn(func.params[i])) {
 
 432                     // convert the python object
 
 433                     PyObject* obj = PyTuple_GetItem(args, pi);
 
 434                     if (obj == Py_None) // special-case None?
 
 435                         vargs[nargs - i - 1].vt = VT_EMPTY;
 
 437                         wxVariant wxV = _PyObj2Variant(obj);
 
 438                         if (PyErr_Occurred())
 
 440                         if (!VariantToMSWVariant(wxV, vargs[nargs - i - 1]) || PyErr_Occurred()) {
 
 442                             msg << _T("Unable to convert value to expected type: (")
 
 443                                 << _VARTYPEname(vargs[nargs - i - 1].vt)
 
 444                                 << _T(") for parameter ") << i;
 
 445                             PyErr_SetString(PyExc_TypeError, msg.mb_str());
 
 455             PyThreadState* tstate = wxPyBeginAllowThreads();
 
 456             VARIANT rv = CallMethod(func.memid, vargs, nargs);
 
 457             wxPyEndAllowThreads(tstate);
 
 459             // Convert the return value and any out-params, ignoring
 
 460             // conversion errors for now
 
 462             MSWVariantToVariant(rv, wv);
 
 463             rval = _Variant2PyObj(wv, true);
 
 467                 // make a list and put the rval in it if it is not None
 
 468                 PyObject* lst = PyList_New(0);
 
 470                     PyList_Append(lst, rval);
 
 474                 // find the out params and convert them
 
 475                 for (int i = 0; i < nargs; i++) {
 
 476                     VARIANTARG& va = vargs[nargs - i - 1];
 
 477                     const wxParamX &px = func.params[i];
 
 479                         MSWVariantToVariant(va, wv);
 
 480                         PyObject* obj = _Variant2PyObj(wv, true);
 
 481                         PyList_Append(lst, obj);
 
 484                 rval = PyList_AsTuple(lst);
 
 487             if (PyErr_Occurred())
 
 491         wxPyEndBlockThreads(blocked);
 
 493             for (int i = 0; i < nargs; i++)
 
 494                 VariantClear(&vargs[i]);
 
 504 // Now tell SWIG about this new class that is implemented above.
 
 506 DocStr(wxActiveXWindow,
 
 507 "ActiveXWindow derives from wxWindow and the constructor accepts a
 
 508 CLSID for the ActiveX Control that should be created.  The
 
 509 ActiveXWindow class simply adds methods that allow you to query
 
 510 some of the TypeInfo exposed by the ActiveX object, and also to
 
 511 get/set properties or call methods by name.  The Python
 
 512 implementation automatically handles converting parameters and
 
 513 return values to/from the types expected by the ActiveX code as
 
 514 specified by the TypeInfo.
 
 518 MustHaveApp(wxActiveXWindow);
 
 520 class wxActiveXWindow : public wxWindow
 
 523     %pythonAppend wxActiveXWindow      "self._setOORInfo(self)"
 
 526         wxActiveXWindow( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
 
 527                          const wxPoint& pos = wxDefaultPosition,
 
 528                          const wxSize& size = wxDefaultSize,
 
 530                          const wxString& name = wxPyPanelNameStr),
 
 531         "Creates an ActiveX control from the clsID given and makes it act
 
 532 as much like a regular wx.Window as possible.", "");
 
 535         const CLSID& , GetCLSID() const,
 
 536         "Return the CLSID used to construct this ActiveX window", "");
 
 540         int , GetAXEventCount() const,
 
 541         "Number of events defined for this control", "");
 
 544         const wxFuncX& , GetAXEventDesc(int idx) const,
 
 545         "Returns event description by index", "");
 
 549         int , GetAXPropCount() const,
 
 550         "Number of properties defined for this control", "");
 
 552     %nokwargs GetAXPropDesc;
 
 553     DocStr(GetPropDesc, "Returns property description by index or by name", "");
 
 554     const wxPropX& GetAXPropDesc(int idx) const;
 
 555     const wxPropX& GetAXPropDesc(const wxString& name) const;
 
 560         int , GetAXMethodCount() const,
 
 561         "Number of methods defined for this control", "");
 
 563     %nokwargs GetAXMethodDesc;
 
 564     DocStr(GetMethodDesc, "Returns method description by index or name", "");
 
 565     const wxFuncX& GetAXMethodDesc(int idx) const;
 
 566     const wxFuncX& GetAXMethodDesc(const wxString& name) const;
 
 570         const wxFuncXArray& , GetAXEvents(),
 
 571         "Returns a sequence of FuncX objects describing the events
 
 572 available for this ActiveX object.", "");
 
 575         const wxFuncXArray& , GetAXMethods(),
 
 576         "Returns a sequence of FuncX objects describing the methods
 
 577 available for this ActiveX object.", "");
 
 580         const wxPropXArray& , GetAXProperties(),
 
 581         "Returns a sequence of PropX objects describing the properties
 
 582 available for this ActiveX object.", "");
 
 587         void , SetAXProp(const wxString& name, PyObject* value),
 
 588         "Set a property of the ActiveX object by name.", "");
 
 592         PyObject* , GetAXProp(const wxString& name),
 
 593         "Get the value of an ActiveX property by name.", "");
 
 596     %nokwargs _CallAXMethod;
 
 598         PyObject* , _CallAXMethod(const wxString& name, PyObject* args),
 
 599         "The implementation for CallMethod.  Calls an ActiveX method, by
 
 600 name passing the parameters given in args.", "");
 
 602         def CallAXMethod(self, name, *args):
 
 604             Front-end for _CallMethod.  Simply passes all positional args
 
 605             after the name as a single tuple to _CallMethod.
 
 607             return self._CallAXMethod(name, args)
 
 611 //---------------------------------------------------------------------------
 
 615     wxEventType , RegisterActiveXEvent(const wxString& eventName),
 
 616     "Creates a standard wx event ID for the given eventName.", "");
 
 620 DocStr(wxActiveXEvent,
 
 621 "An instance of ActiveXEvent is sent to the handler for all bound
 
 622 ActiveX events.  Any event parameters from the ActiveX cntrol are
 
 623 turned into attributes of the Python proxy for this event object.
 
 624 Additionally, there is a property called eventName that will
 
 625 return (surprisingly <wink>) the name of the ActiveX event.", "");
 
 627 class wxActiveXEvent : public wxCommandEvent
 
 630     %feature("shadow") EventName "eventName = property(_activex.ActiveXEvent_EventName)";
 
 631     wxString EventName();
 
 635         // This is called by the EventThunker before calling the
 
 636         // handler. We'll convert and load the ActiveX event parameters into
 
 637         // attributes of the Python event object.
 
 638         void _preCallInit(PyObject* pyself) {
 
 639             bool blocked = wxPyBeginBlockThreads();
 
 640             PyObject* pList = PyList_New(0);
 
 641             PyObject_SetAttrString(pyself, "paramList", pList);
 
 643             for (int i=0; i<self->ParamCount(); i+=1) {
 
 644                 PyObject* name = PyString_FromString((char*)(const char*)self->ParamName(i).mb_str());
 
 645                 PyObject* val = _Variant2PyObj((*self)[i], true);
 
 646                 PyObject_SetAttr(pyself, name, val);
 
 647                 PyList_Append(pList, name);
 
 651             wxPyEndBlockThreads(blocked);
 
 654         // This one is called by the EventThunker after calling the
 
 655         // handler. It reloads any "out" parameters from the python attributes
 
 656         // back into the wxVariant they came from.        
 
 657         void _postCallCleanup(PyObject* pyself) {
 
 658             bool blocked = wxPyBeginBlockThreads();
 
 659             for (int i=0; i<self->ParamCount(); i+=1) {
 
 660                 PyObject* val = PyObject_GetAttrString(
 
 661                     pyself, (char*)(const char*)self->ParamName(i).mb_str());
 
 662                 _PyObj2Variant(val, (*self)[i]);
 
 665             wxPyEndBlockThreads(blocked);
 
 672 //---------------------------------------------------------------------------
 
 676 // Caller should already have the GIL!
 
 677 wxVariant _PyObj2Variant(PyObject* value)
 
 681     if (value == Py_None)
 
 684 #if PYTHON_API_VERSION >= 1012  // Python 2.3+
 
 685     else if (PyBool_Check(value))
 
 686         rval = (value == Py_True) ? true : false;
 
 689     else if (PyInt_Check(value))
 
 690         rval = PyInt_AS_LONG(value);
 
 692     else if (PyFloat_Check(value))
 
 693         rval = PyFloat_AS_DOUBLE(value);
 
 695     else if (PyString_Check(value) || PyUnicode_Check(value))
 
 696         rval = Py2wxString(value);
 
 698     // TODO:    PyList of strings --> wxArrayString
 
 704         PyErr_SetString(PyExc_TypeError, "Unsupported object type in _PyObj2Variant");
 
 711 // This one uses the type of the variant to try and force the conversion
 
 712 bool  _PyObj2Variant(PyObject* value, wxVariant& wv)
 
 714     wxString type = wv.GetType();
 
 716     if ( type == _T("long") || type == _T("bool") || type == _T("char") )
 
 717         wv = PyInt_AsLong(value);
 
 719     else if ( type == _T("string") )
 
 720         wv = Py2wxString(value);
 
 722     else if ( type == _T("double") )
 
 723         wv  = PyFloat_AsDouble(value);
 
 726         // it's some other type that we dont' handle yet.  Log it?
 
 732 // Caller should already have the GIL!
 
 733 PyObject* _Variant2PyObj(wxVariant& value, bool useNone)
 
 735     PyObject* rval = NULL;
 
 737     if (value.IsNull()) {
 
 742     // should "char" be treated as an int or as a string?
 
 743     else if (value.IsType(_T("char")) || value.IsType(_T("long")))
 
 744         rval = PyInt_FromLong(value);
 
 746     else if (value.IsType(_T("double")))
 
 747         rval = PyFloat_FromDouble(value);
 
 749     else if (value.IsType(_T("bool"))) {
 
 750         rval = (bool)value ? Py_True : Py_False;
 
 754     else if (value.IsType(_T("string")))
 
 755         rval = wx2PyString(value);
 
 763             PyErr_SetString(PyExc_TypeError, "Unsupported object type in _Variant2PyObj");
 
 770 wxString _VARTYPEname(VARTYPE vt)
 
 777         return _T("VT_VARIANT");
 
 797     // decimals are converted from doubles too
 
 805         return _T("wx.DateTime");
 
 811         return _T("VT_UNKNOWN");
 
 814         return _T("VT_DISPATCH");
 
 817         return _T("VT_EMPTY");
 
 820         return _T("VT_NULL");
 
 823         return _T("VT_VOID");
 
 827         msg << _T("unsupported type ") << vt;
 
 834 //---------------------------------------------------------------------------
 
 835 //---------------------------------------------------------------------------
 
 840 // A class derived from out wxActiveXWindow for the IE WebBrowser
 
 841 // control that will serve as a base class for a Python
 
 842 // implementation.  This is done so we can "eat our own dog food"
 
 843 // and use a class at least mostly generated by genaxmodule, but
 
 844 // also get some of the extra stuff like loading a document from
 
 845 // a string or a stream, getting text contents, etc. that
 
 846 // Lindsay's version gives us.
 
 849 #include <wx/mstream.h>
 
 851 #include <winerror.h>
 
 852 #include <exdispid.h>
 
 858 #include "IEHtmlStream.h"
 
 860 class wxIEHtmlWindowBase : public wxActiveXWindow {
 
 862     wxAutoOleInterface<IWebBrowser2>  m_webBrowser;
 
 866     wxIEHtmlWindowBase ( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
 
 867                          const wxPoint& pos = wxDefaultPosition,
 
 868                          const wxSize& size = wxDefaultSize,
 
 870                          const wxString& name = wxPyPanelNameStr)
 
 871         : wxActiveXWindow(parent, clsId, id, pos, size, style, name)
 
 875         // Get IWebBrowser2 Interface
 
 876         hret = m_webBrowser.QueryInterface(IID_IWebBrowser2, m_ActiveX);
 
 877         wxASSERT(SUCCEEDED(hret));
 
 880         m_webBrowser->put_MenuBar(VARIANT_FALSE);
 
 881         m_webBrowser->put_AddressBar(VARIANT_FALSE);
 
 882         m_webBrowser->put_StatusBar(VARIANT_FALSE);
 
 883         m_webBrowser->put_ToolBar(VARIANT_FALSE);
 
 885         m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
 
 886         m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
 
 888         m_webBrowser->Navigate( L"about:blank", NULL, NULL, NULL, NULL );
 
 892     void SetCharset(const wxString& charset)
 
 897         IDispatch *pDisp = NULL;
 
 898         hret = m_webBrowser->get_Document(&pDisp);
 
 899         wxAutoOleInterface<IDispatch> disp(pDisp);
 
 903             wxAutoOleInterface<IHTMLDocument2> doc(IID_IHTMLDocument2, disp);
 
 905                 doc->put_charset((BSTR) (const wchar_t *) charset.wc_str(wxConvUTF8));
 
 906             //doc->put_charset((BSTR) wxConvUTF8.cMB2WC(charset).data());
 
 911     bool LoadString(const wxString& html)
 
 914         size_t len = html.length();
 
 915         len *= sizeof(wxChar);
 
 916         data = (char *) malloc(len);
 
 917         memcpy(data, html.c_str(), len);
 
 918         return LoadStream(new wxOwnedMemInputStream(data, len));
 
 922     bool LoadStream(IStreamAdaptorBase *pstrm)
 
 924         // need to prepend this as poxy MSHTML will not recognise a HTML comment
 
 925         // as starting a html document and treats it as plain text
 
 926         // Does nayone know how to force it to html mode ?
 
 928         // TODO: What to do in this case???
 
 930         pstrm->prepend = _T("<html>");
 
 933         // strip leading whitespace as it can confuse MSHTML
 
 934         wxAutoOleInterface<IStream> strm(pstrm);
 
 936         // Document Interface
 
 937         IDispatch *pDisp = NULL;
 
 938         HRESULT hret = m_webBrowser->get_Document(&pDisp);
 
 941         wxAutoOleInterface<IDispatch> disp(pDisp);
 
 944         // get IPersistStreamInit
 
 945         wxAutoOleInterface<IPersistStreamInit>
 
 946             pPersistStreamInit(IID_IPersistStreamInit, disp);
 
 948         if (pPersistStreamInit.Ok())
 
 950             HRESULT hr = pPersistStreamInit->InitNew();
 
 952                 hr = pPersistStreamInit->Load(strm);
 
 954             return SUCCEEDED(hr);
 
 960     bool LoadStream(wxInputStream *is)
 
 962         // wrap reference around stream
 
 963         IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is);
 
 966         return LoadStream(pstrm);
 
 970     wxString GetStringSelection(bool asHTML)
 
 972         wxAutoOleInterface<IHTMLTxtRange> tr(wxieGetSelRange(m_oleObject));
 
 974             return wxEmptyString;
 
 980             hr = tr->get_htmlText(&text);
 
 982             hr = tr->get_text(&text);
 
 984             return wxEmptyString;
 
 992     wxString GetText(bool asHTML)
 
 994         if (! m_webBrowser.Ok())
 
 995             return wxEmptyString;
 
 997         // get document dispatch interface
 
 998         IDispatch *iDisp = NULL;
 
 999         HRESULT hr = m_webBrowser->get_Document(&iDisp);
 
1001             return wxEmptyString;
 
1003         // Query for Document Interface
 
1004         wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
 
1008             return wxEmptyString;
 
1011         IHTMLElement *_body = NULL;
 
1012         hd->get_body(&_body);
 
1014             return wxEmptyString;
 
1015         wxAutoOleInterface<IHTMLElement> body(_body);
 
1022             hr = body->get_innerHTML(&text);
 
1024             hr = body->get_innerText(&text);
 
1026             return wxEmptyString;
 
1029         SysFreeString(text);
 
1035 //     void wxIEHtmlWin::SetEditMode(bool seton)
 
1037 //         m_bAmbientUserMode = ! seton;
 
1038 //         AmbientPropertyChanged(DISPID_AMBIENT_USERMODE);
 
1041 //     bool wxIEHtmlWin::GetEditMode()
 
1043 //         return ! m_bAmbientUserMode;
 
1049 // we'll document it in the derived Python class
 
1050 %feature("noautodoc") wxIEHtmlWindowBase;
 
1051 %feature("noautodoc") wxIEHtmlWindowBase::SetCharset;
 
1052 %feature("noautodoc") wxIEHtmlWindowBase::LoadString;
 
1053 %feature("noautodoc") wxIEHtmlWindowBase::LoadStream;
 
1054 %feature("noautodoc") wxIEHtmlWindowBase::GetStringSelection;
 
1055 %feature("noautodoc") wxIEHtmlWindowBase::GetText;
 
1058 MustHaveApp(wxIEHtmlWindowBase);
 
1060 class wxIEHtmlWindowBase : public wxActiveXWindow {
 
1063     wxIEHtmlWindowBase ( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
 
1064                          const wxPoint& pos = wxDefaultPosition,
 
1065                          const wxSize& size = wxDefaultSize,
 
1067                          const wxString& name = wxPyPanelNameStr);
 
1069     void SetCharset(const wxString& charset);
 
1070     bool LoadString(const wxString& html);
 
1071     bool LoadStream(wxInputStream *is);
 
1072     wxString GetStringSelection(bool asHTML);
 
1073     wxString GetText(bool asHTML);
 
1087 enum wxIEHtmlRefreshLevel
 
1089     wxIEHTML_REFRESH_NORMAL = 0,
 
1090     wxIEHTML_REFRESH_IFEXPIRED = 1,
 
1091     wxIEHTML_REFRESH_CONTINUE = 2,
 
1092     wxIEHTML_REFRESH_COMPLETELY = 3
 
1097 class wxIEHtmlWin : public wxWindow 
 
1100     %pythonAppend wxIEHtmlWin      "self._setOORInfo(self)"
 
1102     wxIEHtmlWin(wxWindow * parent, wxWindowID id = -1,
 
1103                 const wxPoint& pos = wxDefaultPosition,
 
1104                 const wxSize& size = wxDefaultSize,
 
1106                 const wxString& name = wxPyPanelNameStr);
 
1108     void LoadUrl(const wxString& url);
 
1109     bool LoadString(wxString html);
 
1110     bool LoadStream(wxInputStream *is);
 
1112     %pythoncode { Navigate = LoadUrl }
 
1114     void SetCharset(wxString charset);
 
1115     void SetEditMode(bool seton);
 
1117     wxString GetStringSelection(bool asHTML = false);
 
1118     wxString GetText(bool asHTML = false);
 
1124     %name(RefreshPage)bool Refresh(wxIEHtmlRefreshLevel level);
 
1131 wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2  = RegisterActiveXEvent('BeforeNavigate2')
 
1132 wxEVT_COMMAND_MSHTML_NEWWINDOW2       = RegisterActiveXEvent('NewWindow2')
 
1133 wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE = RegisterActiveXEvent('DocumentComplete')
 
1134 wxEVT_COMMAND_MSHTML_PROGRESSCHANGE   = RegisterActiveXEvent('ProgressChange')
 
1135 wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE = RegisterActiveXEvent('StatusTextChange')
 
1136 wxEVT_COMMAND_MSHTML_TITLECHANGE      = RegisterActiveXEvent('TitleChange')
 
1138 EVT_MSHTML_BEFORENAVIGATE2      = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2, 1)
 
1139 EVT_MSHTML_NEWWINDOW2           = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_NEWWINDOW2, 1)
 
1140 EVT_MSHTML_DOCUMENTCOMPLETE     = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE, 1)
 
1141 EVT_MSHTML_PROGRESSCHANGE       = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE, 1)
 
1142 EVT_MSHTML_STATUSTEXTCHANGE     = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE, 1)
 
1143 EVT_MSHTML_TITLECHANGE          = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_TITLECHANGE, 1)
 
1148 //---------------------------------------------------------------------------
 
1149 // Include some extra Python code into the proxy module
 
1151 %pythoncode "_activex_ex.py"
 
1153 //---------------------------------------------------------------------------