/* wxActiveX Library Licence, Version 3 ==================================== Copyright (C) 2003 Lindsay Mathieson [, ...] Everyone is permitted to copy and distribute verbatim copies of this licence document, but changing it is not allowed. wxActiveX LIBRARY LICENCE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public Licence as published by the Free Software Foundation; either version 2 of the Licence, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public Licence for more details. You should have received a copy of the GNU Library General Public Licence along with this software, usually in a file named COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. EXCEPTION NOTICE 1. As a special exception, the copyright holders of this library give permission for additional uses of the text contained in this release of the library as licenced under the wxActiveX Library Licence, applying either version 3 of the Licence, or (at your option) any later version of the Licence as published by the copyright holders of version 3 of the Licence document. 2. The exception is that you may use, copy, link, modify and distribute under the user's own terms, binary object code versions of works based on the Library. 3. If you copy code from files distributed under the terms of the GNU General Public Licence or the GNU Library General Public Licence into a copy of this library, as this licence permits, the exception does not apply to the code that you add in this way. To avoid misleading anyone as to the status of such modified files, you must delete this exception notice from such code and/or adjust the licensing conditions notice accordingly. 4. If you write modifications of your own for this library, it is your choice whether to permit this exception to apply to your modifications. If you do not wish that, you must delete the exception notice from such code and/or adjust the licensing conditions notice accordingly. */ /*! \file wxactivex.h \brief implements wxActiveX window class and OLE tools */ #ifndef WX_ACTIVE_X #define WX_ACTIVE_X #pragma warning( disable : 4101 4786) #pragma warning( disable : 4786) #include #include #include #include #include #include #include #include #include #include using namespace std; /// \brief wxActiveX Namespace for stuff I want to keep out of other tools way. namespace NS_wxActiveX { /// STL utilty class. /// specific to wxActiveX, for creating /// case insenstive maps etc struct less_wxStringI { bool operator()(const wxString& x, const wxString& y) const { return x.CmpNoCase(y) < 0; }; }; }; ////////////////////////////////////////// /// Template class for smart interface handling. /// - Automatically dereferences ole interfaces /// - Smart Copy Semantics /// - Can Create Interfaces /// - Can query for other interfaces template class wxAutoOleInterface { protected: I *m_interface; public: /// takes ownership of an existing interface /// Assumed to already have a AddRef() applied explicit wxAutoOleInterface(I *pInterface = NULL) : m_interface(pInterface) {} /// queries for an interface wxAutoOleInterface(REFIID riid, IUnknown *pUnk) : m_interface(NULL) { QueryInterface(riid, pUnk); }; /// queries for an interface wxAutoOleInterface(REFIID riid, IDispatch *pDispatch) : m_interface(NULL) { QueryInterface(riid, pDispatch); }; /// Creates an Interface wxAutoOleInterface(REFCLSID clsid, REFIID riid) : m_interface(NULL) { CreateInstance(clsid, riid); }; /// copy constructor wxAutoOleInterface(const wxAutoOleInterface& ti) : m_interface(NULL) { operator = (ti); } /// assignment operator wxAutoOleInterface& operator = (const wxAutoOleInterface& ti) { if (ti.m_interface) ti.m_interface->AddRef(); Free(); m_interface = ti.m_interface; return *this; } /// takes ownership of an existing interface /// Assumed to already have a AddRef() applied wxAutoOleInterface& operator = (I *&ti) { Free(); m_interface = ti; return *this; } /// invokes Free() ~wxAutoOleInterface() { Free(); }; /// Releases interface (i.e decrements refCount) inline void Free() { if (m_interface) m_interface->Release(); m_interface = NULL; }; /// queries for an interface HRESULT QueryInterface(REFIID riid, IUnknown *pUnk) { Free(); wxCHECK(pUnk != NULL, -1); return pUnk->QueryInterface(riid, (void **) &m_interface); }; /// Create a Interface instance HRESULT CreateInstance(REFCLSID clsid, REFIID riid) { Free(); return CoCreateInstance(clsid, NULL, CLSCTX_ALL, riid, (void **) &m_interface); }; /// returns the interface pointer inline operator I *() const {return m_interface;} /// returns the dereferenced interface pointer inline I* operator ->() {return m_interface;} /// returns a pointer to the interface pointer inline I** GetRef() {return &m_interface;} /// returns true if we have a valid interface pointer inline bool Ok() const {return m_interface != NULL;} }; /// \brief Converts a std HRESULT to its error code. /// Hardcoded, by no means a definitive list. wxString OLEHResultToString(HRESULT hr); /// \brief Returns the string description of a IID. /// Hardcoded, by no means a definitive list. wxString GetIIDName(REFIID riid); //#define __WXOLEDEBUG #ifdef __WXOLEDEBUG #define WXOLE_TRACE(str) {OutputDebugString(str);OutputDebugString("\r\n");} #define WXOLE_TRACEOUT(stuff)\ {\ wxString os;\ os << stuff << "\r\n";\ WXOLE_TRACE(os.mb_str());\ } #define WXOLE_WARN(__hr,msg)\ {\ if (__hr != S_OK)\ {\ wxString s = "*** ";\ s += msg;\ s += " : "+ OLEHResultToString(__hr);\ WXOLE_TRACE(s.c_str());\ }\ } #else #define WXOLE_TRACE(str) #define WXOLE_TRACEOUT(stuff) #define WXOLE_WARN(_proc,msg) {_proc;} #endif class wxOleInit { public: static IMalloc *GetIMalloc(); wxOleInit(); ~wxOleInit(); }; #define DECLARE_OLE_UNKNOWN(cls)\ private:\ class TAutoInitInt\ {\ public:\ LONG l;\ TAutoInitInt() : l(0) {}\ };\ TAutoInitInt refCount, lockCount;\ wxOleInit oleInit;\ static void _GetInterface(cls *self, REFIID iid, void **_interface, const char *&desc);\ public:\ LONG GetRefCount();\ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject);\ ULONG STDMETHODCALLTYPE AddRef();\ ULONG STDMETHODCALLTYPE Release();\ ULONG STDMETHODCALLTYPE AddLock();\ ULONG STDMETHODCALLTYPE ReleaseLock() #define DEFINE_OLE_TABLE(cls)\ LONG cls::GetRefCount() {return refCount.l;}\ HRESULT STDMETHODCALLTYPE cls::QueryInterface(REFIID iid, void ** ppvObject)\ {\ if (! ppvObject)\ {\ WXOLE_TRACE("*** NULL POINTER ***");\ return E_FAIL;\ };\ const char *desc = NULL;\ cls::_GetInterface(this, iid, ppvObject, desc);\ if (! *ppvObject)\ {\ WXOLE_TRACEOUT("<" << GetIIDName(iid).c_str() << "> Not Found");\ return E_NOINTERFACE;\ };\ WXOLE_TRACEOUT("QI : <" << desc <<">");\ ((IUnknown * )(*ppvObject))->AddRef();\ return S_OK;\ };\ ULONG STDMETHODCALLTYPE cls::AddRef()\ {\ WXOLE_TRACEOUT(# cls << "::Add ref(" << refCount.l << ")");\ InterlockedIncrement(&refCount.l);\ return refCount.l;\ };\ ULONG STDMETHODCALLTYPE cls::Release()\ {\ if (refCount.l > 0)\ {\ InterlockedDecrement(&refCount.l);\ WXOLE_TRACEOUT(# cls << "::Del ref(" << refCount.l << ")");\ if (refCount.l == 0)\ {\ delete this;\ return 0;\ };\ return refCount.l;\ }\ else\ return 0;\ }\ ULONG STDMETHODCALLTYPE cls::AddLock()\ {\ WXOLE_TRACEOUT(# cls << "::Add Lock(" << lockCount.l << ")");\ InterlockedIncrement(&lockCount.l);\ return lockCount.l;\ };\ ULONG STDMETHODCALLTYPE cls::ReleaseLock()\ {\ if (lockCount.l > 0)\ {\ InterlockedDecrement(&lockCount.l);\ WXOLE_TRACEOUT(# cls << "::Del Lock(" << lockCount.l << ")");\ return lockCount.l;\ }\ else\ return 0;\ }\ DEFINE_OLE_BASE(cls) #define DEFINE_OLE_BASE(cls)\ void cls::_GetInterface(cls *self, REFIID iid, void **_interface, const char *&desc)\ {\ *_interface = NULL;\ desc = NULL; #define OLE_INTERFACE(_iid, _type)\ if (IsEqualIID(iid, _iid))\ {\ WXOLE_TRACE("Found Interface <" # _type ">");\ *_interface = (IUnknown *) (_type *) self;\ desc = # _iid;\ return;\ } #define OLE_IINTERFACE(_face) OLE_INTERFACE(IID_##_face, _face) #define OLE_INTERFACE_CUSTOM(func)\ if (func(self, iid, _interface, desc))\ {\ return;\ } #define END_OLE_TABLE\ } /// Main class for embedding a ActiveX control. /// Use by itself or derive from it /// \note The utility program (wxie) can generate a list of events, methods & properties /// for a control. /// First display the control (File|Display), /// then get the type info (ActiveX|Get Type Info) - these are copied to the clipboard. /// Eventually this will be expanded to autogenerate /// wxWindows source files for a control with all methods etc encapsulated. /// \par Usage: /// construct using a ProgId or class id /// \code new wxActiveX(parent, CLSID_WebBrowser, id, pos, size, style, name)\endcode /// \code new wxActiveX(parent, "ShockwaveFlash.ShockwaveFlash", id, pos, size, style, name)\endcode /// \par Properties /// Properties can be set using \c SetProp() and set/retrieved using \c Prop() /// \code SetProp(name, wxVariant(x)) \endcode or /// \code wxString Prop("") = x\endcode /// \code wxString result = Prop("")\endcode /// \code flash_ctl.Prop("movie") = "file:///movies/test.swf";\endcode /// \code flash_ctl.Prop("Playing") = false;\endcode /// \code wxString current_movie = flash_ctl.Prop("movie");\endcode /// \par Methods /// Methods are invoked with \c CallMethod() /// \code wxVariant result = CallMethod("", args, nargs = -1)\endcode /// \code wxVariant args[] = {0L, "file:///e:/dev/wxie/bug-zap.swf"}; /// wxVariant result = X->CallMethod("LoadMovie", args);\endcode /// \par events /// respond to events with the /// \c EVT_ACTIVEX(controlId, eventName, handler) & /// \c EVT_ACTIVEX_DISPID(controlId, eventDispId, handler) macros /// \code /// BEGIN_EVENT_TABLE(wxIEFrame, wxFrame) /// EVT_ACTIVEX_DISPID(ID_MSHTML, DISPID_STATUSTEXTCHANGE, OnMSHTMLStatusTextChangeX) /// EVT_ACTIVEX(ID_MSHTML, "BeforeNavigate2", OnMSHTMLBeforeNavigate2X) /// EVT_ACTIVEX(ID_MSHTML, "TitleChange", OnMSHTMLTitleChangeX) /// EVT_ACTIVEX(ID_MSHTML, "NewWindow2", OnMSHTMLNewWindow2X) /// EVT_ACTIVEX(ID_MSHTML, "ProgressChange", OnMSHTMLProgressChangeX) /// END_EVENT_TABLE()\endcode class wxActiveX : public wxWindow { public: /// General parameter and return type infoformation for Events, Properties and Methods. /// refer to ELEMDESC, IDLDESC in MSDN class ParamX { public: USHORT flags; bool isPtr; bool isSafeArray; bool isOptional; VARTYPE vt; wxString name; ParamX() : isOptional(false), vt(VT_EMPTY) {} inline bool IsIn() const {return (flags & IDLFLAG_FIN) != 0;} inline bool IsOut() const {return (flags & IDLFLAG_FOUT) != 0;} inline bool IsRetVal() const {return (flags & IDLFLAG_FRETVAL) != 0;} }; typedef vector ParamXArray; /// Type & Parameter info for Events and Methods. /// refer to FUNCDESC in MSDN class FuncX { public: wxString name; MEMBERID memid; bool hasOut; ParamX retType; ParamXArray params; }; typedef vector FuncXArray; /// Type info for properties. class PropX { public: wxString name; MEMBERID memid; ParamX type; ParamX arg; bool putByRef; PropX() : putByRef (false) {} inline bool CanGet() const {return type.vt != VT_EMPTY;} inline bool CanSet() const {return arg.vt != VT_EMPTY;} }; typedef vector PropXArray; /// Create using clsid. wxActiveX(wxWindow * parent, REFCLSID clsid, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr); /// create using progid. wxActiveX(wxWindow * parent, const wxString& progId, wxWindowID id = -1, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr); virtual ~wxActiveX(); /// Number of events defined for this control. inline int GetEventCount() const {return m_events.size();} /// returns event description by index. /// throws exception for invalid index const FuncX& GetEventDesc(int idx) const; /// Number of properties defined for this control. inline int GetPropCount() const {return m_props.size();} /// returns property description by index. /// throws exception for invalid index const PropX& GetPropDesc(int idx) const; /// returns property description by name. /// throws exception for invalid name const PropX& GetPropDesc(const wxString& name) const; /// Number of methods defined for this control. inline int GetMethodCount() const {return m_methods.size();} /// returns method description by name. /// throws exception for invalid index const FuncX& GetMethodDesc(int idx) const; /// returns method description by name. /// throws exception for invalid name const FuncX& GetMethodDesc(const wxString& name) const; /// Set property VARIANTARG value by MEMBERID. void SetProp(MEMBERID name, VARIANTARG& value); /// Set property using wxVariant by name. void SetProp(const wxString &name, const wxVariant &value); class wxPropertySetter { public: wxActiveX *m_ctl; wxString m_propName; wxPropertySetter(wxActiveX *ctl, const wxString& propName) : m_ctl(ctl), m_propName(propName) {} inline const wxPropertySetter& operator = (wxVariant v) const { m_ctl->SetProp(m_propName, v); return *this; }; inline operator wxVariant() const {return m_ctl->GetPropAsWxVariant(m_propName);}; inline operator wxString() const {return m_ctl->GetPropAsString(m_propName);}; inline operator char() const {return m_ctl->GetPropAsChar(m_propName);}; inline operator long() const {return m_ctl->GetPropAsLong(m_propName);}; inline operator bool() const {return m_ctl->GetPropAsBool(m_propName);}; inline operator double() const {return m_ctl->GetPropAsDouble(m_propName);}; inline operator wxDateTime() const {return m_ctl->GetPropAsDateTime(m_propName);}; inline operator void *() const {return m_ctl->GetPropAsPointer(m_propName);}; }; /// \fn inline wxPropertySetter Prop(wxString name) {return wxPropertySetter(this, name);} /// \param name Property name to read/set /// \return wxPropertySetter, which has overloads for setting/getting the property /// \brief Generic Get/Set Property by name. /// Automatically handles most types /// \par Usage: /// - Prop("\") = \ /// - var = Prop("\") /// - e.g: /// - \code flash_ctl.Prop("movie") = "file:///movies/test.swf";\endcode /// - \code flash_ctl.Prop("Playing") = false;\endcode /// - \code wxString current_movie = flash_ctl.Prop("movie");\endcode /// \exception raises exception if \ is invalid /// \note Have to add a few more type conversions yet ... inline wxPropertySetter Prop(wxString name) {return wxPropertySetter(this, name);} VARIANT GetPropAsVariant(MEMBERID name); VARIANT GetPropAsVariant(const wxString& name); wxVariant GetPropAsWxVariant(const wxString& name); wxString GetPropAsString(const wxString& name); char GetPropAsChar(const wxString& name); long GetPropAsLong(const wxString& name); bool GetPropAsBool(const wxString& name); double GetPropAsDouble(const wxString& name); wxDateTime GetPropAsDateTime(const wxString& name); void *GetPropAsPointer(const wxString& name); // methods // VARIANTARG form is passed straight to Invoke, // so args in *REVERSE* order VARIANT CallMethod(MEMBERID name, VARIANTARG args[], int argc); VARIANT CallMethod(const wxString& name, VARIANTARG args[] = NULL, int argc = -1); // args are in *NORMAL* order // args can be a single wxVariant or an array /// \fn wxVariant CallMethod(wxString name, wxVariant args[], int nargs = -1); /// \param name name of method to call /// \param args array of wxVariant's, defaults to NULL (no args) /// \param nargs number of arguments passed via args. Defaults to actual number of args for the method /// \return wxVariant /// \brief Call a method of the ActiveX control. /// Automatically handles most types /// \par Usage: /// - result = CallMethod("\", args, nargs) /// - e.g. /// - \code /// wxVariant args[] = {0L, "file:///e:/dev/wxie/bug-zap.swf"}; /// wxVariant result = X->CallMethod("LoadMovie", args);\endcode /// \exception raises exception if \ is invalid /// \note Since wxVariant has built in type conversion, most the std types can be passed easily wxVariant CallMethod(const wxString& name, wxVariant args[], int nargs = -1); HRESULT ConnectAdvise(REFIID riid, IUnknown *eventSink); void OnSize(wxSizeEvent&); void OnPaint(wxPaintEvent& event); void OnMouse(wxMouseEvent& event); void OnSetFocus(wxFocusEvent&); void OnKillFocus(wxFocusEvent&); DECLARE_EVENT_TABLE(); protected: friend class FrameSite; friend class wxActiveXEvents; typedef map MemberIdMap; typedef map NameMap; typedef wxAutoOleInterface wxOleConnectionPoint; typedef pair wxOleConnection; typedef vector wxOleConnectionArray; wxAutoOleInterface m_Dispatch; wxAutoOleInterface m_clientSite; wxAutoOleInterface m_ActiveX; wxAutoOleInterface m_oleObject; wxAutoOleInterface m_oleInPlaceObject; wxAutoOleInterface m_oleInPlaceActiveObject; wxAutoOleInterface m_docView; wxAutoOleInterface m_viewObject; HWND m_oleObjectHWND; bool m_bAmbientUserMode; DWORD m_docAdviseCookie; wxOleConnectionArray m_connections; void CreateActiveX(REFCLSID clsid); void CreateActiveX(LPOLESTR progId); HRESULT AmbientPropertyChanged(DISPID dispid); void GetTypeInfo(); void GetTypeInfo(ITypeInfo *ti, bool defInterface, bool defEventSink); // events FuncXArray m_events; MemberIdMap m_eventMemberIds; // properties PropXArray m_props; NameMap m_propNames; // Methods FuncXArray m_methods; NameMap m_methodNames; long MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); DECLARE_CLASS(wxActiveX) }; // events class wxActiveXEvent : public wxCommandEvent { private: friend class wxActiveXEvents; wxVariant m_params; public: virtual wxEvent *Clone() const { return new wxActiveXEvent(*this); } wxString EventName(); int ParamCount() const; wxString ParamType(int idx); wxString ParamName(int idx); wxVariant& operator[] (int idx); wxVariant& operator[] (wxString name); private: DECLARE_CLASS(wxActiveXEvent) }; const wxEventType& RegisterActiveXEvent(const wxChar *eventName); const wxEventType& RegisterActiveXEvent(DISPID event); typedef void (wxEvtHandler::*wxActiveXEventFunction)(wxActiveXEvent&); /// \def EVT_ACTIVEX(id, eventName, fn) /// \brief Event handle for events by name #define EVT_ACTIVEX(id, eventName, fn) DECLARE_EVENT_TABLE_ENTRY(RegisterActiveXEvent(wxT(eventName)), id, -1, (wxObjectEventFunction) (wxEventFunction) (wxActiveXEventFunction) & fn, (wxObject *) NULL ), /// \def EVT_ACTIVEX_DISPID(id, eventDispId, fn) /// \brief Event handle for events by DISPID (dispath id) #define EVT_ACTIVEX_DISPID(id, eventDispId, fn) DECLARE_EVENT_TABLE_ENTRY(RegisterActiveXEvent(eventDispId), id, -1, (wxObjectEventFunction) (wxEventFunction) (wxActiveXEventFunction) & fn, (wxObject *) NULL ), //util bool wxDateTimeToVariant(wxDateTime dt, VARIANTARG& va); bool VariantToWxDateTime(VARIANTARG va, wxDateTime& dt); /// \relates wxActiveX /// \fn bool MSWVariantToVariant(VARIANTARG& va, wxVariant& vx); /// \param va VARAIANTARG to convert from /// \param vx Destination wxVariant /// \return success/failure (true/false) /// \brief Convert MSW VARIANTARG to wxVariant. /// Handles basic types, need to add: /// - VT_ARRAY | VT_* /// - better support for VT_UNKNOWN (currently treated as void *) /// - better support for VT_DISPATCH (currently treated as void *) bool MSWVariantToVariant(VARIANTARG& va, wxVariant& vx); /// \relates wxActiveX /// \fn bool VariantToMSWVariant(const wxVariant& vx, VARIANTARG& va); /// \param vx wxVariant to convert from /// \param va Destination VARIANTARG /// \return success/failure (true/false) /// \brief Convert wxVariant to MSW VARIANTARG. /// Handles basic types, need to add: /// - VT_ARRAY | VT_* /// - better support for VT_UNKNOWN (currently treated as void *) /// - better support for VT_DISPATCH (currently treated as void *) bool VariantToMSWVariant(const wxVariant& vx, VARIANTARG& va); #endif /* _IEHTMLWIN_H_ */