--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: activex.i
+// Purpose: ActiveX controls (such as Internet Explorer) in a wxWindow
+//
+// Author: Robin Dunn
+//
+// Created: 18-Mar-2004
+// RCS-ID: $Id$
+// Copyright: (c) 2004 by Total Control Software
+// Licence: wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+
+%module activex
+
+%{
+#include "wx/wxPython/wxPython.h"
+#include "wx/wxPython/pyclasses.h"
+#include "wx/wxPython/pyistream.h"
+
+#include "wxactivex.h"
+%}
+
+//---------------------------------------------------------------------------
+
+%import core.i
+%pythoncode { wx = core }
+
+MAKE_CONST_WXSTRING_NOSWIG(PanelNameStr);
+
+%include _activex_rename.i
+
+
+//---------------------------------------------------------------------------
+
+typedef unsigned short USHORT;
+typedef long DISPID;
+typedef long MEMBERID;
+typedef unsigned short VARTYPE;
+
+
+%{
+// Since SWIG doesn't support nested classes, we need to fool it a bit
+// and make them look like global classes. These defines make the C++ code
+// know what we are doing.
+#define wxParamX wxActiveX::ParamX
+#define wxFuncX wxActiveX::FuncX
+#define wxPropX wxActiveX::PropX
+#define wxParamXArray wxActiveX::ParamXArray
+#define wxFuncXArray wxActiveX::FuncXArray
+#define wxPropXArray wxActiveX::PropXArray
+%}
+
+
+%{
+// Some conversion helpers
+static wxVariant _PyObj2Variant(PyObject* value);
+static PyObject* _Variant2PyObj(wxVariant& value, bool useNone=False);
+static wxString _VARTYPEname(VARTYPE vt);
+
+// Check if an exception has been raised (blocking threads)
+inline bool wxPyErr_Occurred()
+{
+ bool rval;
+ wxPyBeginBlockThreads();
+ rval = PyErr_Occurred() != NULL;
+ wxPyEndBlockThreads();
+ return rval;
+}
+
+%}
+
+//---------------------------------------------------------------------------
+%newgroup
+
+DocStr(CLSID,
+"This class wraps the Windows CLSID structure and is used to
+specify the class of the ActiveX object that is to be created. A
+CLSID can be constructed from either a ProgID string, (such as
+'WordPad.Document.1') or a classID string, (such as
+'{CA8A9783-280D-11CF-A24D-444553540000}').");
+
+class CLSID {
+public:
+ %extend {
+ CLSID(const wxString& id)
+ {
+ int result;
+ CLSID* self = new CLSID;
+ memset(self, 0, sizeof(CLSID));
+
+ if (id[0] == _T('{')) {
+ // Looks like a classID string
+ result =
+ CLSIDFromString(
+ (LPOLESTR)(const wchar_t *)id.wc_str(wxConvUTF8),
+ self);
+ } else {
+ // Try a progID
+ result =
+ CLSIDFromProgID(
+ (LPOLESTR)(const wchar_t *)id.wc_str(wxConvUTF8),
+ self);
+ }
+ if (result != NOERROR) {
+ wxPyErr_SetString(PyExc_ValueError, "Not a recognized classID or progID");
+ delete self;
+ return NULL;
+ }
+ return self;
+ }
+
+ ~CLSID() { delete self; }
+
+ wxString GetCLSIDString()
+ {
+ LPOLESTR s;
+ wxString str;
+ if (StringFromCLSID(*self, &s) == S_OK) {
+ str = s;
+ CoTaskMemFree(s);
+ }
+ else {
+ str = _T("Error!"); // TODO: raise exception?
+ }
+ return str;
+ }
+ wxString GetProgIDString()
+ {
+ LPOLESTR s;
+ wxString str;
+ if (ProgIDFromCLSID(*self, &s) == S_OK) {
+ str = s;
+ CoTaskMemFree(s);
+ }
+ else {
+ str = _T("Error!"); // TODO: raise exception?
+ }
+ return str;
+ }
+ }
+ %pythoncode { def __str__(self): return self.GetCLSIDString() }
+};
+
+
+//---------------------------------------------------------------------------
+%newgroup
+
+%define MAKE_ARRAY_WRAPPER(basetype, arrayname)
+class arrayname
+{
+public:
+ %extend {
+ bool __nonzero__() { return self->size() > 0; }
+ int __len__() { return self->size(); }
+
+ const basetype& __getitem__(int idx) {
+ if ( idx >= 0 && idx < self->size() )
+ return (*self)[idx];
+ else {
+ static basetype BadVal;
+ wxPyErr_SetString(PyExc_IndexError, "Index out of range");
+ return BadVal;
+ }
+ }
+ // TODO __iter__??
+ }
+};
+%enddef
+
+//---------------------------------------------------------------------------
+
+%immutable;
+
+class wxParamX
+{
+public:
+ USHORT flags;
+ bool isPtr;
+ bool isSafeArray;
+ bool isOptional;
+ VARTYPE vt;
+ wxString name;
+
+ %feature("shadow") vt_type_get "vt_type = property(_activex.ParamX_vt_type_get)";
+ %extend { wxString vt_type_get() { return _VARTYPEname(self->vt); } }
+
+ %feature("shadow") IsIn "isIn = property(_activex.ParamX_IsIn)";
+ %feature("shadow") IsOut "isOut = property(_activex.ParamX_IsOut)";
+ %feature("shadow") IsRetVal "isRetVal = property(_activex.ParamX_IsRetVal)";
+ bool IsIn() const;
+ bool IsOut() const;
+ bool IsRetVal() const;
+
+};
+
+
+class wxFuncX
+{
+public:
+ wxString name;
+ MEMBERID memid;
+ bool hasOut;
+
+ wxParamX retType;
+ wxParamXArray params;
+};
+
+
+class wxPropX
+{
+public:
+ wxString name;
+ MEMBERID memid;
+ wxParamX type;
+ wxParamX arg;
+ bool putByRef;
+
+ %feature("shadow") CanGet "canGet = property(_activex.PropX_CanGet)";
+ %feature("shadow") CanSet "canSet = property(_activex.PropX_CanSet)";
+ bool CanGet() const;
+ bool CanSet() const;
+};
+%mutable;
+
+
+MAKE_ARRAY_WRAPPER(wxParamX, wxParamXArray);
+MAKE_ARRAY_WRAPPER(wxFuncX, wxFuncXArray);
+MAKE_ARRAY_WRAPPER(wxPropX, wxPropXArray);
+
+
+//---------------------------------------------------------------------------
+%newgroup
+
+%{
+// C++ version of a Python-aware wxActiveX
+class wxActiveXWindow : public wxActiveX
+{
+private:
+ CLSID m_CLSID;
+public:
+ wxActiveXWindow( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString& name = wxPyPanelNameStr)
+ : wxActiveX(parent, clsId, id, pos, size, style, name)
+ {
+ m_CLSID = clsId;
+ }
+
+ const CLSID& GetCLSID() const { return m_CLSID; }
+
+
+ // Renamed versions of some base class methods that delegate
+ // to the base where appropriate, and raise Python exceptions
+ // when needed.
+ int GetAXEventCount() const { return wxActiveX::GetEventCount(); }
+ int GetAXPropCount() const { return wxActiveX::GetPropCount(); }
+ int GetAXMethodCount() const { return wxActiveX::GetMethodCount(); }
+
+ const wxFuncX& GetAXEventDesc(int idx) const
+ {
+ static wxFuncX BadVal;
+ if (idx < 0 || idx >= GetAXEventCount()) {
+ wxPyErr_SetString(PyExc_IndexError, "Index out of range");
+ return BadVal;
+ }
+ return m_events[idx];
+ }
+ const wxFuncX& GetAXMethodDesc(int idx) const
+ {
+ static wxFuncX BadVal;
+ if (idx < 0 || idx >= GetAXMethodCount()) {
+ wxPyErr_SetString(PyExc_IndexError, "Index out of range");
+ return BadVal;
+ }
+ return m_methods[idx];
+ }
+ const wxPropX& GetAXPropDesc(int idx) const
+ {
+ static wxPropX BadVal;
+ if (idx < 0 || idx >= GetAXPropCount()) {
+ wxPyErr_SetString(PyExc_IndexError, "Index out of range");
+ return BadVal;
+ }
+ return m_props[idx];
+ }
+
+ const wxFuncX& GetAXMethodDesc(const wxString& name) const
+ {
+ NameMap::const_iterator it = m_methodNames.find(name);
+ if (it == m_methodNames.end()) {
+ wxString msg;
+ msg << "method <" << name << "> not found";
+ wxPyErr_SetString(PyExc_KeyError, msg.mb_str());
+ static wxFuncX BadVal;
+ return BadVal;
+ };
+ return GetAXMethodDesc(it->second);
+ }
+ const wxPropX& GetAXPropDesc(const wxString& name) const
+ {
+ NameMap::const_iterator it = m_propNames.find(name);
+ if (it == m_propNames.end()) {
+ wxString msg;
+ msg << "property <" << name << "> not found";
+ wxPyErr_SetString(PyExc_KeyError, msg.mb_str());
+ static wxPropX BadVal;
+ return BadVal;
+ };
+ return GetAXPropDesc(it->second);
+ }
+
+ // Accessors for the internal vectors of events, methods and
+ // proprties. Can be used as sequence like objects from
+ // Python.
+ const wxFuncXArray& GetAXEvents() { return m_events; }
+ const wxFuncXArray& GetAXMethods() { return m_methods; }
+ const wxPropXArray& GetAXProperties() { return m_props; }
+
+
+ // Set a property from a Python object
+ void SetAXProp(const wxString& name, PyObject* value)
+ {
+ const wxPropX& prop = GetAXPropDesc(name);
+ wxPyBeginBlockThreads();
+ if (! PyErr_Occurred() ) {
+ if (! prop.CanSet()) {
+ wxString msg;
+ msg << "property <" << name << "> is readonly";
+ PyErr_SetString(PyExc_TypeError, msg.mb_str());
+ goto done;
+ } else {
+ wxVariant wxV = _PyObj2Variant(value);
+ if (PyErr_Occurred())
+ goto done;
+ VARIANT v = {prop.arg.vt};
+ if (!VariantToMSWVariant(wxV, v) || PyErr_Occurred()) {
+ wxString msg;
+ msg << "Unable to convert value to expected type: ("
+ << _VARTYPEname(prop.arg.vt) << ") for property <"
+ << name << ">";
+ PyErr_SetString(PyExc_TypeError, msg.mb_str());
+ goto done;
+ }
+ PyThreadState* tstate = wxPyBeginAllowThreads();
+ SetProp(prop.memid, v);
+ VariantClear(&v);
+ wxPyEndAllowThreads(tstate);
+ }
+ }
+ done:
+ wxPyEndBlockThreads();
+ }
+
+
+ // Get a property and convert it to a Python object
+ PyObject* GetAXProp(const wxString& name)
+ {
+ PyObject* rval = NULL;
+ const wxPropX& prop = GetAXPropDesc(name);
+ wxPyBeginBlockThreads();
+ if (! PyErr_Occurred() ) {
+ if (! prop.CanGet()) {
+ wxString msg;
+ msg << "property <" << name << "> is writeonly";
+ PyErr_SetString(PyExc_TypeError, msg.mb_str());
+ goto done;
+ } else {
+ PyThreadState* tstate = wxPyBeginAllowThreads();
+ VARIANT v = GetPropAsVariant(prop.memid);
+ wxPyEndAllowThreads(tstate);
+ wxVariant wv;
+ if (!MSWVariantToVariant(v, wv) || PyErr_Occurred()) {
+ wxString msg;
+ msg << "Unable to convert value to expected type: ("
+ << _VARTYPEname(prop.arg.vt) << ") for property <"
+ << name << ">";
+ PyErr_SetString(PyExc_TypeError, msg.mb_str());
+ goto done;
+ }
+ rval = _Variant2PyObj(wv);
+ VariantClear(&v);
+ }
+ }
+ done:
+ wxPyEndBlockThreads();
+ return rval;
+ }
+
+
+ // If both IsIn and isOut are false, assume it is actually an
+ // input param
+ bool paramIsIn(const wxParamX& p)
+ {
+ return p.IsIn() || (!p.IsIn() && !p.IsOut());
+ }
+
+
+ // Call a method of the ActiveX object
+ PyObject* _CallAXMethod(const wxString& name, PyObject* args)
+ {
+ VARIANTARG *vargs = NULL;
+ int nargs = 0;
+ PyObject* rval = NULL;
+ const wxFuncX& func = GetAXMethodDesc(name);
+
+ wxPyBeginBlockThreads();
+ if (! PyErr_Occurred() ) {
+ nargs = func.params.size();
+ if (nargs > 0)
+ vargs = new VARIANTARG[nargs];
+
+ if (vargs) {
+ // init type of vargs, in reverse order
+ int i;
+ for (i = 0; i < nargs; i++)
+ vargs[nargs - i - 1].vt = func.params[i].vt;
+
+ // Map the args coming from Python to the input parameters in vargs
+ int pi = 0;
+ i = 0;
+ while ( i<nargs && pi<PyTuple_Size(args) ) {
+ // Move to the next input param.
+ if (! paramIsIn(func.params[i])) {
+ i += 1;
+ continue;
+ }
+ // convert the python object
+ PyObject* obj = PyTuple_GetItem(args, pi);
+ if (obj == Py_None) // special-case None?
+ vargs[nargs - i - 1].vt = VT_EMPTY;
+ else {
+ wxVariant wxV = _PyObj2Variant(obj);
+ if (PyErr_Occurred())
+ goto done;
+ if (!VariantToMSWVariant(wxV, vargs[nargs - i - 1]) || PyErr_Occurred()) {
+ wxString msg;
+ msg << "Unable to convert value to expected type: ("
+ << _VARTYPEname(vargs[nargs - i - 1].vt)
+ << ") for parameter " << i;
+ PyErr_SetString(PyExc_TypeError, msg.mb_str());
+ goto done;
+ }
+ }
+ i += 1;
+ pi += 1;
+ }
+ }
+
+ // call the method
+ PyThreadState* tstate = wxPyBeginAllowThreads();
+ VARIANT rv = CallMethod(func.memid, vargs, nargs);
+ wxPyEndAllowThreads(tstate);
+
+ // Convert the return value and any out-params, ignoring
+ // conversion errors for now
+ wxVariant wv;
+ MSWVariantToVariant(rv, wv);
+ rval = _Variant2PyObj(wv, True);
+ VariantClear(&rv);
+
+ if (func.hasOut) {
+ // make a list and put the rval in it if it is not None
+ PyObject* lst = PyList_New(0);
+ if (rval != Py_None)
+ PyList_Append(lst, rval);
+ else
+ Py_DECREF(rval);
+
+ // find the out params and convert them
+ for (int i = 0; i < nargs; i++) {
+ VARIANTARG& va = vargs[nargs - i - 1];
+ const wxParamX &px = func.params[i];
+ if (px.IsOut()) {
+ MSWVariantToVariant(va, wv);
+ PyObject* obj = _Variant2PyObj(wv, True);
+ PyList_Append(lst, obj);
+ }
+ }
+ rval = PyList_AsTuple(lst);
+ Py_DECREF(lst);
+ }
+ if (PyErr_Occurred())
+ PyErr_Clear();
+ }
+ done:
+ wxPyEndBlockThreads();
+ if (vargs) {
+ for (int i = 0; i < nargs; i++)
+ VariantClear(&vargs[i]);
+ delete [] vargs;
+ }
+ return rval;
+ }
+};
+%}
+
+
+
+// Now tell SWIG about this new class that is implemented above.
+
+DocStr(wxActiveXWindow,
+"ActiveXWindow derives from wxWindow and the constructor accepts a
+CLSID for the ActiveX Control that should be created. The
+ActiveXWindow class simply adds methods that allow you to query
+some of the TypeInfo exposed by the ActiveX object, and also to
+get/set properties or call methods by name. The Python
+implementation automatically handles converting parameters and
+return values to/from the types expected by the ActiveX code as
+specified by the TypeInfo.
+");
+
+
+class wxActiveXWindow : public wxWindow
+{
+public:
+ %pythonAppend wxActiveXWindow "self._setOORInfo(self)"
+
+ DocCtorStr(
+ wxActiveXWindow( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString& name = wxPyPanelNameStr),
+ "Creates an ActiveX control from the clsID given and makes it act
+as much like a regular wx.Window as possible.");
+
+ DocDeclStr(
+ const CLSID& , GetCLSID() const,
+ "Return the CLSID used to construct this ActiveX window");
+
+
+ DocDeclStr(
+ int , GetAXEventCount() const,
+ "Number of events defined for this control");
+
+ DocDeclStr(
+ const wxFuncX& , GetAXEventDesc(int idx) const,
+ "Returns event description by index");
+
+
+ DocDeclStr(
+ int , GetAXPropCount() const,
+ "Number of properties defined for this control");
+
+ %nokwargs GetAXPropDesc;
+ DocStr(GetPropDesc, "Returns property description by index or by name");
+ const wxPropX& GetAXPropDesc(int idx) const;
+ const wxPropX& GetAXPropDesc(const wxString& name) const;
+
+
+
+ DocDeclStr(
+ int , GetAXMethodCount() const,
+ "Number of methods defined for this control");
+
+ %nokwargs GetAXMethodDesc;
+ DocStr(GetMethodDesc, "Returns method description by index or name");
+ const wxFuncX& GetAXMethodDesc(int idx) const;
+ const wxFuncX& GetAXMethodDesc(const wxString& name) const;
+
+
+ DocDeclStr(
+ const wxFuncXArray& , GetAXEvents(),
+ "Returns a sequence of FuncX objects describing the events
+available for this ActiveX object.");
+
+ DocDeclStr(
+ const wxFuncXArray& , GetAXMethods(),
+ "Returns a sequence of FuncX objects describing the methods
+available for this ActiveX object.");
+
+ DocDeclStr(
+ const wxPropXArray& , GetAXProperties(),
+ "Returns a sequence of PropX objects describing the properties
+available for this ActiveX object.");
+
+
+
+ DocDeclStr(
+ void , SetAXProp(const wxString& name, PyObject* value),
+ "Set a property of the ActiveX object by name.");
+
+
+ DocDeclStr(
+ PyObject* , GetAXProp(const wxString& name),
+ "Get the value of an ActiveX property by name.");
+
+
+ %nokwargs _CallAXMethod;
+ DocDeclStr(
+ PyObject* , _CallAXMethod(const wxString& name, PyObject* args),
+ "The implementation for CallMethod. Calls an ActiveX method, by
+name passing the parameters given in args.");
+ %pythoncode {
+ def CallAXMethod(self, name, *args):
+ """
+ Front-end for _CallMethod. Simply passes all positional args
+ after the name as a single tuple to _CallMethod.
+ """
+ return self._CallAXMethod(name, args)
+ }
+};
+
+//---------------------------------------------------------------------------
+%newgroup
+
+DocDeclStr(
+ wxEventType , RegisterActiveXEvent(const wxString& eventName),
+ "Creates a standard wx event ID for the given eventName.");
+
+
+
+DocStr(wxActiveXEvent,
+"An instance of ActiveXEvent is sent to the handler for all bound
+ActiveX events. Any event parameters from the ActiveX cntrol are
+turned into attributes of the Python proxy for this event object.
+Additionally, there is a property called eventName that will
+return (suprizingly <wink>) the name of the ActiveX event.");
+
+class wxActiveXEvent : public wxCommandEvent
+{
+public:
+ %feature("shadow") EventName "eventName = property(_activex.ActiveXEvent_EventName)";
+ wxString EventName();
+
+ %extend {
+ DocStr(_preInit,
+"This is called by the EventThunker before calling the handler.
+We'll convert and load the ActiveX event parameters into
+attributes of the Python event object.");
+ void _preInit(PyObject* pyself) {
+ wxPyBeginBlockThreads();
+ PyObject* pList = PyList_New(0);
+ PyObject_SetAttrString(pyself, "paramList", pList);
+ Py_DECREF(pList);
+ for (int i=0; i<self->ParamCount(); i+=1) {
+ PyObject* name = PyString_FromString((char*)self->ParamName(i).mb_str());
+ PyObject* val = _Variant2PyObj((*self)[i], True);
+ PyObject_SetAttr(pyself, name, val);
+ PyList_Append(pList, name);
+ Py_DECREF(val);
+ Py_DECREF(name);
+ }
+ wxPyEndBlockThreads();
+ }
+ }
+};
+
+//---------------------------------------------------------------------------
+
+%{
+
+// Caller should already have the GIL!
+wxVariant _PyObj2Variant(PyObject* value)
+{
+ wxVariant rval;
+
+ if (value == Py_None)
+ return rval;
+
+ else if (PyBool_Check(value))
+ rval = (value == Py_True) ? true : false;
+
+ else if (PyInt_Check(value))
+ rval = PyInt_AS_LONG(value);
+
+ else if (PyFloat_Check(value))
+ rval = PyFloat_AS_DOUBLE(value);
+
+ else if (PyString_Check(value) || PyUnicode_Check(value))
+ rval = Py2wxString(value);
+
+ // TODO: PyList of strings --> wxArrayString
+ // wxDateTime
+ // list of objects
+
+ else {
+ PyErr_SetString(PyExc_TypeError, "Unsupported object type in _PyObj2Variant");
+ rval = (long)0;
+ }
+
+ return rval;
+}
+
+
+// Caller should already have the GIL!
+PyObject* _Variant2PyObj(wxVariant& value, bool useNone)
+{
+ PyObject* rval = NULL;
+
+ if (value.IsNull()) {
+ rval = Py_None;
+ Py_INCREF(rval);
+ }
+
+ // should "char" be treated as an int or as a string?
+ else if (value.IsType(_T("char")) || value.IsType(_T("long")))
+ rval = PyInt_FromLong(value);
+
+ else if (value.IsType(_T("double")))
+ rval = PyFloat_FromDouble(value);
+
+ else if (value.IsType(_T("bool")))
+ rval = PyBool_FromLong((bool)value);
+
+ else if (value.IsType(_T("string")))
+ rval = wx2PyString(value);
+
+ else {
+ if (useNone) {
+ rval = Py_None;
+ Py_INCREF(rval);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "Unsupported object type in _Variant2PyObj");
+ }
+ }
+ return rval;
+}
+
+
+wxString _VARTYPEname(VARTYPE vt)
+{
+ if (vt & VT_BYREF)
+ vt &= ~(VT_BYREF);
+
+ switch(vt) {
+ case VT_VARIANT:
+ return _T("VT_VARIANT");
+
+ // 1 byte chars
+ case VT_I1:
+ case VT_UI1:
+ // 2 byte shorts
+ case VT_I2:
+ case VT_UI2:
+ // 4 bytes longs
+ case VT_I4:
+ case VT_UI4:
+ case VT_INT:
+ case VT_UINT:
+ case VT_ERROR:
+ return _T("int");
+
+ // 4 byte floats
+ case VT_R4:
+ // 8 byte doubles
+ case VT_R8:
+ // decimals are converted from doubles too
+ case VT_DECIMAL:
+ return _T("double");
+
+ case VT_BOOL:
+ return _T("bool");
+
+ case VT_DATE:
+ return _T("wx.DateTime");
+
+ case VT_BSTR:
+ return _T("string");
+
+ case VT_UNKNOWN:
+ return _T("VT_UNKNOWN");
+
+ case VT_DISPATCH:
+ return _T("VT_DISPATCH");
+
+ case VT_EMPTY:
+ return _T("VT_EMPTY");
+
+ case VT_NULL:
+ return _T("VT_NULL");
+
+ case VT_VOID:
+ return _T("VT_VOID");
+
+ default:
+ wxString msg;
+ msg << _T("unsupported type ") << vt;
+ return msg;
+ }
+}
+
+%}
+
+//---------------------------------------------------------------------------
+//---------------------------------------------------------------------------
+%newgroup
+
+
+%{
+// A class derived from out wxActiveXWindow for the IE WebBrowser
+// control that will serve as a base class for a Python
+// implementation. This is done so we can "eat our own dog food"
+// and use a class at least mostly generated by genaxmodule, but
+// also get some of the extra stuff like loading a document from
+// a string or a stream, getting text contents, etc. that
+// Lindsay's version gives us.
+//
+
+#include <wx/mstream.h>
+#include <oleidl.h>
+#include <winerror.h>
+#include <exdispid.h>
+#include <exdisp.h>
+#include <olectl.h>
+#include <Mshtml.h>
+#include <sstream>
+
+#include "IEHtmlStream.h"
+
+class wxIEHtmlWindowBase : public wxActiveXWindow {
+private:
+ wxAutoOleInterface<IWebBrowser2> m_webBrowser;
+
+public:
+
+ wxIEHtmlWindowBase ( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString& name = wxPyPanelNameStr)
+ : wxActiveXWindow(parent, clsId, id, pos, size, style, name)
+ {
+ HRESULT hret;
+
+ // Get IWebBrowser2 Interface
+ hret = m_webBrowser.QueryInterface(IID_IWebBrowser2, m_ActiveX);
+ wxASSERT(SUCCEEDED(hret));
+ }
+
+
+ void SetCharset(const wxString& charset)
+ {
+ HRESULT hret;
+
+ // HTML Document ?
+ IDispatch *pDisp = NULL;
+ hret = m_webBrowser->get_Document(&pDisp);
+ wxAutoOleInterface<IDispatch> disp(pDisp);
+
+ if (disp.Ok())
+ {
+ wxAutoOleInterface<IHTMLDocument2> doc(IID_IHTMLDocument2, disp);
+ if (doc.Ok())
+ doc->put_charset((BSTR) (const wchar_t *) charset.wc_str(wxConvUTF8));
+ //doc->put_charset((BSTR) wxConvUTF8.cMB2WC(charset).data());
+ }
+ }
+
+
+ bool LoadString(const wxString& html)
+ {
+ char *data = NULL;
+ size_t len = html.length();
+ len *= sizeof(wxChar);
+ data = (char *) malloc(len);
+ memcpy(data, html.c_str(), len);
+ return LoadStream(new wxOwnedMemInputStream(data, len));
+ }
+
+
+ bool LoadStream(IStreamAdaptorBase *pstrm)
+ {
+ // need to prepend this as poxy MSHTML will not recognise a HTML comment
+ // as starting a html document and treats it as plain text
+ // Does nayone know how to force it to html mode ?
+ pstrm->prepend = "<html>";
+
+ // strip leading whitespace as it can confuse MSHTML
+ wxAutoOleInterface<IStream> strm(pstrm);
+
+ // Document Interface
+ IDispatch *pDisp = NULL;
+ HRESULT hret = m_webBrowser->get_Document(&pDisp);
+ if (! pDisp)
+ return false;
+ wxAutoOleInterface<IDispatch> disp(pDisp);
+
+
+ // get IPersistStreamInit
+ wxAutoOleInterface<IPersistStreamInit>
+ pPersistStreamInit(IID_IPersistStreamInit, disp);
+
+ if (pPersistStreamInit.Ok())
+ {
+ HRESULT hr = pPersistStreamInit->InitNew();
+ if (SUCCEEDED(hr))
+ hr = pPersistStreamInit->Load(strm);
+
+ return SUCCEEDED(hr);
+ }
+ else
+ return false;
+ }
+
+ bool LoadStream(wxInputStream *is)
+ {
+ // wrap reference around stream
+ IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is);
+ pstrm->AddRef();
+
+ return LoadStream(pstrm);
+ }
+
+
+ wxString GetStringSelection(bool asHTML)
+ {
+ wxAutoOleInterface<IHTMLTxtRange> tr(wxieGetSelRange(m_oleObject));
+ if (! tr)
+ return wxEmptyString;
+
+ BSTR text = NULL;
+ HRESULT hr = E_FAIL;
+
+ if (asHTML)
+ hr = tr->get_htmlText(&text);
+ else
+ hr = tr->get_text(&text);
+ if (hr != S_OK)
+ return wxEmptyString;
+
+ wxString s = text;
+ SysFreeString(text);
+
+ return s;
+ };
+
+ wxString GetText(bool asHTML)
+ {
+ if (! m_webBrowser.Ok())
+ return wxEmptyString;
+
+ // get document dispatch interface
+ IDispatch *iDisp = NULL;
+ HRESULT hr = m_webBrowser->get_Document(&iDisp);
+ if (hr != S_OK)
+ return wxEmptyString;
+
+ // Query for Document Interface
+ wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
+ iDisp->Release();
+
+ if (! hd.Ok())
+ return wxEmptyString;
+
+ // get body element
+ IHTMLElement *_body = NULL;
+ hd->get_body(&_body);
+ if (! _body)
+ return wxEmptyString;
+ wxAutoOleInterface<IHTMLElement> body(_body);
+
+ // get inner text
+ BSTR text = NULL;
+ hr = E_FAIL;
+
+ if (asHTML)
+ hr = body->get_innerHTML(&text);
+ else
+ hr = body->get_innerText(&text);
+ if (hr != S_OK)
+ return wxEmptyString;
+
+ wxString s = text;
+ SysFreeString(text);
+
+ return s;
+ }
+
+
+// void wxIEHtmlWin::SetEditMode(bool seton)
+// {
+// m_bAmbientUserMode = ! seton;
+// AmbientPropertyChanged(DISPID_AMBIENT_USERMODE);
+// };
+
+// bool wxIEHtmlWin::GetEditMode()
+// {
+// return ! m_bAmbientUserMode;
+// };
+};
+%}
+
+
+// we'll document it in the derived Python class
+%feature("noautodoc") wxIEHtmlWindowBase;
+%feature("noautodoc") wxIEHtmlWindowBase::SetCharset;
+%feature("noautodoc") wxIEHtmlWindowBase::LoadString;
+%feature("noautodoc") wxIEHtmlWindowBase::LoadStream;
+%feature("noautodoc") wxIEHtmlWindowBase::GetStringSelection;
+%feature("noautodoc") wxIEHtmlWindowBase::GetText;
+
+
+class wxIEHtmlWindowBase : public wxActiveXWindow {
+public:
+
+ wxIEHtmlWindowBase ( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString& name = wxPyPanelNameStr);
+
+ void SetCharset(const wxString& charset);
+ bool LoadString(const wxString& html);
+ bool LoadStream(wxInputStream *is);
+ wxString GetStringSelection(bool asHTML);
+ wxString GetText(bool asHTML);
+};
+
+
+
+
+
+
+
+
+
+
+
+#if 0
+enum wxIEHtmlRefreshLevel
+{
+ wxIEHTML_REFRESH_NORMAL = 0,
+ wxIEHTML_REFRESH_IFEXPIRED = 1,
+ wxIEHTML_REFRESH_CONTINUE = 2,
+ wxIEHTML_REFRESH_COMPLETELY = 3
+};
+
+DocStr(wxIEHtmlWin,
+"");
+class wxIEHtmlWin : public wxWindow
+{
+public:
+ %pythonAppend wxIEHtmlWin "self._setOORInfo(self)"
+
+ wxIEHtmlWin(wxWindow * parent, wxWindowID id = -1,
+ const wxPoint& pos = wxDefaultPosition,
+ const wxSize& size = wxDefaultSize,
+ long style = 0,
+ const wxString& name = wxPyPanelNameStr);
+
+ void LoadUrl(const wxString& url);
+ bool LoadString(wxString html);
+ bool LoadStream(wxInputStream *is);
+
+ %pythoncode { Navigate = LoadUrl }
+
+ void SetCharset(wxString charset);
+ void SetEditMode(bool seton);
+ bool GetEditMode();
+ wxString GetStringSelection(bool asHTML = false);
+ wxString GetText(bool asHTML = false);
+
+ bool GoBack();
+ bool GoForward();
+ bool GoHome();
+ bool GoSearch();
+ %name(RefreshPage)bool Refresh(wxIEHtmlRefreshLevel level);
+ bool Stop();
+};
+
+
+
+%pythoncode {
+wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2 = RegisterActiveXEvent('BeforeNavigate2')
+wxEVT_COMMAND_MSHTML_NEWWINDOW2 = RegisterActiveXEvent('NewWindow2')
+wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE = RegisterActiveXEvent('DocumentComplete')
+wxEVT_COMMAND_MSHTML_PROGRESSCHANGE = RegisterActiveXEvent('ProgressChange')
+wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE = RegisterActiveXEvent('StatusTextChange')
+wxEVT_COMMAND_MSHTML_TITLECHANGE = RegisterActiveXEvent('TitleChange')
+
+EVT_MSHTML_BEFORENAVIGATE2 = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2, 1)
+EVT_MSHTML_NEWWINDOW2 = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_NEWWINDOW2, 1)
+EVT_MSHTML_DOCUMENTCOMPLETE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE, 1)
+EVT_MSHTML_PROGRESSCHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE, 1)
+EVT_MSHTML_STATUSTEXTCHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE, 1)
+EVT_MSHTML_TITLECHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_TITLECHANGE, 1)
+}
+
+#endif
+
+//---------------------------------------------------------------------------
+// Include some extra Python code into the proxy module
+
+%pythoncode "_activex_ex.py"
+
+//---------------------------------------------------------------------------