/*
                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 <wx/setup.h>
#include <wx/wx.h>
#include <wx/variant.h>
#include <wx/datetime.h>
#include <oleidl.h>
#include <exdisp.h>
#include <docobj.h>
#include <iostream>
#include <vector>
#include <map>
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 I> 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<I>& ti) : m_interface(NULL)
    {
        operator = (ti);
    }

    /// assignment operator
    wxAutoOleInterface<I>& operator = (const wxAutoOleInterface<I>& 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<I>& 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("<name>") = x\endcode
///         \code wxString result = Prop("<name>")\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("<name>", 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<ParamX>  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<FuncX>  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<PropX>  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("\<name\>") =  \<value\>
    ///     - var = Prop("\<name\>")
    ///     - 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 \<name\> 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("\<name\>", 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 \<name\> 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;

    unsigned long m_pdwRegister;
        
    typedef map<MEMBERID, int>                                  MemberIdMap;
    typedef map<wxString, int, NS_wxActiveX::less_wxStringI>    NameMap;
    
    typedef wxAutoOleInterface<IConnectionPoint>    wxOleConnectionPoint;
    typedef pair<wxOleConnectionPoint, DWORD>       wxOleConnection;
    typedef vector<wxOleConnection>                 wxOleConnectionArray;

    wxAutoOleInterface<IDispatch>           m_Dispatch;
    wxAutoOleInterface<IOleClientSite>      m_clientSite;
    wxAutoOleInterface<IUnknown>            m_ActiveX;
    wxAutoOleInterface<IOleObject>          m_oleObject;
    wxAutoOleInterface<IOleInPlaceObject>   m_oleInPlaceObject;
    wxAutoOleInterface<IOleInPlaceActiveObject>

                                            m_oleInPlaceActiveObject;
    wxAutoOleInterface<IOleDocumentView>    m_docView;
    wxAutoOleInterface<IViewObject>         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;

    virtual bool MSWTranslateMessage(WXMSG* pMsg);
    WXLRESULT 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_ */
