
/* SVN-ID:      $Id: wxactivex.cpp 2739 2010-01-05 05:13:25Z mdootson $ */

/*
                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.
*/

#undef read
#undef select
#undef write
#undef send

#include "wx/wxprec.h"
#include "wxactivex.h"
#include <wx/strconv.h>
#include <wx/event.h>
#include <wx/string.h>
#include <wx/datetime.h>

#include <windows.h>
#include <ole2.h>
#include <oleidl.h>
#include <winerror.h>
#include <idispids.h>
#include <exdispid.h>
#include <servprov.h>

#ifndef _MSC_VER
#    include <oleauto.h>
#endif


#include <olectl.h>
#include <Mshtml.h>

#include <sstream>
using namespace std;

#define wxACTIVEX_CLSID_MOZILLA_BROWSER CLSID_MozillaBrowser
#define wxACTIVEX_CLSID_WEB_BROWSER CLSID_WebBrowser

//////////////////////////////////////////////////////////////////////

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, 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);
	}
}

wxString VarTypeAsString(VARTYPE vt)
{
#define VT(vtype, desc) case vtype : return desc

    if (vt & VT_BYREF)
        vt -= VT_BYREF;

    if (vt & VT_ARRAY)
        vt -= VT_ARRAY;

    switch (vt)
    {
    VT(VT_SAFEARRAY, wxT("SafeArray"));
    VT(VT_EMPTY, wxT("empty"));
    VT(VT_NULL, wxT("null"));
    VT(VT_UI1, wxT("byte"));
    VT(VT_I1, wxT("char"));
    VT(VT_I2, wxT("short"));
    VT(VT_I4, wxT("long"));
    VT(VT_UI2, wxT("unsigned short"));
    VT(VT_UI4, wxT("unsigned long"));
    VT(VT_INT, wxT("int"));
    VT(VT_UINT, wxT("unsigned int"));
    VT(VT_R4, wxT("real(4)"));
    VT(VT_R8, wxT("real(8)"));
    VT(VT_CY, wxT("Currency"));
    VT(VT_DATE, wxT("wxDate"));
    VT(VT_BSTR, wxT("wxString"));
    VT(VT_DISPATCH, wxT("IDispatch"));
    VT(VT_ERROR, wxT("SCode Error"));
    VT(VT_BOOL, wxT("bool"));
    VT(VT_VARIANT, wxT("wxVariant"));
    VT(VT_UNKNOWN, wxT("IUknown"));
    VT(VT_VOID, wxT("void"));
    VT(VT_PTR, wxT("void *"));
    VT(VT_USERDEFINED, wxT("*user defined*"));

    default:
        {
            wxString s;
            s << wxT("Unknown(") << vt << wxT(")");
            return s;
        };
    };

#undef VT
};

void wxActiveX::CreateActiveX(REFCLSID clsid)
{
    //SetTransparent();

	HRESULT hret;

    ////////////////////////////////////////////////////////
    // FrameSite
    FrameSite *frame = new FrameSite(this);
    // oleClientSite
    hret = m_clientSite.QueryInterface(IID_IOleClientSite, (IDispatch *) frame);
    wxASSERT(SUCCEEDED(hret));
    // adviseSink
    wxAutoOleInterface<IAdviseSink> adviseSink(IID_IAdviseSink, (IDispatch *) frame);
    wxASSERT(adviseSink.Ok());


	// // Create Object, get IUnknown interface
    m_ActiveX.CreateInstance(clsid, IID_IUnknown);
	wxASSERT(m_ActiveX.Ok());

	// 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);
	wxASSERT(SUCCEEDED(hret));

    // get IViewObject Interface
    hret = m_viewObject.QueryInterface(IID_IViewObject, m_ActiveX);
	wxASSERT(SUCCEEDED(hret));

    // 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);
	wxASSERT(SUCCEEDED(hret));

    // status
	DWORD dwMiscStatus;
	m_oleObject->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus);
    wxASSERT(SUCCEEDED(hret));

    // 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 = (wxChar) *va.pbVal;
		else
            vx = (wxChar) 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 = (wxChar) vx;
		else
            va.bVal = (wxChar) 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;
    };
};

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::FuncXMap::iterator mit = m_activeX->m_events.find((MEMBERID) dispIdMember);
        if (mit == m_activeX->m_events.end())
            return S_OK;

        wxActiveX::FuncX &func = mit->second;


        // 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();
};

