The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#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;

// 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, 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, "SafeArray");
    VT(VT_EMPTY, "empty");
    VT(VT_NULL, "null");
    VT(VT_UI1, "byte");
    VT(VT_I1, "char");
    VT(VT_I2, "short");
    VT(VT_I4, "long");
    VT(VT_UI2, "unsigned short");
    VT(VT_UI4, "unsigned long");
    VT(VT_INT, "int");
    VT(VT_UINT, "unsigned int");
    VT(VT_R4, "real(4)");
    VT(VT_R8, "real(8)");
    VT(VT_CY, "Currency");
    VT(VT_DATE, "wxDate");
    VT(VT_BSTR, "wxString");
    VT(VT_DISPATCH, "IDispatch");
    VT(VT_ERROR, "SCode Error");
    VT(VT_BOOL, "bool");
    VT(VT_VARIANT, "wxVariant");
    VT(VT_UNKNOWN, "IUknown");
    VT(VT_VOID, "void");
    VT(VT_PTR, "void *");
    VT(VT_USERDEFINED, "*user defined*");

    default:
        {
            wxString s;
            s << "Unknown(" << vt << ")";
            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 = (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;
    };
};

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

						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 = "" ;
       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 = "" ;
       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 = "" ;
       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 = "" ;
       return( tmp ) ;
     }
     const wxActiveX::FuncX& func = this->GetMethodDesc(idx);
     const wxActiveX::ParamX& param = func.params[argx];
     return( param.name ) ;
}

///////////////////////////////////////////////
// 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 << "property <" << name << "> 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 << "method <" << name << "> 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 << "property <" << name << "> 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 << "property <" << name << "> 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(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("no oleInPlaceObject")); 
        event.Skip(); 
        return; 
    }

	wxLogTrace(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("no message"));
        event.Skip(); return; 
    };

	if (!::SendMessage(m_oleObjectHWND, msg, wParam, lParam)) 
    { 
        wxLogTrace(wxT("msg not delivered"));
        event.Skip(); 
        return; 
    };

	wxLogTrace(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[] = 
  {
#ifdef _MSC_VER
    ADD_KNOWN_IID(ServiceProvider),
#endif
    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";
}