]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/contrib/activex/wxie/wxactivex.cpp
Lindsay Mathieson's newest wxActiveX class has been wrapped into a new
[wxWidgets.git] / wxPython / contrib / activex / wxie / wxactivex.cpp
diff --git a/wxPython/contrib/activex/wxie/wxactivex.cpp b/wxPython/contrib/activex/wxie/wxactivex.cpp
new file mode 100644 (file)
index 0000000..4cdb000
--- /dev/null
@@ -0,0 +1,2714 @@
+/*
+                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.
+*/
+
+#include "wxActiveX.h"
+#include <wx/strconv.h>
+#include <wx/event.h>
+#include <wx/string.h>
+#include <wx/datetime.h>
+#include <wx/log.h>
+#include <oleidl.h>
+#include <winerror.h>
+#include <idispids.h>
+#include <olectl.h>
+using namespace std;
+
+// Depending on compilation mode, the wx headers may have undef'd
+// this, but in this case we need it so the virtual method in
+// FrameSite will match what is in oleidl.h.
+#ifndef GetObject
+    #ifdef _UNICODE
+        #define GetObject GetObjectW
+    #else
+        #define GetObject GetObjectA
+    #endif
+#endif
+
+
+//////////////////////////////////////////////////////////////////////
+BEGIN_EVENT_TABLE(wxActiveX, wxWindow)
+    EVT_SIZE(wxActiveX::OnSize)
+    EVT_PAINT(wxActiveX::OnPaint)
+    EVT_MOUSE_EVENTS(wxActiveX::OnMouse)
+    EVT_SET_FOCUS(wxActiveX::OnSetFocus)
+    EVT_KILL_FOCUS(wxActiveX::OnKillFocus)
+END_EVENT_TABLE()
+
+class wxActiveX;
+
+class FrameSite : 
+    public IOleClientSite,
+    public IOleInPlaceSiteEx,
+    public IOleInPlaceFrame,
+    public IOleItemContainer,
+    public IDispatch,
+    public IOleCommandTarget,
+    public IOleDocumentSite,
+    public IAdviseSink,
+    public IOleControlSite
+{
+private:
+    DECLARE_OLE_UNKNOWN(FrameSite);
+
+public:
+    FrameSite(wxActiveX * win);
+    virtual ~FrameSite();
+
+    //IOleWindow
+    STDMETHODIMP GetWindow(HWND*);
+    STDMETHODIMP ContextSensitiveHelp(BOOL);
+
+    //IOleInPlaceUIWindow
+    STDMETHODIMP GetBorder(LPRECT);
+    STDMETHODIMP RequestBorderSpace(LPCBORDERWIDTHS);
+    STDMETHODIMP SetBorderSpace(LPCBORDERWIDTHS);
+    STDMETHODIMP SetActiveObject(IOleInPlaceActiveObject*, LPCOLESTR);
+    
+    //IOleInPlaceFrame
+    STDMETHODIMP InsertMenus(HMENU, LPOLEMENUGROUPWIDTHS);
+    STDMETHODIMP SetMenu(HMENU, HOLEMENU, HWND);
+    STDMETHODIMP RemoveMenus(HMENU);
+    STDMETHODIMP SetStatusText(LPCOLESTR);
+    STDMETHODIMP EnableModeless(BOOL);
+    STDMETHODIMP TranslateAccelerator(LPMSG, WORD);
+
+    //IOleInPlaceSite
+    STDMETHODIMP CanInPlaceActivate();
+    STDMETHODIMP OnInPlaceActivate();
+    STDMETHODIMP OnUIActivate();
+    STDMETHODIMP GetWindowContext(IOleInPlaceFrame**, IOleInPlaceUIWindow**, 
+        LPRECT, LPRECT, LPOLEINPLACEFRAMEINFO);
+    STDMETHODIMP Scroll(SIZE);
+    STDMETHODIMP OnUIDeactivate(BOOL);
+    STDMETHODIMP OnInPlaceDeactivate();
+    STDMETHODIMP DiscardUndoState();
+    STDMETHODIMP DeactivateAndUndo();
+    STDMETHODIMP OnPosRectChange(LPCRECT);
+
+    //IOleInPlaceSiteEx
+    STDMETHODIMP OnInPlaceActivateEx(BOOL*, DWORD);
+    STDMETHODIMP OnInPlaceDeactivateEx(BOOL);
+    STDMETHODIMP RequestUIActivate();
+
+    //IOleClientSite
+    STDMETHODIMP SaveObject();
+    STDMETHODIMP GetMoniker(DWORD, DWORD, IMoniker**);
+    STDMETHODIMP GetContainer(LPOLECONTAINER FAR*);
+    STDMETHODIMP ShowObject();
+    STDMETHODIMP OnShowWindow(BOOL);
+    STDMETHODIMP RequestNewObjectLayout();
+
+    //IOleControlSite
+    STDMETHODIMP OnControlInfoChanged();
+    STDMETHODIMP LockInPlaceActive(BOOL);
+    STDMETHODIMP GetExtendedControl(IDispatch**);
+    STDMETHODIMP TransformCoords(POINTL*, POINTF*, DWORD);
+    STDMETHODIMP TranslateAccelerator(LPMSG, DWORD);
+    STDMETHODIMP OnFocus(BOOL);
+    STDMETHODIMP ShowPropertyFrame();
+
+    //IOleCommandTarget
+    STDMETHODIMP QueryStatus(const GUID*, ULONG, OLECMD[], OLECMDTEXT*);
+    STDMETHODIMP Exec(const GUID*, DWORD, DWORD, VARIANTARG*, VARIANTARG*);
+
+    //IParseDisplayName
+    STDMETHODIMP ParseDisplayName(IBindCtx*, LPOLESTR, ULONG*, IMoniker**);
+
+    //IOleContainer
+    STDMETHODIMP EnumObjects(DWORD, IEnumUnknown**);
+    STDMETHODIMP LockContainer(BOOL);
+
+    //IOleItemContainer
+    STDMETHODIMP GetObject(LPOLESTR, DWORD, IBindCtx*, REFIID, void**);
+    STDMETHODIMP GetObjectStorage(LPOLESTR, IBindCtx*, REFIID, void**);
+    STDMETHODIMP IsRunning(LPOLESTR);
+    
+    //IDispatch
+    STDMETHODIMP GetIDsOfNames(REFIID, OLECHAR**, unsigned int, LCID, DISPID*);
+    STDMETHODIMP GetTypeInfo(unsigned int, LCID, ITypeInfo**);
+    STDMETHODIMP GetTypeInfoCount(unsigned int*);
+    STDMETHODIMP Invoke(DISPID, REFIID, LCID, WORD, DISPPARAMS*, VARIANT*, EXCEPINFO*, UINT*);
+
+    //IAdviseSink
+    void STDMETHODCALLTYPE OnDataChange(FORMATETC*, STGMEDIUM*);
+    void STDMETHODCALLTYPE OnViewChange(DWORD, LONG);
+    void STDMETHODCALLTYPE OnRename(IMoniker*);
+    void STDMETHODCALLTYPE OnSave();
+    void STDMETHODCALLTYPE OnClose();
+
+    // IOleDocumentSite
+    HRESULT STDMETHODCALLTYPE ActivateMe(IOleDocumentView __RPC_FAR *pViewToActivate);
+
+protected:
+
+    wxActiveX * m_window;
+
+    HDC m_hDCBuffer;
+    HWND m_hWndParent;
+
+    bool m_bSupportsWindowlessActivation;
+    bool m_bInPlaceLocked;
+    bool m_bInPlaceActive;
+    bool m_bUIActive;
+    bool m_bWindowless;
+    
+
+
+    LCID m_nAmbientLocale;
+    COLORREF m_clrAmbientForeColor;
+    COLORREF m_clrAmbientBackColor;
+    bool m_bAmbientShowHatching;
+    bool m_bAmbientShowGrabHandles;
+    bool m_bAmbientAppearance;
+};
+
+DEFINE_OLE_TABLE(FrameSite)
+    OLE_INTERFACE(IID_IUnknown, IOleClientSite)
+
+    OLE_IINTERFACE(IOleClientSite)
+
+    OLE_INTERFACE(IID_IOleWindow, IOleInPlaceSite)
+    OLE_IINTERFACE(IOleInPlaceSite)
+    OLE_IINTERFACE(IOleInPlaceSiteEx)
+
+    //OLE_IINTERFACE(IOleWindow)
+    OLE_IINTERFACE(IOleInPlaceUIWindow)
+    OLE_IINTERFACE(IOleInPlaceFrame)
+
+    OLE_IINTERFACE(IParseDisplayName)
+    OLE_IINTERFACE(IOleContainer)
+    OLE_IINTERFACE(IOleItemContainer)
+
+    OLE_IINTERFACE(IDispatch)
+
+    OLE_IINTERFACE(IOleCommandTarget)
+
+    OLE_IINTERFACE(IOleDocumentSite)
+
+    OLE_IINTERFACE(IAdviseSink)
+
+    OLE_IINTERFACE(IOleControlSite)
+
+END_OLE_TABLE;
+
+
+wxActiveX::wxActiveX(wxWindow * parent, REFCLSID clsid, wxWindowID id,
+        const wxPoint& pos,
+        const wxSize& size,
+        long style,
+        const wxString& name) :
+wxWindow(parent, id, pos, size, style, name)
+{
+    m_bAmbientUserMode = true;
+    m_docAdviseCookie = 0;
+    CreateActiveX(clsid);
+}
+
+wxActiveX::wxActiveX(wxWindow * parent, const wxString& progId, wxWindowID id,
+        const wxPoint& pos,
+        const wxSize& size,
+        long style,
+        const wxString& name) :
+    wxWindow(parent, id, pos, size, style, name)
+{
+    m_bAmbientUserMode = true;
+    m_docAdviseCookie = 0;
+    CreateActiveX((LPOLESTR) (const wchar_t *) progId.wc_str(wxConvUTF8));
+}
+
+wxActiveX::~wxActiveX()
+{
+    // disconnect connection points
+    wxOleConnectionArray::iterator it = m_connections.begin();
+    while (it != m_connections.end())
+    {
+        wxOleConnectionPoint& cp = it->first;
+        cp->Unadvise(it->second);
+
+        it++;
+    };
+    m_connections.clear();
+
+    if (m_oleInPlaceObject.Ok()) 
+    {
+        m_oleInPlaceObject->InPlaceDeactivate();
+        m_oleInPlaceObject->UIDeactivate();
+    }
+
+
+    if (m_oleObject.Ok()) 
+    {
+        if (m_docAdviseCookie != 0)
+            m_oleObject->Unadvise(m_docAdviseCookie);
+
+        m_oleObject->DoVerb(OLEIVERB_HIDE, NULL, m_clientSite, 0, (HWND) GetHWND(), NULL);
+        m_oleObject->Close(OLECLOSE_NOSAVE);
+        m_oleObject->SetClientSite(NULL);
+    }
+}
+
+void wxActiveX::CreateActiveX(REFCLSID clsid)
+{
+    SetTransparent();
+
+    HRESULT hret;
+
+    ////////////////////////////////////////////////////////
+    // FrameSite
+    FrameSite *frame = new FrameSite(this);
+    // oleClientSite
+    hret = m_clientSite.QueryInterface(IID_IOleClientSite, (IDispatch *) frame);
+    wxCHECK_RET(SUCCEEDED(hret), _T("m_clientSite.QueryInterface failed"));
+    // adviseSink
+    wxAutoOleInterface<IAdviseSink> adviseSink(IID_IAdviseSink, (IDispatch *) frame);
+    wxCHECK_RET(adviseSink.Ok(), _T("adviseSink not Ok"));
+
+
+    // // Create Object, get IUnknown interface
+    m_ActiveX.CreateInstance(clsid, IID_IUnknown);
+    wxCHECK_RET(m_ActiveX.Ok(), _T("m_ActiveX.CreateInstance failed"));
+
+    // Get Dispatch interface
+    hret = m_Dispatch.QueryInterface(IID_IDispatch, m_ActiveX); 
+    WXOLE_WARN(hret, "Unable to get dispatch interface");
+
+    // Type Info
+    GetTypeInfo();
+
+    // Get IOleObject interface
+    hret = m_oleObject.QueryInterface(IID_IOleObject, m_ActiveX); 
+    wxCHECK_RET(SUCCEEDED(hret), _("Unable to get IOleObject interface"));
+
+    // get IViewObject Interface
+    hret = m_viewObject.QueryInterface(IID_IViewObject, m_ActiveX); 
+    wxCHECK_RET(SUCCEEDED(hret), _T("Unable to get IViewObject Interface"));
+
+    // document advise
+    m_docAdviseCookie = 0;
+    hret = m_oleObject->Advise(adviseSink, &m_docAdviseCookie);
+    WXOLE_WARN(hret, "m_oleObject->Advise(adviseSink, &m_docAdviseCookie),\"Advise\")");
+    m_oleObject->SetHostNames(L"wxActiveXContainer", NULL);
+    OleSetContainedObject(m_oleObject, TRUE);
+    OleRun(m_oleObject);
+
+
+    // Get IOleInPlaceObject interface
+    hret = m_oleInPlaceObject.QueryInterface(IID_IOleInPlaceObject, m_ActiveX);
+    wxCHECK_RET(SUCCEEDED(hret), _T("Unable to get IOleInPlaceObject interface"));
+
+    // status
+    DWORD dwMiscStatus;
+    m_oleObject->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus);
+    wxCHECK_RET(SUCCEEDED(hret), _T("Unable to get oleObject status"));
+
+    // set client site first ?
+    if (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
+        m_oleObject->SetClientSite(m_clientSite);
+
+
+    // stream init
+    wxAutoOleInterface<IPersistStreamInit>
+        pPersistStreamInit(IID_IPersistStreamInit, m_oleObject);
+
+    if (pPersistStreamInit.Ok())
+    {
+        hret = pPersistStreamInit->InitNew();
+        WXOLE_WARN(hret, "CreateActiveX::pPersistStreamInit->InitNew()");
+    };
+
+    if (! (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
+        m_oleObject->SetClientSite(m_clientSite);
+
+
+    int w, h;
+    GetClientSize(&w, &h);
+    RECT posRect;
+    posRect.left = 0;
+    posRect.top = 0;
+    posRect.right = w;
+    posRect.bottom = h;
+
+    m_oleObjectHWND = 0;
+
+    if (m_oleInPlaceObject.Ok())
+    {
+        hret = m_oleInPlaceObject->GetWindow(&m_oleObjectHWND);
+        WXOLE_WARN(hret, "m_oleInPlaceObject->GetWindow(&m_oleObjectHWND)");
+        if (SUCCEEDED(hret))
+            ::SetActiveWindow(m_oleObjectHWND);
+    };
+
+
+    if (! (dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME))
+    {
+        if (w > 0 && h > 0 && m_oleInPlaceObject.Ok())
+            m_oleInPlaceObject->SetObjectRects(&posRect, &posRect);
+
+        hret = m_oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL, m_clientSite, 0, (HWND)GetHWND(), &posRect);
+        hret = m_oleObject->DoVerb(OLEIVERB_SHOW, 0, m_clientSite, 0, (HWND)GetHWND(), &posRect);
+    };
+
+    if (! m_oleObjectHWND && m_oleInPlaceObject.Ok())
+    {
+        hret = m_oleInPlaceObject->GetWindow(&m_oleObjectHWND);
+        WXOLE_WARN(hret, "m_oleInPlaceObject->GetWindow(&m_oleObjectHWND)");
+    };
+
+    if (m_oleObjectHWND)
+    {
+        ::SetActiveWindow(m_oleObjectHWND);
+        ::ShowWindow(m_oleObjectHWND, SW_SHOW);
+
+        // Update by GBR to resize older controls
+        wxSizeEvent szEvent;
+        szEvent.m_size = wxSize(w, h) ;
+        AddPendingEvent(szEvent);
+    };
+}
+
+void wxActiveX::CreateActiveX(LPOLESTR progId)
+{
+    CLSID clsid;
+    if (CLSIDFromProgID(progId, &clsid) != S_OK)
+        return;
+
+    CreateActiveX(clsid);
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Case Insensitive Map of Event names to eventTypes
+// created dynamically at run time in:
+//      EVT_ACTIVEX(eventName, id, fn)
+// we map the pointer to them so that:
+//      const wxEventType& RegisterActiveXEvent(wxString eventName);
+// can return a const reference, which is neccessary for event tables
+// probably should use a wxWindows hash table here, but I'm lazy ...
+typedef map<wxString, wxEventType *, NS_wxActiveX::less_wxStringI> ActiveXNamedEventMap;
+static ActiveXNamedEventMap sg_NamedEventMap;
+
+const wxEventType& RegisterActiveXEvent(const wxChar *eventName)
+{
+    wxString ev = eventName;
+    ActiveXNamedEventMap::iterator it = sg_NamedEventMap.find(ev);
+    if (it == sg_NamedEventMap.end())
+    {
+        wxEventType  *et = new wxEventType(wxNewEventType());
+        sg_NamedEventMap[ev] = et;
+
+        return *et;
+    };
+
+    return *(it->second);
+};
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Map of Event DISPID's to eventTypes
+// created dynamically at run time in:
+//      EVT_ACTIVEX(eventName, id, fn)
+// we map the pointer to them so that:
+//      const wxEventType& RegisterActiveXEvent(wxString eventName);
+// can return a const reference, which is neccessary for event tables
+
+typedef map<DISPID, wxEventType *> ActiveXDISPIDEventMap;
+static ActiveXDISPIDEventMap sg_dispIdEventMap;
+
+const wxEventType& RegisterActiveXEvent(DISPID event)
+{
+    ActiveXDISPIDEventMap::iterator it = sg_dispIdEventMap.find(event);
+    if (it == sg_dispIdEventMap.end())
+    {
+        wxEventType  *et = new wxEventType(wxNewEventType());
+        sg_dispIdEventMap[event] = et;
+
+        return *et;
+    };
+
+    return *(it->second);
+};
+
+// one off class for automatic freeing of activeX eventtypes
+class ActiveXEventMapFlusher
+{
+public:
+    ~ActiveXEventMapFlusher()
+    {
+        // Named events
+        ActiveXNamedEventMap::iterator it = sg_NamedEventMap.end();
+        while (it != sg_NamedEventMap.end())
+        {
+            delete it->second;
+            it++;
+        };
+        sg_NamedEventMap.clear();
+
+        // DISPID events
+        ActiveXDISPIDEventMap::iterator dit = sg_dispIdEventMap.end();
+        while (dit != sg_dispIdEventMap.end())
+        {
+            delete dit->second;
+            dit++;
+        };
+        sg_dispIdEventMap.clear();
+    };
+};
+
+static ActiveXEventMapFlusher s_dummyActiveXEventMapFlusher;
+
+
+//////////////////////////////////////////////////////
+VARTYPE wxTypeToVType(const wxVariant& v)
+{
+    wxString type = v.GetType();
+    if (type == wxT("bool"))
+        return VT_BOOL;
+    else if (type == wxT("char"))
+        return VT_I1;
+    else if (type == wxT("datetime"))
+        return VT_DATE;
+    else if (type == wxT("double"))
+        return VT_R8;
+    else if (type == wxT("list"))
+        return VT_ARRAY;
+    else if (type == wxT("long"))
+        return VT_I4;
+    else if (type == wxT("string"))
+        return VT_BSTR;
+    else if (type == wxT("stringlist"))
+        return VT_ARRAY;
+    else if (type == wxT("date"))
+        return VT_DATE;
+    else if (type == wxT("time"))
+        return VT_DATE;
+    else if (type == wxT("void*"))
+        return VT_VOID | VT_BYREF;
+    else
+        return VT_NULL;
+};
+
+bool wxDateTimeToDATE(wxDateTime dt, DATE& d)
+{
+    SYSTEMTIME st;
+    memset(&st, 0, sizeof(st));
+
+    st.wYear = dt.GetYear();
+    st.wMonth = dt.GetMonth() + 1;
+    st.wDay = dt.GetDay();
+    st.wHour = dt.GetHour();
+    st.wMinute = dt.GetMinute();
+    st.wSecond = dt.GetSecond();
+    st.wMilliseconds = dt.GetMillisecond();
+    return SystemTimeToVariantTime(&st, &d) != FALSE;
+};
+
+bool wxDateTimeToVariant(wxDateTime dt, VARIANTARG& va)
+{
+    return wxDateTimeToDATE(dt, va.date);
+};
+
+bool DATEToWxDateTime(DATE date, wxDateTime& dt)
+{
+    SYSTEMTIME st;
+    if (! VariantTimeToSystemTime(date, &st))
+        return false;
+
+    dt = wxDateTime(
+        st.wDay, 
+        wxDateTime::Month(int(wxDateTime::Jan) + st.wMonth - 1), 
+        st.wYear, 
+        st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
+
+    return true;
+};
+
+bool VariantToWxDateTime(VARIANTARG va, wxDateTime& dt)
+{
+    HRESULT hr = VariantChangeType(&va, &va, 0, VT_DATE);
+    if (! SUCCEEDED(hr))
+        return false;
+
+    return DATEToWxDateTime(va.date, dt);
+};
+
+bool MSWVariantToVariant(VARIANTARG& va, wxVariant& vx)
+{
+    bool byRef = false;
+    VARTYPE vt = va.vt;
+
+    if (vt & VT_ARRAY)
+        return false; // don't support arrays yet
+
+    if (vt & VT_BYREF)
+    {
+        byRef = true;
+        vt &= ~(VT_BYREF);
+    };
+
+
+    switch(vt)
+    {
+    case VT_VARIANT:
+        if (byRef)
+            return MSWVariantToVariant(*va.pvarVal, vx);
+        else
+        {
+            VARIANT tmp = va;
+            VariantChangeType(&tmp, &tmp, 0, wxTypeToVType(vx));
+            bool rc = MSWVariantToVariant(tmp, vx);
+            VariantClear(&tmp);
+            return rc;
+        };
+
+    // 1 byte chars
+    case VT_I1:
+    case VT_UI1:
+        if (byRef)
+            vx = (char) *va.pbVal;
+        else
+            vx = (char) va.bVal;
+        return true;
+
+    // 2 byte shorts
+    case VT_I2:
+    case VT_UI2:
+        if (byRef)
+            vx = (long) *va.puiVal;
+        else
+            vx = (long) va.uiVal;
+        return true;
+
+    // 4 bytes longs
+    case VT_I4:
+    case VT_UI4:
+    case VT_INT:
+    case VT_UINT:
+    case VT_ERROR:
+        if (byRef)
+            vx = (long) *va.pulVal;
+        else
+            vx = (long) va.ulVal;
+        return true;
+    
+
+    // 4 byte floats
+    case VT_R4:
+        if (byRef)
+            vx = *va.pfltVal;
+        else
+            vx = va.fltVal;
+        return true;
+
+    // 8 byte doubles
+    case VT_R8:
+        if (byRef)
+            vx = *va.pdblVal;
+        else
+            vx = va.dblVal;
+        return true;
+
+    case VT_BOOL:
+        if (byRef)
+            vx = (*va.pboolVal ? true : false);
+        else
+            vx = (va.boolVal ? true : false);
+        return true;
+
+    case VT_CY:
+        vx.MakeNull();
+        return false; // what the hell is a CY ?
+
+    case VT_DECIMAL:
+        {
+            double d = 0;
+            HRESULT hr;
+            if (byRef)
+                hr = VarR8FromDec(va.pdecVal, &d);
+            else
+                hr = VarR8FromDec(&va.decVal, &d);
+
+            vx = d;
+            return SUCCEEDED(hr);
+        };
+
+    case VT_DATE:
+        {
+            wxDateTime dt;
+            bool rc =  false;
+            if (byRef)
+                rc = DATEToWxDateTime(*va.pdate, dt);
+            else
+                rc = VariantToWxDateTime(va, dt);
+            vx = dt;
+            return rc;
+        };
+
+    case VT_BSTR:
+        if (byRef)
+            vx = wxString(*va.pbstrVal);
+        else
+            vx = wxString(va.bstrVal);
+        return true;
+
+    case VT_UNKNOWN: // should do a custom wxVariantData for this
+        if (byRef)
+            vx = (void *) *va.ppunkVal;
+        else
+            vx = (void *) va.punkVal;
+        return false;
+
+    case VT_DISPATCH: // should do a custom wxVariantData for this
+        if (byRef)
+            vx = (void *) *va.ppdispVal;
+        else
+            vx = (void *) va.pdispVal;
+        return false;
+
+    default:
+        vx.MakeNull();
+        return false;
+    };
+};
+
+bool VariantToMSWVariant(const wxVariant& vx, VARIANTARG& va)
+{
+    bool byRef = false;
+    VARTYPE vt = va.vt;
+
+    if (vt & VT_ARRAY)
+        return false; // don't support arrays yet
+
+    if (vt & VT_BYREF)
+    {
+        byRef = true;
+        vt &= ~(VT_BYREF);
+    };
+
+    switch(vt)
+    {
+    case VT_VARIANT:
+        if (byRef)
+            return VariantToMSWVariant(vx, *va.pvarVal);
+        else
+        {
+            va.vt = wxTypeToVType(vx);
+            return VariantToMSWVariant(vx, va);
+        };
+
+    // 1 byte chars
+    case VT_I1:
+    case VT_UI1:
+        if (byRef)
+            *va.pbVal = (char) vx;
+        else
+            va.bVal = (char) vx;
+        return true;
+
+    // 2 byte shorts
+    case VT_I2:
+    case VT_UI2:
+        if (byRef)
+            *va.puiVal = (long) vx;
+        else
+            va.uiVal = (long) vx;
+        return true;
+
+    // 4 bytes longs
+    case VT_I4:
+    case VT_UI4:
+    case VT_INT:
+    case VT_UINT:
+    case VT_ERROR:
+        if (byRef)
+            *va.pulVal = (long) vx;
+        else
+            va.ulVal = (long) vx;
+        return true;
+    
+
+    // 4 byte floats
+    case VT_R4:
+        if (byRef)
+            *va.pfltVal = (double) vx;
+        else
+            va.fltVal = (double) vx;
+        return true;
+
+    // 8 byte doubles
+    case VT_R8:
+        if (byRef)
+            *va.pdblVal = (double) vx;
+        else
+            va.dblVal = (double) vx;
+        return true;
+
+    case VT_BOOL:
+        if (byRef)
+            *va.pboolVal = ((bool) vx) ? TRUE : FALSE;
+        else
+            va.boolVal = ((bool) vx) ? TRUE : FALSE;
+        return true;
+
+    case VT_CY:
+        return false; // what the hell is a CY ?
+
+    case VT_DECIMAL:
+        if (byRef)
+            return SUCCEEDED(VarDecFromR8(vx, va.pdecVal));
+        else
+            return SUCCEEDED(VarDecFromR8(vx, &va.decVal));
+
+    case VT_DATE:
+        if (byRef)
+            return wxDateTimeToDATE(vx, *va.pdate);
+        else
+            return wxDateTimeToVariant(vx,va);
+
+    case VT_BSTR:
+        if (byRef)
+            *va.pbstrVal = SysAllocString(vx.GetString().wc_str(wxConvUTF8));
+        else
+            va.bstrVal = SysAllocString(vx.GetString().wc_str(wxConvUTF8));
+        return true;
+
+    case VT_UNKNOWN: // should do a custom wxVariantData for this
+        if (byRef)
+            *va.ppunkVal = (IUnknown *) (void *) vx;
+        else
+            va.punkVal = (IUnknown *) (void *) vx;
+        return false;
+
+    case VT_DISPATCH: // should do a custom wxVariantData for this
+        if (byRef)
+            *va.ppdispVal = (IDispatch *) (void *) vx;
+        else
+            va.pdispVal = (IDispatch *) (void *) vx;
+        return false;
+
+    default:
+        return false;
+    };
+};
+
+IMPLEMENT_CLASS(wxActiveXEvent, wxCommandEvent)
+
+class wxActiveXEvents : public IDispatch
+{
+private:
+    DECLARE_OLE_UNKNOWN(wxActiveXEvents);
+
+
+    wxActiveX   *m_activeX;
+    IID         m_customId;
+    bool        m_haveCustomId;
+
+    friend bool wxActiveXEventsInterface(wxActiveXEvents *self, REFIID iid, void **_interface, const char *&desc);
+
+public:
+    wxActiveXEvents(wxActiveX *ax) : m_activeX(ax), m_haveCustomId(false) {}
+    wxActiveXEvents(wxActiveX *ax, REFIID iid) : m_activeX(ax), m_haveCustomId(true), m_customId(iid) {}
+    virtual ~wxActiveXEvents() 
+    {
+    }
+
+    //IDispatch
+    STDMETHODIMP GetIDsOfNames(REFIID r, OLECHAR** o, unsigned int i, LCID l, DISPID* d)
+    { 
+        return E_NOTIMPL;
+    };
+
+    STDMETHODIMP GetTypeInfo(unsigned int i, LCID l, ITypeInfo** t)
+    { 
+        return E_NOTIMPL;
+    };
+
+    STDMETHODIMP GetTypeInfoCount(unsigned int* i)
+    { 
+        return E_NOTIMPL;
+    };
+
+
+    void DispatchEvent(wxActiveX::FuncX &func, const wxEventType& eventType, DISPPARAMS * pDispParams)
+    {
+        wxActiveXEvent  event;
+        event.SetId(m_activeX->GetId());
+        event.SetEventType(eventType);
+        event.m_params.NullList();
+        event.m_params.SetName(func.name);
+
+        // arguments
+        if (pDispParams)
+        {
+            // cdecl call
+            // sometimes the pDispParams does not match the param info for a activex control
+            int nArg = min(func.params.size(), pDispParams->cArgs);
+            for (int i = nArg - 1; i >= 0; i--)
+            {
+                VARIANTARG& va = pDispParams->rgvarg[i];
+                wxActiveX::ParamX &px = func.params[nArg - i - 1];
+                wxVariant vx;
+
+                vx.SetName(px.name);
+                MSWVariantToVariant(va, vx);
+                event.m_params.Append(vx);
+            };
+        };
+
+        if (func.hasOut)
+        {
+            int nArg = min(func.params.size(), pDispParams->cArgs);
+            m_activeX->GetParent()->ProcessEvent(event);
+            for (int i = 0; i < nArg; i++)
+            {
+                VARIANTARG& va = pDispParams->rgvarg[i];
+                wxActiveX::ParamX &px = func.params[nArg - i - 1];
+
+                if (px.IsOut())
+                {
+                    wxVariant& vx = event.m_params[nArg - i - 1];
+                    
+                    VariantToMSWVariant(vx, va);
+                };
+            };
+        }
+        else
+            m_activeX->GetParent()->AddPendingEvent(event);
+
+    };
+
+    STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
+                          WORD wFlags, DISPPARAMS * pDispParams,
+                          VARIANT * pVarResult, EXCEPINFO * pExcepInfo,
+                          unsigned int * puArgErr)
+    { 
+        if (wFlags & (DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
+            return E_NOTIMPL;
+
+        wxASSERT(m_activeX);
+
+        // find event for dispid 
+        wxActiveX::MemberIdMap::iterator mit = m_activeX->m_eventMemberIds.find((MEMBERID) dispIdMember);
+        if (mit == m_activeX->m_eventMemberIds.end())
+            return S_OK;
+
+        // sanity check
+        int midx = mit->second;
+        if (midx < 0 || midx >= m_activeX->GetEventCount())
+            return S_OK;
+
+        wxActiveX::FuncX &func = m_activeX->m_events[midx];
+
+
+        // try to find dispid event
+        ActiveXDISPIDEventMap::iterator dit = sg_dispIdEventMap.find(dispIdMember);
+        if (dit != sg_dispIdEventMap.end())
+        {
+            // Dispatch Event
+            DispatchEvent(func, *(dit->second), pDispParams);
+            return S_OK;
+        };
+
+        // try named event
+        ActiveXNamedEventMap::iterator nit = sg_NamedEventMap.find(func.name);
+        if (nit == sg_NamedEventMap.end())
+            return S_OK;
+
+        // Dispatch Event
+        DispatchEvent(func, *(nit->second), pDispParams);
+        return S_OK;
+    }
+};
+
+bool wxActiveXEventsInterface(wxActiveXEvents *self, REFIID iid, void **_interface, const char *&desc)
+{
+    if (self->m_haveCustomId && IsEqualIID(iid, self->m_customId))
+    {
+        WXOLE_TRACE("Found Custom Dispatch Interface");
+        *_interface = (IUnknown *) (IDispatch *) self;
+        desc = "Custom Dispatch Interface";
+        return true;
+    };
+
+    return false;
+};
+
+DEFINE_OLE_TABLE(wxActiveXEvents)
+    OLE_IINTERFACE(IUnknown)
+    OLE_INTERFACE(IID_IDispatch, IDispatch)
+    OLE_INTERFACE_CUSTOM(wxActiveXEventsInterface)
+END_OLE_TABLE;
+
+wxString wxActiveXEvent::EventName()
+{
+    return m_params.GetName();
+};
+
+int wxActiveXEvent::ParamCount() const
+{
+    return m_params.GetCount();
+};
+
+wxString wxActiveXEvent::ParamType(int idx)
+{
+    wxASSERT(idx >= 0 && idx < m_params.GetCount());
+
+    return m_params[idx].GetType();
+};
+
+wxString wxActiveXEvent::ParamName(int idx)
+{
+    wxASSERT(idx >= 0 && idx < m_params.GetCount());
+
+    return m_params[idx].GetName();
+};
+
+static wxVariant nullVar;
+
+wxVariant& wxActiveXEvent::operator[] (int idx)
+{
+    wxASSERT(idx >= 0 && idx < ParamCount());
+
+    return m_params[idx];
+};
+
+wxVariant& wxActiveXEvent::operator[] (wxString name)
+{
+    for (int i = 0; i < m_params.GetCount(); i++)
+    {
+        if (name.CmpNoCase(m_params[i].GetName()) == 0)
+            return m_params[i];
+    };
+
+    wxString err = "wxActiveXEvent::operator[] invalid name <" + name + ">";
+    err += "\r\nValid Names = :\r\n";
+    for (i = 0; i < m_params.GetCount(); i++)
+    {
+        err += m_params[i].GetName();
+        err += "\r\n";
+    };
+
+    wxASSERT_MSG(false, err);
+
+    return nullVar;
+};
+
+void wxActiveX::GetTypeInfo()
+{
+    /*
+    We are currently only interested in the IDispatch interface 
+    to the control. For dual interfaces (TypeKind = TKIND_INTERFACE)
+    we should drill down through the inheritance 
+    (using TYPEATTR->cImplTypes) and GetRefTypeOfImplType(n)
+    and retrieve all the func names etc that way, then generate a C++ 
+    header  file for it.
+
+    But we don't do this and probably never will, so if we have a DUAL 
+    interface then we query for the IDispatch 
+    via GetRefTypeOfImplType(-1).
+    */
+
+    HRESULT hret = 0;
+
+    // get type info via class info
+    wxAutoOleInterface<IProvideClassInfo> classInfo(IID_IProvideClassInfo, m_ActiveX);
+    if (! classInfo.Ok())
+        return;
+
+    // type info
+    wxAutoOleInterface<ITypeInfo> typeInfo;
+    hret = classInfo->GetClassInfo(typeInfo.GetRef());
+    if (! typeInfo.Ok())
+        return;
+
+    // TYPEATTR
+    TYPEATTR *ta = NULL;
+    hret = typeInfo->GetTypeAttr(&ta);
+    if (! ta)
+        return;
+
+    // this should be a TKIND_COCLASS
+    wxASSERT(ta->typekind == TKIND_COCLASS);
+
+    // iterate contained interfaces
+    for (int i = 0; i < ta->cImplTypes; i++)
+    {
+        HREFTYPE rt = 0;
+
+        // get dispatch type info handle
+        hret = typeInfo->GetRefTypeOfImplType(i, &rt);
+        if (! SUCCEEDED(hret))
+            continue;
+
+        // get dispatch type info interface
+        wxAutoOleInterface<ITypeInfo>  ti;
+        hret = typeInfo->GetRefTypeInfo(rt, ti.GetRef());
+        if (! ti.Ok())
+            continue;
+
+        // check if default event sink
+        bool defInterface = false;
+        bool defEventSink = false;
+        int impTypeFlags = 0;
+        typeInfo->GetImplTypeFlags(i, &impTypeFlags);
+
+        if (impTypeFlags & IMPLTYPEFLAG_FDEFAULT)
+        {
+            if (impTypeFlags & IMPLTYPEFLAG_FSOURCE)
+            {
+                WXOLE_TRACEOUT("Default Event Sink");
+                defEventSink = true;
+                if (impTypeFlags & IMPLTYPEFLAG_FDEFAULTVTABLE)
+                {
+                    WXOLE_TRACEOUT("*ERROR* - Default Event Sink is via vTable");
+                    defEventSink = false;
+                };
+            }
+            else
+            {
+                WXOLE_TRACEOUT("Default Interface");
+                defInterface = true;
+            }
+        };
+
+
+        // process
+        GetTypeInfo(ti, defInterface, defEventSink);
+    };
+
+
+    // free
+    typeInfo->ReleaseTypeAttr(ta);
+};
+
+void ElemDescToParam(const ELEMDESC& ed, wxActiveX::ParamX& param)
+{
+    param.flags = ed.idldesc.wIDLFlags;
+    param.vt = ed.tdesc.vt;
+    param.isPtr = (param.vt == VT_PTR);
+    param.isSafeArray = (param.vt == VT_SAFEARRAY);
+    if (param.isPtr || param.isSafeArray)
+        param.vt = ed.tdesc.lptdesc->vt;
+};
+
+void wxActiveX::GetTypeInfo(ITypeInfo *ti, bool defInterface, bool defEventSink)
+{
+    // wxAutoOleInterface<> assumes a ref has already been added
+    ti->AddRef();
+    wxAutoOleInterface<ITypeInfo> typeInfo(ti);
+
+    // TYPEATTR
+    TYPEATTR *ta = NULL;
+    HRESULT hret = typeInfo->GetTypeAttr(&ta);
+    if (! ta)
+        return;
+
+    if (ta->typekind == TKIND_DISPATCH)
+    {
+        WXOLE_TRACEOUT("GUID = " << GetIIDName(ta->guid).c_str());
+
+        if (defEventSink)
+        {
+            wxActiveXEvents *disp = new wxActiveXEvents(this, ta->guid);
+            ConnectAdvise(ta->guid, disp);
+        };
+
+
+        // Get Function Names
+        for (int i = 0; i < ta->cFuncs; i++)
+        {
+            FUNCDESC FAR *fd = NULL;
+
+            hret = typeInfo->GetFuncDesc(i, &fd);
+            if (! fd)
+                continue;
+
+            BSTR anames[1] = {NULL};
+            unsigned int n = 0;
+
+            hret = typeInfo->GetNames(fd->memid, anames, 1, &n);
+
+            if (anames[0])
+            {
+                wxString name = anames[0];
+
+                WXOLE_TRACEOUT("Name " << i << " = " << name.c_str());
+                SysFreeString(anames[0]);
+
+                if (defInterface || defEventSink)
+                {
+                    FuncX func;
+                    func.name = name;
+                    func.memid = fd->memid;
+                    func.hasOut = false;
+
+                    // get Param Names
+                    unsigned int maxPNames = fd->cParams + 1;
+                    unsigned int nPNames = 0;
+                    BSTR *pnames = new BSTR[maxPNames];
+
+                    hret = typeInfo->GetNames(fd->memid, pnames, maxPNames, &nPNames);
+
+                    int pbase = 0;
+                    if (fd->cParams < int(nPNames))
+                    {
+                        pbase++;
+                        SysFreeString(pnames[0]);
+                    };
+
+                    // params
+                    ElemDescToParam(fd->elemdescFunc, func.retType);
+                    for (int p = 0; p < fd->cParams; p++)
+                    {
+                        ParamX param;
+
+                        ElemDescToParam(fd->lprgelemdescParam[p], param);
+
+                        param.name = pnames[pbase + p];
+                        SysFreeString(pnames[pbase + p]);
+
+                        param.isOptional = (p > fd->cParams - fd->cParamsOpt);
+
+                        func.hasOut |= (param.IsOut() || param.isPtr);
+                        func.params.push_back(param);
+                    };
+                    delete [] pnames;
+
+                    if (defEventSink)
+                    {
+                        m_events.push_back(func);
+                        m_eventMemberIds[fd->memid] = m_events.size() - 1;
+                    }
+                    else
+                    {
+                        if (fd->invkind == INVOKE_FUNC)
+                        {
+                            m_methods.push_back(func);
+                            m_methodNames[func.name] = m_methods.size() - 1;
+                        }
+                        else
+                        {
+                            NameMap::iterator it = m_propNames.find(func.name);
+                            int idx = -1;
+                            if (it == m_propNames.end())
+                            {
+                                m_props.push_back(PropX());
+                                idx = m_props.size() - 1;
+                                m_propNames[func.name] = idx;
+                                m_props[idx].name = func.name;
+                                m_props[idx].memid = func.memid;
+                                
+                            }
+                            else
+                                idx = it->second;
+                            
+                            if (fd->invkind == INVOKE_PROPERTYGET)
+                                m_props[idx].type = func.retType;
+                            else if (func.params.size() > 0)
+                            {
+                                m_props[idx].arg = func.params[0];
+                                m_props[idx].putByRef = (fd->invkind == INVOKE_PROPERTYPUTREF);
+                            };
+                        };
+                    };
+                };
+            };
+
+            typeInfo->ReleaseFuncDesc(fd);
+        };
+    }
+
+    typeInfo->ReleaseTypeAttr(ta);
+};
+
+///////////////////////////////////////////////
+// Type Info exposure
+const wxActiveX::FuncX& wxActiveX::GetEventDesc(int idx) const
+{
+    wxASSERT(idx >= 0 && idx < GetEventCount());
+
+    return m_events[idx];
+};
+
+const wxActiveX::PropX& wxActiveX::GetPropDesc(int idx) const
+{
+    if (idx < 0 || idx >= GetPropCount())
+        throw exception("Property index out of bounds");
+
+    return m_props[idx];
+};
+
+const wxActiveX::PropX& wxActiveX::GetPropDesc(const wxString& name) const
+{
+    NameMap::const_iterator it = m_propNames.find(name);
+    if (it == m_propNames.end())
+    {
+        wxString s;
+        s << "property <" << name << "> not found";
+        throw exception(s.mb_str());
+    };
+
+    return GetPropDesc(it->second);
+};
+
+const wxActiveX::FuncX& wxActiveX::GetMethodDesc(int idx) const
+{
+    if (idx < 0 || idx >= GetMethodCount())
+        throw exception("Method index out of bounds");
+
+
+    return m_methods[idx];
+};
+
+
+const wxActiveX::FuncX& wxActiveX::GetMethodDesc(const wxString& name) const
+{
+    NameMap::const_iterator it = m_methodNames.find(name);
+    if (it == m_methodNames.end())
+    {
+        wxString s;
+        s << "method <" << name << "> not found";
+        throw exception(s.mb_str());
+    };
+
+    return GetMethodDesc(it->second);
+};
+
+
+void wxActiveX::SetProp(MEMBERID name, VARIANTARG& value)
+{
+    DISPID pids[1] = {DISPID_PROPERTYPUT};
+    DISPPARAMS params = {&value, pids, 1, 1};
+
+    EXCEPINFO x;
+    memset(&x, 0, sizeof(x));
+    unsigned int argErr = 0;
+
+    HRESULT hr = m_Dispatch->Invoke(
+        name, 
+        IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT,
+        &params, NULL, &x, &argErr);
+
+    WXOLE_WARN(hr, "Invoke Prop(...)");
+};
+
+void wxActiveX::SetProp(const wxString &name, const wxVariant &value)
+{
+    const PropX& prop = GetPropDesc(name);
+    if (! prop.CanSet())
+    {
+        wxString s;
+        s << "property <" << name << "> is readonly";
+        throw exception(s.mb_str());
+    };
+
+    VARIANT v = {prop.arg.vt};
+    VariantToMSWVariant(value, v);
+    SetProp(prop.memid, v);
+    VariantClear(&v); // this releases any BSTR's etc
+};
+
+VARIANT wxActiveX::GetPropAsVariant(MEMBERID name)
+{
+    VARIANT v;
+    VariantInit(&v);
+
+    DISPPARAMS params = {NULL, NULL, 0, 0};
+
+    EXCEPINFO x;
+    memset(&x, 0, sizeof(x));
+    unsigned int argErr = 0;
+
+    HRESULT hr = m_Dispatch->Invoke(
+        name, 
+        IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET,
+        &params, &v, &x, &argErr);
+
+    WXOLE_WARN(hr, "Invoke Prop(...)");
+
+    return v;
+};
+
+VARIANT wxActiveX::GetPropAsVariant(const wxString& name)
+{
+    const PropX& prop = GetPropDesc(name);
+    if (! prop.CanGet())
+    {
+        wxString s;
+        s << "property <" << name << "> is writeonly";
+        throw exception(s.mb_str());
+    };
+
+    return GetPropAsVariant(prop.memid);
+};
+    
+wxVariant wxActiveX::GetPropAsWxVariant(const wxString& name)
+{
+    VARIANT v = GetPropAsVariant(name);
+    HRESULT hr = VariantChangeType(&v, &v, 0, VT_BSTR);
+    if (! SUCCEEDED(hr))
+        throw exception("Unable to convert variant");
+
+    wxVariant wv;
+    MSWVariantToVariant(v, wv);
+
+    VariantClear(&v);
+
+    return wv;
+};
+
+wxString wxActiveX::GetPropAsString(const wxString& name)
+{
+    VARIANT v = GetPropAsVariant(name);
+    HRESULT hr = VariantChangeType(&v, &v, 0, VT_BSTR);
+    if (! SUCCEEDED(hr))
+        throw exception("Unable to convert variant");
+
+    wxString s = v.bstrVal;
+    VariantClear(&v);
+
+    return s;
+};
+
+char wxActiveX::GetPropAsChar(const wxString& name)
+{
+    VARIANT v = GetPropAsVariant(name);
+    HRESULT hr = VariantChangeType(&v, &v, 0, VT_I1);
+    if (! SUCCEEDED(hr))
+        throw exception("Unable to convert variant");
+
+    return v.cVal;
+};
+
+long wxActiveX::GetPropAsLong(const wxString& name)
+{
+    VARIANT v = GetPropAsVariant(name);
+    HRESULT hr = VariantChangeType(&v, &v, 0, VT_I4);
+    if (! SUCCEEDED(hr))
+        throw exception("Unable to convert variant");
+
+    return v.iVal;
+};
+
+bool wxActiveX::GetPropAsBool(const wxString& name)
+{
+    VARIANT v = GetPropAsVariant(name);
+    HRESULT hr = VariantChangeType(&v, &v, 0, VT_BOOL);
+    if (! SUCCEEDED(hr))
+        throw exception("Unable to convert variant");
+
+    return v.boolVal != 0;
+};
+
+double wxActiveX::GetPropAsDouble(const wxString& name)
+{
+    VARIANT v = GetPropAsVariant(name);
+    HRESULT hr = VariantChangeType(&v, &v, 0, VT_R8);
+    if (! SUCCEEDED(hr))
+        throw exception("Unable to convert variant");
+
+    return v.dblVal;
+};
+
+wxDateTime wxActiveX::GetPropAsDateTime(const wxString& name)
+{
+    wxDateTime dt;
+    VARIANT v = GetPropAsVariant(name);
+
+    if (! VariantToWxDateTime(v, dt))
+        throw exception("Unable to convert variant to wxDateTime");
+
+    return dt;
+};
+
+void *wxActiveX::GetPropAsPointer(const wxString& name)
+{
+    VARIANT v = GetPropAsVariant(name);
+    HRESULT hr = VariantChangeType(&v, &v, 0, VT_BYREF);
+    if (! SUCCEEDED(hr))
+        throw exception("Unable to convert variant");
+
+    return v.byref;
+};
+
+
+
+// call methods
+VARIANT wxActiveX::CallMethod(MEMBERID name, VARIANTARG args[], int argc)
+{
+    DISPPARAMS pargs = {args, NULL, argc, 0};
+    VARIANT retVal;
+    VariantInit(&retVal);
+
+    EXCEPINFO x;
+    memset(&x, 0, sizeof(x));
+    unsigned int argErr = 0;
+
+    HRESULT hr = m_Dispatch->Invoke(
+        name, 
+        IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
+        &pargs, &retVal, &x, &argErr);
+
+    WXOLE_WARN(hr, "Invoke Method(...)");
+    return retVal;
+};
+
+VARIANT wxActiveX::CallMethod(const wxString& name, VARIANTARG args[], int argc)
+{
+    const FuncX& func = GetMethodDesc(name);
+    if (argc < 0)
+        argc = func.params.size();
+
+    return CallMethod(func.memid, args, argc);
+};
+
+
+wxVariant wxActiveX::CallMethod(const wxString& name, wxVariant args[], int nargs)
+{
+    const FuncX& func = GetMethodDesc(name);
+
+    if (args == NULL)
+        nargs = 0;
+
+    VARIANTARG *vargs = NULL;
+    if (nargs < 0)
+        nargs = func.params.size();
+
+    if (nargs > 0)
+        vargs = new VARIANTARG[nargs];
+
+    if (vargs)
+    {
+        // init type of vargs
+        for (int i = 0; i < nargs; i++)
+            vargs[nargs - i - 1].vt = func.params[i].vt;
+
+        // put data
+        for (i = 0; i < nargs; i++)
+            VariantToMSWVariant(args[i], vargs[nargs - i - 1]);
+    };
+
+    VARIANT rv = CallMethod(func.memid, vargs, nargs);
+
+    // process any by ref params
+    if (func.hasOut)
+    {
+        for (int i = 0; i < nargs; i++)
+        {
+            VARIANTARG& va = vargs[nargs - i - 1];
+            const wxActiveX::ParamX &px = func.params[i];
+
+            if (px.IsOut())
+            {
+                wxVariant& vx = args[i];
+
+                MSWVariantToVariant(va, vx);
+            };
+        };
+    }
+
+    if (vargs)
+    {
+        for (int i = 0; i < nargs; i++)
+            VariantClear(&vargs[i]);
+        delete [] vargs;
+    };
+
+    wxVariant ret;
+
+    MSWVariantToVariant(rv, ret);
+    VariantClear(&rv);
+
+    return ret;
+};
+
+
+///////////////////////////////////////////////
+
+HRESULT wxActiveX::ConnectAdvise(REFIID riid, IUnknown *events)
+{
+    wxOleConnectionPoint    cp;
+    DWORD                   adviseCookie = 0;
+
+    wxAutoOleInterface<IConnectionPointContainer> cpContainer(IID_IConnectionPointContainer, m_ActiveX);
+    if (! cpContainer.Ok())
+        return E_FAIL;
+    
+    HRESULT hret = cpContainer->FindConnectionPoint(riid, cp.GetRef());
+    if (! SUCCEEDED(hret))
+        return hret;
+    
+    hret = cp->Advise(events, &adviseCookie);
+
+    if (SUCCEEDED(hret))
+        m_connections.push_back(wxOleConnection(cp, adviseCookie));
+    else
+    {
+        WXOLE_WARN(hret, "ConnectAdvise");
+    };
+
+    return hret;
+};
+
+HRESULT wxActiveX::AmbientPropertyChanged(DISPID dispid)
+{
+    wxAutoOleInterface<IOleControl> oleControl(IID_IOleControl, m_oleObject);
+
+    if (oleControl.Ok())
+        return oleControl->OnAmbientPropertyChange(dispid);
+    else
+        return S_FALSE;
+};
+
+#define HIMETRIC_PER_INCH   2540
+#define MAP_PIX_TO_LOGHIM(x,ppli)   MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
+
+static void PixelsToHimetric(SIZEL &sz)
+{
+    static int logX = 0;
+    static int logY = 0;
+
+    if (logY == 0)
+    {
+        // initaliase
+        HDC dc = GetDC(NULL);
+        logX = GetDeviceCaps(dc, LOGPIXELSX);
+        logY = GetDeviceCaps(dc, LOGPIXELSY);
+        ReleaseDC(NULL, dc);
+    };
+
+#define HIMETRIC_INCH   2540
+#define CONVERT(x, logpixels)   MulDiv(HIMETRIC_INCH, (x), (logpixels))
+
+    sz.cx = CONVERT(sz.cx, logX);
+    sz.cy = CONVERT(sz.cy, logY);
+
+#undef CONVERT
+#undef HIMETRIC_INCH
+}
+
+
+void wxActiveX::OnSize(wxSizeEvent& event)
+{
+    int w, h;
+    GetClientSize(&w, &h);
+
+    RECT posRect;
+    posRect.left = 0;
+    posRect.top = 0;
+    posRect.right = w;
+    posRect.bottom = h;
+
+    if (w <= 0 && h <= 0)
+        return;
+
+    // extents are in HIMETRIC units
+    if (m_oleObject.Ok())
+    {
+        SIZEL sz = {w, h};
+        PixelsToHimetric(sz);
+
+        SIZEL sz2;
+
+        m_oleObject->GetExtent(DVASPECT_CONTENT, &sz2);
+        if (sz2.cx !=  sz.cx || sz.cy != sz2.cy)
+            m_oleObject->SetExtent(DVASPECT_CONTENT, &sz);
+    };
+
+    if (m_oleInPlaceObject.Ok()) 
+        m_oleInPlaceObject->SetObjectRects(&posRect, &posRect);
+}
+
+void wxActiveX::OnPaint(wxPaintEvent& event)
+{
+    wxLogTrace(wxT(""),wxT("repainting activex win"));
+    wxPaintDC dc(this);
+    dc.BeginDrawing();
+    int w, h;
+    GetSize(&w, &h);
+    RECT posRect;
+    posRect.left = 0;
+    posRect.top = 0;
+    posRect.right = w;
+    posRect.bottom = h;
+
+    // Draw only when control is windowless or deactivated
+    if (m_viewObject)
+    {
+        ::RedrawWindow(m_oleObjectHWND, NULL, NULL, RDW_INTERNALPAINT);
+        {
+            RECTL *prcBounds = (RECTL *) &posRect;
+            m_viewObject->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL, 
+                (HDC)dc.GetHDC(), prcBounds, NULL, NULL, 0);
+        }
+    }
+    else
+    {
+        dc.SetBrush(*wxRED_BRUSH);
+        dc.DrawRectangle(0, 0, w, h);
+        dc.SetBrush(wxNullBrush);
+    }
+    dc.EndDrawing();
+}
+
+
+void wxActiveX::OnMouse(wxMouseEvent& event)
+{
+    if (m_oleObjectHWND == NULL) 
+    { 
+        wxLogTrace(wxT(""),wxT("no oleInPlaceObject")); 
+        event.Skip(); 
+        return; 
+    }
+
+    wxLogTrace(wxT(""),wxT("mouse event"));
+    UINT msg = 0;
+    WPARAM wParam = 0;
+    LPARAM lParam = 0;
+    LRESULT lResult = 0;
+
+    if (event.m_metaDown) 
+        wParam |= MK_CONTROL;
+    if (event.m_shiftDown) 
+        wParam |= MK_SHIFT;
+    if (event.m_leftDown) 
+        wParam |= MK_LBUTTON;
+    if (event.m_middleDown) 
+        wParam |= MK_MBUTTON;
+    if (event.m_rightDown) 
+        wParam |= MK_RBUTTON;
+    lParam = event.m_x << 16;
+    lParam |= event.m_y;
+
+    if (event.LeftDown()) 
+        msg = WM_LBUTTONDOWN;
+    else if (event.LeftDClick()) 
+        msg = WM_LBUTTONDBLCLK;
+    else if (event.LeftUp()) 
+        msg = WM_LBUTTONUP;
+    else if (event.MiddleDown()) 
+        msg = WM_MBUTTONDOWN;
+    else if (event.MiddleDClick()) 
+        msg = WM_MBUTTONDBLCLK;
+    else if (event.MiddleUp()) 
+        msg = WM_MBUTTONUP;
+    else if (event.RightDown()) 
+        msg = WM_RBUTTONDOWN;
+    else if (event.RightDClick()) 
+        msg = WM_RBUTTONDBLCLK;
+    else if (event.RightUp()) 
+        msg = WM_RBUTTONUP;
+    else if (event.Moving() || event.Dragging()) 
+        msg = WM_MOUSEMOVE;
+
+    wxString log;
+    if (msg == 0) 
+    { 
+        wxLogTrace(wxT(""),wxT("no message"));
+        event.Skip(); return; 
+    };
+
+    if (!::SendMessage(m_oleObjectHWND, msg, wParam, lParam)) 
+    { 
+        wxLogTrace(wxT(""),wxT("msg not delivered"));
+        event.Skip(); 
+        return; 
+    };
+
+    wxLogTrace(wxT(""),wxT("msg sent"));
+}
+
+long wxActiveX::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
+{
+    if (m_oleObjectHWND == NULL)
+        return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
+
+    switch(nMsg)
+    {
+    case WM_CHAR:
+    case WM_DEADCHAR:
+    case WM_KEYDOWN:
+    case WM_KEYUP:
+    case WM_SYSCHAR:
+    case WM_SYSDEADCHAR:
+    case WM_SYSKEYDOWN:
+    case WM_SYSKEYUP:
+        PostMessage(m_oleObjectHWND, nMsg, wParam, lParam);
+
+    default:
+        return wxWindow::MSWWindowProc(nMsg, wParam, lParam);
+    };
+};
+
+void wxActiveX::OnSetFocus(wxFocusEvent& event)
+{
+    if (m_oleInPlaceActiveObject.Ok()) 
+        m_oleInPlaceActiveObject->OnFrameWindowActivate(TRUE);
+}
+
+void wxActiveX::OnKillFocus(wxFocusEvent& event)
+{
+    if (m_oleInPlaceActiveObject.Ok()) 
+        m_oleInPlaceActiveObject->OnFrameWindowActivate(FALSE);
+}
+
+
+FrameSite::FrameSite(wxActiveX * win)
+{
+    m_window = win;
+    m_bSupportsWindowlessActivation = true;
+    m_bInPlaceLocked = false;
+    m_bUIActive = false;
+    m_bInPlaceActive = false;
+    m_bWindowless = false;
+
+    m_nAmbientLocale = 0;
+    m_clrAmbientForeColor = ::GetSysColor(COLOR_WINDOWTEXT);
+    m_clrAmbientBackColor = ::GetSysColor(COLOR_WINDOW);
+    m_bAmbientShowHatching = true;
+    m_bAmbientShowGrabHandles = true;
+    m_bAmbientAppearance = true;
+    m_hDCBuffer = NULL;
+    m_hWndParent = (HWND)m_window->GetHWND();
+}
+
+FrameSite::~FrameSite()
+{
+}
+
+
+//IDispatch
+
+HRESULT FrameSite::GetIDsOfNames(REFIID riid, OLECHAR ** rgszNames, unsigned int cNames,
+                                 LCID lcid, DISPID * rgDispId)
+{
+    WXOLE_TRACE("IDispatch::GetIDsOfNames");
+    return E_NOTIMPL;
+}
+
+HRESULT FrameSite::GetTypeInfo(unsigned int iTInfo, LCID lcid, ITypeInfo ** ppTInfo)
+{
+    WXOLE_TRACE("IDispatch::GetTypeInfo");
+    return E_NOTIMPL;
+}
+
+HRESULT FrameSite::GetTypeInfoCount(unsigned int * pcTInfo)
+{
+    WXOLE_TRACE("IDispatch::GetTypeInfoCount");
+    return E_NOTIMPL;
+}
+
+HRESULT FrameSite::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
+                          WORD wFlags, DISPPARAMS * pDispParams,
+                          VARIANT * pVarResult, EXCEPINFO * pExcepInfo,
+                          unsigned int * puArgErr)
+{
+    WXOLE_TRACE("IDispatch::Invoke");
+
+    if (!(wFlags & DISPATCH_PROPERTYGET))
+        return S_OK;
+
+    HRESULT hr;
+
+    if (pVarResult == NULL) 
+        return E_INVALIDARG;
+
+    //The most common case is boolean, use as an initial type
+    V_VT(pVarResult) = VT_BOOL;
+
+    switch (dispIdMember)
+    {
+        case DISPID_AMBIENT_MESSAGEREFLECT:
+            WXOLE_TRACE("Invoke::DISPID_AMBIENT_MESSAGEREFLECT");
+            V_BOOL(pVarResult)= FALSE;
+            return S_OK;
+
+        case DISPID_AMBIENT_DISPLAYASDEFAULT:
+            WXOLE_TRACE("Invoke::DISPID_AMBIENT_DISPLAYASDEFAULT");
+            V_BOOL(pVarResult)= TRUE;
+            return S_OK;
+
+        case DISPID_AMBIENT_OFFLINEIFNOTCONNECTED:
+            WXOLE_TRACE("Invoke::DISPID_AMBIENT_OFFLINEIFNOTCONNECTED");
+            V_BOOL(pVarResult) = TRUE;
+            return S_OK;
+
+
+        case DISPID_AMBIENT_SILENT:
+            WXOLE_TRACE("Invoke::DISPID_AMBIENT_SILENT");
+            V_BOOL(pVarResult)= TRUE;
+            return S_OK;
+
+        case DISPID_AMBIENT_APPEARANCE:
+            pVarResult->vt = VT_BOOL;
+            pVarResult->boolVal = m_bAmbientAppearance;
+            break;
+
+        case DISPID_AMBIENT_FORECOLOR:
+            pVarResult->vt = VT_I4;
+            pVarResult->lVal = (long) m_clrAmbientForeColor;
+            break;
+
+        case DISPID_AMBIENT_BACKCOLOR:
+            pVarResult->vt = VT_I4;
+            pVarResult->lVal = (long) m_clrAmbientBackColor;
+            break;
+
+        case DISPID_AMBIENT_LOCALEID:
+            pVarResult->vt = VT_I4;
+            pVarResult->lVal = (long) m_nAmbientLocale;
+            break;
+
+        case DISPID_AMBIENT_USERMODE:
+            pVarResult->vt = VT_BOOL;
+            pVarResult->boolVal = m_window->m_bAmbientUserMode;
+            break;
+
+        case DISPID_AMBIENT_SHOWGRABHANDLES:
+            pVarResult->vt = VT_BOOL;
+            pVarResult->boolVal = m_bAmbientShowGrabHandles;
+            break;
+
+        case DISPID_AMBIENT_SHOWHATCHING:
+            pVarResult->vt = VT_BOOL;
+            pVarResult->boolVal = m_bAmbientShowHatching;
+            break;
+
+        default:
+            return DISP_E_MEMBERNOTFOUND;
+    }
+
+    return S_OK;
+}
+
+//IOleWindow
+
+HRESULT FrameSite::GetWindow(HWND * phwnd)
+{
+    WXOLE_TRACE("IOleWindow::GetWindow");
+    if (phwnd == NULL) 
+        return E_INVALIDARG;
+    (*phwnd) = m_hWndParent;
+    return S_OK;
+}
+
+HRESULT FrameSite::ContextSensitiveHelp(BOOL fEnterMode)
+{
+    WXOLE_TRACE("IOleWindow::ContextSensitiveHelp");
+    return S_OK;
+}
+
+//IOleInPlaceUIWindow
+
+HRESULT FrameSite::GetBorder(LPRECT lprectBorder)
+{
+    WXOLE_TRACE("IOleInPlaceUIWindow::GetBorder");
+    if (lprectBorder == NULL) 
+        return E_INVALIDARG;
+    return INPLACE_E_NOTOOLSPACE;
+}
+
+HRESULT FrameSite::RequestBorderSpace(LPCBORDERWIDTHS pborderwidths)
+{
+    WXOLE_TRACE("IOleInPlaceUIWindow::RequestBorderSpace");
+    if (pborderwidths == NULL) 
+        return E_INVALIDARG;
+    return INPLACE_E_NOTOOLSPACE;
+}
+
+HRESULT FrameSite::SetBorderSpace(LPCBORDERWIDTHS pborderwidths)
+{
+    WXOLE_TRACE("IOleInPlaceUIWindow::SetBorderSpace");
+    return S_OK;
+}
+
+HRESULT FrameSite::SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
+{
+    WXOLE_TRACE("IOleInPlaceUIWindow::SetActiveObject");
+
+    if (pActiveObject)
+        pActiveObject->AddRef();
+
+    m_window->m_oleInPlaceActiveObject = pActiveObject;
+    return S_OK;
+}
+
+//IOleInPlaceFrame
+
+HRESULT FrameSite::InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
+{
+    WXOLE_TRACE("IOleInPlaceFrame::InsertMenus");
+    return S_OK;
+}
+
+HRESULT FrameSite::SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
+{
+    WXOLE_TRACE("IOleInPlaceFrame::SetMenu");
+    return S_OK;
+}
+
+HRESULT FrameSite::RemoveMenus(HMENU hmenuShared)
+{
+    WXOLE_TRACE("IOleInPlaceFrame::RemoveMenus");
+    return S_OK;
+}
+
+HRESULT FrameSite::SetStatusText(LPCOLESTR pszStatusText)
+{
+    WXOLE_TRACE("IOleInPlaceFrame::SetStatusText");
+    //((wxFrame*)wxGetApp().GetTopWindow())->GetStatusBar()->SetStatusText(pszStatusText);
+    return S_OK;
+}
+
+HRESULT FrameSite::EnableModeless(BOOL fEnable)
+{
+    WXOLE_TRACE("IOleInPlaceFrame::EnableModeless");
+    return S_OK;
+}
+
+HRESULT FrameSite::TranslateAccelerator(LPMSG lpmsg, WORD wID)
+{
+    WXOLE_TRACE("IOleInPlaceFrame::TranslateAccelerator");
+    // TODO: send an event with this id
+    if (m_window->m_oleInPlaceActiveObject.Ok())
+        m_window->m_oleInPlaceActiveObject->TranslateAccelerator(lpmsg);
+
+    return S_FALSE;
+}
+
+//IOleInPlaceSite
+
+HRESULT FrameSite::CanInPlaceActivate()
+{
+    WXOLE_TRACE("IOleInPlaceSite::CanInPlaceActivate");
+    return S_OK;
+}
+
+HRESULT FrameSite::OnInPlaceActivate()
+{
+    WXOLE_TRACE("IOleInPlaceSite::OnInPlaceActivate");
+    m_bInPlaceActive = true;
+    return S_OK;
+}
+
+HRESULT FrameSite::OnUIActivate()
+{
+    WXOLE_TRACE("IOleInPlaceSite::OnUIActivate");
+    m_bUIActive = true;
+    return S_OK;
+}
+
+HRESULT FrameSite::GetWindowContext(IOleInPlaceFrame **ppFrame,
+                                    IOleInPlaceUIWindow **ppDoc,
+                                    LPRECT lprcPosRect,
+                                    LPRECT lprcClipRect,
+                                    LPOLEINPLACEFRAMEINFO lpFrameInfo)
+{
+    WXOLE_TRACE("IOleInPlaceSite::GetWindowContext");
+    if (ppFrame == NULL || ppDoc == NULL || lprcPosRect == NULL ||
+        lprcClipRect == NULL || lpFrameInfo == NULL)
+    {
+        if (ppFrame != NULL) 
+            (*ppFrame) = NULL;
+        if (ppDoc != NULL) 
+            (*ppDoc) = NULL;
+        return E_INVALIDARG;
+    }
+
+    HRESULT hr = QueryInterface(IID_IOleInPlaceFrame, (void **) ppFrame);
+    if (! SUCCEEDED(hr))
+    {
+        WXOLE_TRACE("IOleInPlaceSite::IOleInPlaceFrame Error !");
+        return E_UNEXPECTED;
+    };
+
+    hr = QueryInterface(IID_IOleInPlaceUIWindow, (void **) ppDoc);
+    if (! SUCCEEDED(hr))
+    {
+        WXOLE_TRACE("IOleInPlaceSite::IOleInPlaceUIWindow Error !");
+        (*ppFrame)->Release();
+        *ppFrame = NULL;
+        return E_UNEXPECTED;
+    };
+
+    int w, h;
+    m_window->GetClientSize(&w, &h);
+    if (lprcPosRect)
+    {
+        lprcPosRect->left = lprcPosRect->top = 0;
+        lprcPosRect->right = w;
+        lprcPosRect->bottom = h;
+    };
+    if (lprcClipRect)
+    {
+        lprcClipRect->left = lprcClipRect->top = 0;
+        lprcClipRect->right = w;
+        lprcClipRect->bottom = h;
+    };
+
+    memset(lpFrameInfo, 0, sizeof(OLEINPLACEFRAMEINFO));
+    lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO);
+    lpFrameInfo->hwndFrame = m_hWndParent;
+
+    return S_OK;
+}
+
+HRESULT FrameSite::Scroll(SIZE scrollExtent)
+{
+    WXOLE_TRACE("IOleInPlaceSite::Scroll");
+    return S_OK;
+}
+
+HRESULT FrameSite::OnUIDeactivate(BOOL fUndoable)
+{
+    WXOLE_TRACE("IOleInPlaceSite::OnUIDeactivate");
+    m_bUIActive = false;
+    return S_OK;
+}
+
+HRESULT FrameSite::OnInPlaceDeactivate()
+{
+    WXOLE_TRACE("IOleInPlaceSite::OnInPlaceDeactivate");
+    m_bInPlaceActive = false;
+    return S_OK;
+}
+
+HRESULT FrameSite::DiscardUndoState()
+{
+    WXOLE_TRACE("IOleInPlaceSite::DiscardUndoState");
+    return S_OK;
+}
+
+HRESULT FrameSite::DeactivateAndUndo()
+{
+    WXOLE_TRACE("IOleInPlaceSite::DeactivateAndUndo");
+    return S_OK;
+}
+
+HRESULT FrameSite::OnPosRectChange(LPCRECT lprcPosRect)
+{
+    WXOLE_TRACE("IOleInPlaceSite::OnPosRectChange");
+    if (m_window->m_oleInPlaceObject.Ok() && lprcPosRect)
+        m_window->m_oleInPlaceObject->SetObjectRects(lprcPosRect, lprcPosRect);
+
+    return S_OK;
+}
+
+//IOleInPlaceSiteEx
+
+HRESULT FrameSite::OnInPlaceActivateEx(BOOL * pfNoRedraw, DWORD dwFlags)
+{
+    WXOLE_TRACE("IOleInPlaceSiteEx::OnInPlaceActivateEx");
+    OleLockRunning(m_window->m_ActiveX, TRUE, FALSE);
+    if (pfNoRedraw) 
+        (*pfNoRedraw) = FALSE;
+    return S_OK;
+}
+
+HRESULT FrameSite::OnInPlaceDeactivateEx(BOOL fNoRedraw)
+{
+    WXOLE_TRACE("IOleInPlaceSiteEx::OnInPlaceDeactivateEx");
+    OleLockRunning(m_window->m_ActiveX, FALSE, FALSE);
+    return S_OK;
+}
+
+HRESULT FrameSite::RequestUIActivate()
+{
+    WXOLE_TRACE("IOleInPlaceSiteEx::RequestUIActivate");
+    return S_OK;
+}
+
+
+//IOleClientSite
+
+HRESULT FrameSite::SaveObject()
+{
+    WXOLE_TRACE("IOleClientSite::SaveObject");
+    return S_OK;
+}
+
+const char *OleGetMonikerToStr(DWORD dwAssign)
+{
+    switch (dwAssign)
+    {
+    case OLEGETMONIKER_ONLYIFTHERE  : return "OLEGETMONIKER_ONLYIFTHERE";
+    case OLEGETMONIKER_FORCEASSIGN  : return "OLEGETMONIKER_FORCEASSIGN";
+    case OLEGETMONIKER_UNASSIGN     : return "OLEGETMONIKER_UNASSIGN";
+    case OLEGETMONIKER_TEMPFORUSER  : return "OLEGETMONIKER_TEMPFORUSER";    
+    default                         : return "Bad Enum";
+    };
+};
+
+const char *OleGetWhicMonikerStr(DWORD dwWhichMoniker)
+{
+    switch(dwWhichMoniker)
+    {
+    case OLEWHICHMK_CONTAINER   : return "OLEWHICHMK_CONTAINER";
+    case OLEWHICHMK_OBJREL      : return "OLEWHICHMK_OBJREL";
+    case OLEWHICHMK_OBJFULL     : return "OLEWHICHMK_OBJFULL";
+    default                     : return "Bad Enum";
+    };
+};
+
+HRESULT FrameSite::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker,
+                              IMoniker ** ppmk)
+{
+    WXOLE_TRACEOUT("IOleClientSite::GetMoniker(" << OleGetMonikerToStr(dwAssign) << ", " << OleGetWhicMonikerStr(dwWhichMoniker) << ")");
+
+
+    if (! ppmk)
+        return E_FAIL;
+
+    /*
+    HRESULT hr = CreateFileMoniker(L"e:\\dev\\wxie\\bug-zap.swf", ppmk);
+    if (SUCCEEDED(hr))
+        return S_OK;
+    */
+    *ppmk = NULL;
+    
+    return E_FAIL ;
+}
+
+HRESULT FrameSite::GetContainer(LPOLECONTAINER * ppContainer)
+{
+    WXOLE_TRACE("IOleClientSite::GetContainer");
+    if (ppContainer == NULL) 
+        return E_INVALIDARG;
+    
+    HRESULT hr = QueryInterface(IID_IOleContainer, (void**)(ppContainer));
+    wxASSERT(SUCCEEDED(hr));
+
+    return hr;
+}
+
+HRESULT FrameSite::ShowObject()
+{
+    WXOLE_TRACE("IOleClientSite::ShowObject");
+    if (m_window->m_oleObjectHWND)
+        ::ShowWindow(m_window->m_oleObjectHWND, SW_SHOW);
+    return S_OK;
+}
+
+HRESULT FrameSite::OnShowWindow(BOOL fShow)
+{
+    WXOLE_TRACE("IOleClientSite::OnShowWindow");
+    return S_OK;
+}
+
+HRESULT FrameSite::RequestNewObjectLayout()
+{
+    WXOLE_TRACE("IOleClientSite::RequestNewObjectLayout");
+    return E_NOTIMPL;
+}
+
+// IParseDisplayName
+
+HRESULT FrameSite::ParseDisplayName(IBindCtx *pbc, LPOLESTR pszDisplayName,
+                                    ULONG *pchEaten, IMoniker **ppmkOut)
+{
+    WXOLE_TRACE("IParseDisplayName::ParseDisplayName");
+    return E_NOTIMPL;
+}
+
+//IOleContainer
+
+HRESULT FrameSite::EnumObjects(DWORD grfFlags, IEnumUnknown **ppenum)
+{
+    WXOLE_TRACE("IOleContainer::EnumObjects");
+    return E_NOTIMPL;
+}
+
+HRESULT FrameSite::LockContainer(BOOL fLock)
+{
+    WXOLE_TRACE("IOleContainer::LockContainer");
+    // TODO
+    return S_OK;
+}
+
+//IOleItemContainer
+
+HRESULT FrameSite::GetObject(LPOLESTR pszItem, DWORD dwSpeedNeeded, 
+                             IBindCtx * pbc, REFIID riid, void ** ppvObject)
+{
+    WXOLE_TRACE("IOleItemContainer::GetObject");
+    if (pszItem == NULL) 
+        return E_INVALIDARG;
+    if (ppvObject == NULL) 
+        return E_INVALIDARG;
+
+    *ppvObject = NULL;
+    return MK_E_NOOBJECT;
+}
+
+HRESULT FrameSite::GetObjectStorage(LPOLESTR pszItem, IBindCtx * pbc, 
+                                    REFIID riid, void ** ppvStorage)
+{
+    WXOLE_TRACE("IOleItemContainer::GetObjectStorage");
+    if (pszItem == NULL) 
+        return E_INVALIDARG;
+    if (ppvStorage == NULL) 
+        return E_INVALIDARG;
+
+    *ppvStorage = NULL;
+    return MK_E_NOOBJECT;
+}
+
+HRESULT FrameSite::IsRunning(LPOLESTR pszItem)
+{
+    WXOLE_TRACE("IOleItemContainer::IsRunning");
+    if (pszItem == NULL) 
+        return E_INVALIDARG;
+
+    return MK_E_NOOBJECT;
+}
+
+
+
+//IOleControlSite
+
+HRESULT FrameSite::OnControlInfoChanged()
+{
+    WXOLE_TRACE("IOleControlSite::OnControlInfoChanged");
+    return S_OK;
+}
+
+HRESULT FrameSite::LockInPlaceActive(BOOL fLock)
+{
+    WXOLE_TRACE("IOleControlSite::LockInPlaceActive");
+    m_bInPlaceLocked = (fLock) ? true : false;
+    return S_OK;
+}
+
+HRESULT FrameSite::GetExtendedControl(IDispatch ** ppDisp)
+{
+    WXOLE_TRACE("IOleControlSite::GetExtendedControl");
+    return E_NOTIMPL;
+}
+
+HRESULT FrameSite::TransformCoords(POINTL * pPtlHimetric, POINTF * pPtfContainer, DWORD dwFlags)
+{
+    WXOLE_TRACE("IOleControlSite::TransformCoords");
+    HRESULT hr = S_OK;
+
+    if (pPtlHimetric == NULL)
+        return E_INVALIDARG;
+
+    if (pPtfContainer == NULL)
+        return E_INVALIDARG;
+
+    return E_NOTIMPL;
+
+}
+
+HRESULT FrameSite::TranslateAccelerator(LPMSG pMsg, DWORD grfModifiers)
+{
+    WXOLE_TRACE("IOleControlSite::TranslateAccelerator");
+    // TODO: send an event with this id
+    return E_NOTIMPL;
+}
+
+HRESULT FrameSite::OnFocus(BOOL fGotFocus)
+{
+    WXOLE_TRACE("IOleControlSite::OnFocus");
+    return S_OK;
+}
+
+HRESULT FrameSite::ShowPropertyFrame()
+{
+    WXOLE_TRACE("IOleControlSite::ShowPropertyFrame");
+    return E_NOTIMPL;
+}
+
+//IOleCommandTarget
+
+HRESULT FrameSite::QueryStatus(const GUID * pguidCmdGroup, ULONG cCmds, 
+                               OLECMD * prgCmds, OLECMDTEXT * pCmdTet)
+{
+    WXOLE_TRACE("IOleCommandTarget::QueryStatus");
+    if (prgCmds == NULL) return E_INVALIDARG;
+    bool bCmdGroupFound = false;
+
+    for (ULONG nCmd = 0; nCmd < cCmds; nCmd++)
+    {
+        // unsupported by default
+        prgCmds[nCmd].cmdf = 0;
+
+        // TODO
+    }
+
+    if (!bCmdGroupFound) { OLECMDERR_E_UNKNOWNGROUP; }
+    return S_OK;
+}
+
+HRESULT FrameSite::Exec(const GUID * pguidCmdGroup, DWORD nCmdID, 
+                        DWORD nCmdExecOpt, VARIANTARG * pVaIn, 
+                        VARIANTARG * pVaOut)
+{
+    WXOLE_TRACE("IOleCommandTarget::Exec");
+    bool bCmdGroupFound = false;
+
+    if (!bCmdGroupFound) { OLECMDERR_E_UNKNOWNGROUP; }
+    return OLECMDERR_E_NOTSUPPORTED;
+}
+
+//IAdviseSink
+
+void STDMETHODCALLTYPE FrameSite::OnDataChange(FORMATETC * pFormatEtc, STGMEDIUM * pgStgMed)
+{
+    WXOLE_TRACE("IAdviseSink::OnDataChange");
+}
+
+void STDMETHODCALLTYPE FrameSite::OnViewChange(DWORD dwAspect, LONG lIndex)
+{
+    WXOLE_TRACE("IAdviseSink::OnViewChange");
+    // redraw the control
+}
+
+void STDMETHODCALLTYPE FrameSite::OnRename(IMoniker * pmk)
+{
+    WXOLE_TRACE("IAdviseSink::OnRename");
+}
+
+void STDMETHODCALLTYPE FrameSite::OnSave()
+{
+    WXOLE_TRACE("IAdviseSink::OnSave");
+}
+
+void STDMETHODCALLTYPE FrameSite::OnClose()
+{
+    WXOLE_TRACE("IAdviseSink::OnClose");
+}
+
+/////////////////////////////////////////////
+// IOleDocumentSite
+HRESULT STDMETHODCALLTYPE FrameSite::ActivateMe(
+        /* [in] */ IOleDocumentView __RPC_FAR *pViewToActivate)
+{
+    wxAutoOleInterface<IOleInPlaceSite> inPlaceSite(IID_IOleInPlaceSite, (IDispatch *) this);
+    if (!inPlaceSite.Ok())
+        return E_FAIL;
+
+    if (pViewToActivate)
+    {
+        m_window->m_docView = pViewToActivate;
+        m_window->m_docView->SetInPlaceSite(inPlaceSite);
+    }
+    else
+    {
+        wxAutoOleInterface<IOleDocument> oleDoc(IID_IOleDocument, m_window->m_oleObject);
+        if (! oleDoc.Ok())
+            return E_FAIL;
+
+        HRESULT hr = oleDoc->CreateView(inPlaceSite, NULL, 0, m_window->m_docView.GetRef());
+        if (hr != S_OK)
+            return E_FAIL;
+
+        m_window->m_docView->SetInPlaceSite(inPlaceSite);
+    };
+
+    m_window->m_docView->UIActivate(TRUE);
+
+    return S_OK;
+};
+
+
+static IMalloc *iMalloc = NULL;
+
+IMalloc *wxOleInit::GetIMalloc()
+{
+    assert(iMalloc);
+    return iMalloc;
+};
+
+wxOleInit::wxOleInit()
+{
+    if (OleInitialize(NULL) == S_OK && iMalloc == NULL)
+        CoGetMalloc(1, &iMalloc);
+    else if (iMalloc)
+        iMalloc->AddRef();
+};
+
+wxOleInit::~wxOleInit()
+{
+    if (iMalloc)
+    {
+        if (iMalloc->Release() == 0)
+            iMalloc = NULL;
+    };
+
+    OleUninitialize();
+}
+
+bool GetSysErrMessage(int err, wxString& s)
+{
+    char buf[256];
+    if (FormatMessage(
+        FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+        err,0, buf, sizeof(buf), NULL) == 0)
+        return false;
+
+    buf[sizeof(buf) - 1] = 0;
+    s = buf;
+    return true;
+};
+
+wxString OLEHResultToString(HRESULT hr)
+{
+    // try formatmessage
+    wxString err;
+    if (GetSysErrMessage(hr, err))
+        return err;
+
+    switch (hr)
+    {
+    case S_OK:
+        return "";
+
+    case CONNECT_E_CANNOTCONNECT:
+        return "Cannot connect to event interface (maybe not there ?) - see MSDN";
+
+    case DISP_E_MEMBERNOTFOUND:
+        return "The requested member does not exist, or the call to Invoke tried to set the value of a read-only property.";
+
+    case DISP_E_BADVARTYPE:
+        return "One of the parameters in rgvarg is not a valid variant type.";
+
+    case DISP_E_BADPARAMCOUNT:
+        return "The number of elements provided to DISPPARAMS is different from the number of parameters accepted by the method or property";
+
+    case DISP_E_EXCEPTION:
+        return "The application needs to raise an exception. In this case, the structure passed in pExcepInfo should be filled in.";
+
+    case DISP_E_TYPEMISMATCH:
+        return "One or more of the parameters could not be coerced. The index within rgvarg of the first parameter with the incorrect type is returned in the puArgErr parameter.";
+
+    case DISP_E_PARAMNOTOPTIONAL:
+        return "A required parameter was omitted.";
+
+    case DISP_E_PARAMNOTFOUND:
+        return "One of the parameter DISPIDs does not correspond to a parameter on the method. In this case, puArgErr should be set to the first parameter that contains the error.";
+
+    case OLECMDERR_E_UNKNOWNGROUP:
+        return "The pguidCmdGroup parameter is not NULL but does not specify a recognized command group.";
+
+    case OLECMDERR_E_NOTSUPPORTED:
+        return "The nCmdID parameter is not a valid command in the group identified by pguidCmdGroup.";
+
+    case OLECMDERR_E_DISABLED:
+        return "The command identified by nCmdID is currently disabled and cannot be executed.";
+
+    case OLECMDERR_E_NOHELP:
+        return "The caller has asked for help on the command identified by nCmdID, but no help is available.";
+
+    case OLECMDERR_E_CANCELED:
+        return "The user canceled the execution of the command.";
+
+    case E_INVALIDARG:
+        return "E_INVALIDARG";
+
+    case E_OUTOFMEMORY:
+        return "E_OUTOFMEMORY";
+
+    case E_NOINTERFACE:
+        return "E_NOINTERFACE";
+
+    case E_UNEXPECTED:
+        return "E_UNEXPECTED";
+
+    case STG_E_INVALIDFLAG:
+        return "STG_E_INVALIDFLAG";
+
+    case E_FAIL:
+        return "E_FAIL";
+
+    case E_NOTIMPL:
+        return "E_NOTIMPL";
+
+    default:
+        {
+            char buf[64];
+            sprintf(buf, "Unknown - 0x%X", hr);
+            return wxString(buf);
+        }
+    };
+};
+
+// borrowed from src/msw/ole/oleutils.cpp
+wxString GetIIDName(REFIID riid)
+{
+  // an association between symbolic name and numeric value of an IID
+  struct KNOWN_IID 
+  {
+    const IID  *pIid;
+    const wxChar *szName;
+  };
+
+  // construct the table containing all known interfaces
+  #define ADD_KNOWN_IID(name) { &IID_I##name, _T(#name) }
+  #define ADD_KNOWN_GUID(name) { &name, _T(#name) }
+
+  static const KNOWN_IID aKnownIids[] = 
+  {
+    ADD_KNOWN_IID(ServiceProvider),
+    ADD_KNOWN_IID(AdviseSink),
+    ADD_KNOWN_IID(AdviseSink2),
+    ADD_KNOWN_IID(BindCtx),
+    ADD_KNOWN_IID(ClassFactory),
+#if ( !defined( __VISUALC__) || (__VISUALC__!=1010) ) && !defined(__MWERKS__)
+    ADD_KNOWN_IID(ContinueCallback),
+    ADD_KNOWN_IID(EnumOleDocumentViews),
+    ADD_KNOWN_IID(OleCommandTarget),
+    ADD_KNOWN_IID(OleDocument),
+    ADD_KNOWN_IID(OleDocumentSite),
+    ADD_KNOWN_IID(OleDocumentView),
+    ADD_KNOWN_IID(Print),
+#endif
+    ADD_KNOWN_IID(DataAdviseHolder),
+    ADD_KNOWN_IID(DataObject),
+    ADD_KNOWN_IID(Debug),
+    ADD_KNOWN_IID(DebugStream),
+    ADD_KNOWN_IID(DfReserved1),
+    ADD_KNOWN_IID(DfReserved2),
+    ADD_KNOWN_IID(DfReserved3),
+    ADD_KNOWN_IID(Dispatch),
+    ADD_KNOWN_IID(DropSource),
+    ADD_KNOWN_IID(DropTarget),
+    ADD_KNOWN_IID(EnumCallback),
+    ADD_KNOWN_IID(EnumFORMATETC),
+    ADD_KNOWN_IID(EnumGeneric),
+    ADD_KNOWN_IID(EnumHolder),
+    ADD_KNOWN_IID(EnumMoniker),
+    ADD_KNOWN_IID(EnumOLEVERB),
+    ADD_KNOWN_IID(EnumSTATDATA),
+    ADD_KNOWN_IID(EnumSTATSTG),
+    ADD_KNOWN_IID(EnumString),
+    ADD_KNOWN_IID(EnumUnknown),
+    ADD_KNOWN_IID(EnumVARIANT),
+    ADD_KNOWN_IID(ExternalConnection),
+    ADD_KNOWN_IID(InternalMoniker),
+    ADD_KNOWN_IID(LockBytes),
+    ADD_KNOWN_IID(Malloc),
+    ADD_KNOWN_IID(Marshal),
+    ADD_KNOWN_IID(MessageFilter),
+    ADD_KNOWN_IID(Moniker),
+    ADD_KNOWN_IID(OleAdviseHolder),
+    ADD_KNOWN_IID(OleCache),
+    ADD_KNOWN_IID(OleCache2),
+    ADD_KNOWN_IID(OleCacheControl),
+    ADD_KNOWN_IID(OleClientSite),
+    ADD_KNOWN_IID(OleContainer),
+    ADD_KNOWN_IID(OleInPlaceActiveObject),
+    ADD_KNOWN_IID(OleInPlaceFrame),
+    ADD_KNOWN_IID(OleInPlaceObject),
+    ADD_KNOWN_IID(OleInPlaceSite),
+    ADD_KNOWN_IID(OleInPlaceUIWindow),
+    ADD_KNOWN_IID(OleItemContainer),
+    ADD_KNOWN_IID(OleLink),
+    ADD_KNOWN_IID(OleManager),
+    ADD_KNOWN_IID(OleObject),
+    ADD_KNOWN_IID(OlePresObj),
+    ADD_KNOWN_IID(OleWindow),
+    ADD_KNOWN_IID(PSFactory),
+    ADD_KNOWN_IID(ParseDisplayName),
+    ADD_KNOWN_IID(Persist),
+    ADD_KNOWN_IID(PersistFile),
+    ADD_KNOWN_IID(PersistStorage),
+    ADD_KNOWN_IID(PersistStream),
+    ADD_KNOWN_IID(ProxyManager),
+    ADD_KNOWN_IID(RootStorage),
+    ADD_KNOWN_IID(RpcChannel),
+    ADD_KNOWN_IID(RpcProxy),
+    ADD_KNOWN_IID(RpcStub),
+    ADD_KNOWN_IID(RunnableObject),
+    ADD_KNOWN_IID(RunningObjectTable),
+    ADD_KNOWN_IID(StdMarshalInfo),
+    ADD_KNOWN_IID(Storage),
+    ADD_KNOWN_IID(Stream),
+    ADD_KNOWN_IID(StubManager),
+    ADD_KNOWN_IID(Unknown),
+    ADD_KNOWN_IID(ViewObject),
+    ADD_KNOWN_IID(ViewObject2),
+    ADD_KNOWN_GUID(IID_IDispatch),
+    ADD_KNOWN_GUID(IID_IWebBrowser),
+    ADD_KNOWN_GUID(IID_IWebBrowserApp),
+    ADD_KNOWN_GUID(IID_IWebBrowser2),
+    ADD_KNOWN_GUID(IID_IWebBrowser),
+    ADD_KNOWN_GUID(DIID_DWebBrowserEvents2),
+    ADD_KNOWN_GUID(DIID_DWebBrowserEvents),
+  };
+
+  // don't clobber preprocessor name space
+  #undef ADD_KNOWN_IID
+  #undef ADD_KNOWN_GUID
+
+  // try to find the interface in the table
+  for ( size_t ui = 0; ui < WXSIZEOF(aKnownIids); ui++ ) 
+  {
+    if ( riid == *aKnownIids[ui].pIid ) 
+    {
+      return aKnownIids[ui].szName;
+    }
+  }
+
+  // unknown IID, just transform to string
+  LPOLESTR str = NULL;
+  StringFromIID(riid, &str);
+  if (str)
+  {
+      wxString s = str;
+      CoTaskMemFree(str);
+      return s;
+  }
+  else
+      return "StringFromIID() error";
+}