wxString wxActiveXEvent::ParamVal(int idx)
{
    wxASSERT(idx >= 0 && idx < m_params.GetCount());

    return m_params[idx] ;
};

void wxActiveXEvent::ParamSetBool(int idx , bool val)
{
    wxASSERT(idx >= 0 && idx < m_params.GetCount());
    m_params[idx] = val ;
};

void wxActiveXEvent::ParamSetInt(int idx , long val)
{
    wxASSERT(idx >= 0 && idx < m_params.GetCount());
    m_params[idx] = val ;
};

void wxActiveXEvent::ParamSetString(int idx , wxString val)
{
    wxASSERT(idx >= 0 && idx < m_params.GetCount());
    m_params[idx] = val ;
};

static wxVariant nullVar;

wxVariant& wxActiveXEvent::operator[] (int idx)
{
    wxASSERT(idx >= 0 && idx < ParamCount());

    return m_params[idx];
};

wxVariant& wxActiveXEvent::operator[] (wxString name)
{
    int i;
    for (i = 0; i < m_params.GetCount(); i++)
    {
        if (name.CmpNoCase(m_params[i].GetName()) == 0)
            return m_params[i];
    };

    wxString err = wxT("wxActiveXEvent::operator[] invalid name <") + name + wxT(">");
    err += wxT("\r\nValid Names = :\r\n");
    for (i = 0; i < m_params.GetCount(); i++)
    {
        err += m_params[i].GetName();
        err += wxT("\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)
	{

#ifdef __WXOLEDEBUG

        WXOLE_TRACEOUT("GUID = " << GetIIDName(ta->guid).c_str());

#endif

        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]);

						func.hasOut |= (param.IsOut() || param.isPtr);
						func.params.push_back(param);
					};
                    delete [] pnames;

					if (defEventSink)
					{
						m_events[fd->memid] = func;
					}
					else
					{
						if (fd->invkind == INVOKE_FUNC)
						{
							m_methods[func.name] = func;
						}
						else
						{
							PropXMap::iterator it = m_props.find(func.name);
							if (it == m_props.end())
                            {
								it = m_props.insert(PropXMap::value_type(func.name, PropX())).first;
                                it->second.name = func.name;
                                it->second.memid = func.memid;

                            };

							if (fd->invkind == INVOKE_PROPERTYGET)
								it->second.type = func.retType;
							else if (func.params.size() > 0)
							{
								it->second.arg = func.params[0];
								it->second.putByRef = (fd->invkind == INVOKE_PROPERTYPUTREF);
							};
						};
					};
                };
			};

			typeInfo->ReleaseFuncDesc(fd);
		};
	}

	typeInfo->ReleaseTypeAttr(ta);
};

wxString wxActiveX::GetEventName(int idx) {
     if (idx < 0 || idx >= this->GetEventCount() ) {
       wxString tmp = wxT("") ;
       return( tmp ) ;
     }
     const wxActiveX::FuncX& func = this->GetEventDesc(idx);
     return( func.name ) ;
}

wxString wxActiveX::GetPropName(int idx) {
     if (idx < 0 || idx >= this->GetPropCount() ) {
       wxString tmp = wxT("") ;
       return( tmp ) ;
     }

     const wxActiveX::PropX prop = this->GetPropDesc(idx);
     return( prop.name ) ;
}

