wxWidgets/wxPython/contrib/activex/wxie/wxactivex.cpp
2004-05-08 01:29:20 +00:00

2717 lines
71 KiB
C++

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