wxString wxActiveX::GetMethodName(int idx) {
     if (idx < 0 || idx >= this->GetMethodCount() ) {
       wxString tmp = wxT("") ;
       return( tmp ) ;
     }
     const wxActiveX::FuncX& func = this->GetMethodDesc(idx);
     return( func.name ) ;
}

wxString wxActiveX::PropType(wxString name)
{
   const wxActiveX::PropX prop = this->GetPropDesc(name);
   wxString ret = VarTypeAsString(prop.type.vt) ;
   return( ret ) ;
};

int wxActiveX::GetMethodArgCount(int idx) {
     if (idx < 0 || idx >= this->GetMethodCount() ) {
       int tmp = 0 ;
       return( tmp ) ;
     }
     const wxActiveX::FuncX& func = this->GetMethodDesc(idx);
     int argsz = func.params.size() ;
     return( argsz ) ;
}

wxString wxActiveX::GetMethodArgName(int idx , int argx) {
     if (idx < 0 || idx >= this->GetMethodCount() ) {
       wxString tmp = wxT("") ;
       return( tmp ) ;
     }
     const wxActiveX::FuncX& func = this->GetMethodDesc(idx);
     const wxActiveX::ParamX& param = func.params[argx];
     return( param.name ) ;
}

void wxActiveX::ActivateOLEWindowDirect(bool activate)
{
    if (m_oleInPlaceActiveObject.Ok())
        m_oleInPlaceActiveObject->OnFrameWindowActivate(activate);
}

///////////////////////////////////////////////
// Type Info exposure
const wxActiveX::FuncX& wxActiveX::GetEventDesc(int idx) const
{
    wxASSERT(idx >= 0 && idx < GetEventCount());

	FuncXMap::const_iterator it = m_events.begin();
	while (idx > 0)
	{
		it++;
		idx--;
	};
    return it->second;
};

const wxActiveX::PropX& wxActiveX::GetPropDesc(int idx) const
{
    if (idx < 0 || idx >= GetPropCount())
        croak("Property index out of bounds");

	PropXMap::const_iterator it = m_props.begin();
	while (idx > 0)
	{
		it++;
		idx--;
	};
    return it->second;
};

const wxActiveX::PropX& wxActiveX::GetPropDesc(wxString name) const
{
	PropXMap::const_iterator it = m_props.find(name);
    if (it == m_props.end())
    {
        wxString s;
        s << wxT("property <") << name << wxT("> not found");
        croak(s.mb_str());
    };

    return it->second;
};

const wxActiveX::FuncX& wxActiveX::GetMethodDesc(int idx) const
{
    if (idx < 0 || idx >= GetMethodCount())
        croak("Method index out of bounds");


	FuncXStringMap::const_iterator it = m_methods.begin();
	while (idx > 0)
	{
		it++;
		idx--;
	};
    return it->second;
};


const wxActiveX::FuncX& wxActiveX::GetMethodDesc(wxString name) const
{
	FuncXStringMap::const_iterator it = m_methods.find(name);
    if (it == m_methods.end())
    {
        wxString s;
        s << wxT("method <") << name << wxT("> not found");
        croak(s.mb_str());
    };

    return 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 << wxT("property <") << name << wxT("> is readonly");
        croak(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 << wxT("property <") << name << wxT("> is writeonly");
		croak(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))
        croak("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))
        croak("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))
        croak("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))
        croak("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))
        croak("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))
        croak("Unable to convert variant");

    return v.dblVal;
};

wxDateTime wxActiveX::GetPropAsDateTime(const wxString& name)
{
	wxDateTime dt;
    VARIANT v = GetPropAsVariant(name);

	if (! VariantToWxDateTime(v, dt))
        croak("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))
        croak("Unable to convert variant");

    return v.byref;
};

wxString wxActiveX::PropVal(wxString name)
{
    return Prop(name) ;
};

void wxActiveX::PropSetBool(wxString name , bool val)
{
    SetProp(name, val) ;
};

void wxActiveX::PropSetInt(wxString name , long val)
{
    SetProp(name, val) ;
};

void wxActiveX::PropSetString(wxString name , wxString val)
{
    SetProp(name, val) ;
};


// 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(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(wxString name, wxVariant args)
{
    const FuncX& func = GetMethodDesc(name);

    VARIANTARG *vargs = NULL;
    int nargs = min(int (args.GetCount()), int (func.params.size()));
    if (nargs > 0)
        vargs = new VARIANTARG[nargs];

    if (vargs)
    {
        // init type of vargs
        int i;
        for (i = 0; i < nargs; i++)
            vargs[nargs - i - 1].vt = func.params[i].vt;

        // put data
        if (args.GetType() == wxT("list"))
        {
            for (i = 0; i < nargs; i++)
                VariantToMSWVariant(args[i], vargs[nargs - i - 1]);
        }
        else
            VariantToMSWVariant(args, vargs[0]);
    };

    VARIANT rv = CallMethod(func.memid, vargs, nargs);

    if (vargs)
    {
        for (int i = 0; i < nargs; i++)
            VariantClear(&vargs[i]);
        delete [] vargs;
    };

    wxVariant ret;

    MSWVariantToVariant(rv, ret);
    VariantClear(&rv);

    return ret;
};

wxVariant wxActiveX::CallMethod(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
		int i;
        for (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('%s', wxT("repainting activex win"));
	wxPaintDC dc(this);
	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();  // deprecated
}


void wxActiveX::OnMouse(wxMouseEvent& event)
{
	if (m_oleObjectHWND == NULL)
    {
        wxLogTrace('%s', wxT("no oleInPlaceObject"));
        event.Skip();
        return;
    }
    wxLogTrace('%s', 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('%s', wxT("no message"));
        event.Skip(); return;
    };

	if (!::SendMessage(m_oleObjectHWND, msg, wParam, lParam))
    {
        event.Skip();
        wxLogTrace('%s', wxT("msg not delivered"));
        return;
    };
    wxLogTrace('%s', 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)
{
    wxChar 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 wxT("");

	case CONNECT_E_CANNOTCONNECT:
        return wxT("Cannot connect to event interface (maybe not there ?) - see MSDN");

    case DISP_E_MEMBERNOTFOUND:
        return wxT("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 wxT("One of the parameters in rgvarg is not a valid variant type.");

    case DISP_E_BADPARAMCOUNT:
        return wxT("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 wxT("The application needs to raise an exception. In this case, the structure passed in pExcepInfo should be filled in.");

    case DISP_E_TYPEMISMATCH:
        return wxT("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 wxT("A required parameter was omitted.");

	case DISP_E_PARAMNOTFOUND:
        return wxT("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 wxT("The pguidCmdGroup parameter is not NULL but does not specify a recognized command group.");

    case OLECMDERR_E_NOTSUPPORTED:
        return wxT("The nCmdID parameter is not a valid command in the group identified by pguidCmdGroup.");

    case OLECMDERR_E_DISABLED:
        return wxT("The command identified by nCmdID is currently disabled and cannot be executed.");

    case OLECMDERR_E_NOHELP:
        return wxT("The caller has asked for help on the command identified by nCmdID, but no help is available.");

    case OLECMDERR_E_CANCELED:
        return wxT("The user canceled the execution of the command.");

    case E_INVALIDARG:
        return wxT("E_INVALIDARG");

    case E_OUTOFMEMORY:
        return wxT("E_OUTOFMEMORY");

    case E_NOINTERFACE:
        return wxT("E_NOINTERFACE");

    case E_UNEXPECTED:
        return wxT("E_UNEXPECTED");

    case STG_E_INVALIDFLAG:
        return wxT("STG_E_INVALIDFLAG");

    case E_FAIL:
        return wxT("E_FAIL");

    case E_NOTIMPL:
        return wxT("E_NOTIMPL");

    default:
        {
            return wxString::Format(wxT("Unknown - 0x%X"), hr);
        }
    };
};

