#include "wx/msw/dc.h"
#include "wx/msw/ole/activex.h"
+#include "wx/msw/private.h" // for wxCopyRectToRECT
+
// autointerfaces that we only use here
-WX_DECLARE_AUTOOLE(wxAutoIOleInPlaceSite, IOleInPlaceSite)
-WX_DECLARE_AUTOOLE(wxAutoIOleDocument, IOleDocument)
-WX_DECLARE_AUTOOLE(wxAutoIPersistStreamInit, IPersistStreamInit)
-WX_DECLARE_AUTOOLE(wxAutoIAdviseSink, IAdviseSink)
-WX_DECLARE_AUTOOLE(wxAutoIProvideClassInfo, IProvideClassInfo)
-WX_DECLARE_AUTOOLE(wxAutoITypeInfo, ITypeInfo)
-WX_DECLARE_AUTOOLE(wxAutoIConnectionPoint, IConnectionPoint)
-WX_DECLARE_AUTOOLE(wxAutoIConnectionPointContainer, IConnectionPointContainer)
+typedef wxAutoOleInterface<IOleInPlaceSite> wxAutoIOleInPlaceSite;
+typedef wxAutoOleInterface<IOleDocument> wxAutoIOleDocument;
+typedef wxAutoOleInterface<IPersistStreamInit> wxAutoIPersistStreamInit;
+typedef wxAutoOleInterface<IAdviseSink> wxAutoIAdviseSink;
+typedef wxAutoOleInterface<IProvideClassInfo> wxAutoIProvideClassInfo;
+typedef wxAutoOleInterface<ITypeInfo> wxAutoITypeInfo;
+typedef wxAutoOleInterface<IConnectionPoint> wxAutoIConnectionPoint;
+typedef wxAutoOleInterface<IConnectionPointContainer> wxAutoIConnectionPointContainer;
-DEFINE_EVENT_TYPE(wxEVT_ACTIVEX)
+wxDEFINE_EVENT( wxEVT_ACTIVEX, wxActiveXEvent );
// Ole class helpers (sort of MFC-like) from wxActiveX
#define DECLARE_OLE_UNKNOWN(cls)\
{\
public:\
LONG l;\
- TAutoInitInt() : l(0) {}\
+ TAutoInitInt() : l(1) {}\
};\
TAutoInitInt refCount, lockCount;\
static void _GetInterface(cls *self, REFIID iid, void **_interface, const char *&desc);\
friend bool wxActiveXEventsInterface(wxActiveXEvents *self, REFIID iid, void **_interface, const char *&desc);
public:
+
+ // a pointer to this static variable is used as an 'invalid_entry_marker'
+ // wxVariants containing a void* to this variables are 'empty' in the sense
+ // that the actual ActiveX OLE parameter has not been converted and inserted
+ // into m_params.
+ static wxVariant ms_invalidEntryMarker;
+
wxActiveXEvents(wxActiveXContainer *ax) : m_activeX(ax), m_haveCustomId(false) {}
wxActiveXEvents(wxActiveXContainer *ax, REFIID iid) : m_activeX(ax), m_customId(iid), m_haveCustomId(true) {}
virtual ~wxActiveXEvents()
}
- STDMETHODIMP Invoke(DISPID dispIdMember, REFIID WXUNUSED(riid),
- LCID WXUNUSED(lcid),
+ STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid,
+ LCID lcid,
WORD wFlags, DISPPARAMS * pDispParams,
- VARIANT * WXUNUSED(pVarResult), EXCEPINFO * WXUNUSED(pExcepInfo),
- unsigned int * WXUNUSED(puArgErr))
+ VARIANT * pVarResult, EXCEPINFO * pExcepInfo,
+ unsigned int * puArgErr)
{
if (wFlags & (DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
return E_NOTIMPL;
// Dispatch Event
wxActiveXEvent event;
event.SetEventType(wxEVT_ACTIVEX);
+ // Create an empty list of Variants
+ // Note that the event parameters use lazy evaluation
+ // They are not actually created until wxActiveXEvent::operator[] is called
event.m_params.NullList();
event.m_dispid = dispIdMember;
- // arguments
- if (pDispParams)
- {
- for (DWORD i = pDispParams->cArgs; i > 0; i--)
- {
- VARIANTARG& va = pDispParams->rgvarg[i-1];
- wxVariant vx;
+ // save the native (MSW) event parameters for event handlers that need to access them
+ // this can be done on the stack since wxActiveXEvent is also allocated on the stack
+ wxActiveXEventNativeMSW eventParameters(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+ event.SetClientData(&eventParameters);
-// vx.SetName(px.name);
- wxConvertOleToVariant(va, vx);
- event.m_params.Append(vx);
- }
- }
+ // The event parameters are not copied to event.m_params until they are actually
+ // referenced in wxActiveXEvent::operator[]
+ // This increases performance and avoids error messages and/or crashes
+ // when the event has parameters that are not (yet or never) supported
+ // by wxConvertOleToVariant
// process the events from the activex method
- m_activeX->ProcessEvent(event);
+ m_activeX->ProcessEvent(event);
for (DWORD i = 0; i < pDispParams->cArgs; i++)
{
- VARIANTARG& va = pDispParams->rgvarg[i];
- wxVariant& vx =
- event.m_params[pDispParams->cArgs - i - 1];
- wxConvertVariantToOle(vx, va);
+ size_t params_index = pDispParams->cArgs - i - 1;
+ if (params_index < event.m_params.GetCount()) {
+ wxVariant &vx = event.m_params[params_index];
+ // copy the result back to pDispParams only if the event has been accessed
+ // i.e. if vx != ms_invalidEntryMarker
+ if (!vx.IsType(wxActiveXEvents::ms_invalidEntryMarker.GetType()) || vx!=ms_invalidEntryMarker) {
+ VARIANTARG& va = pDispParams->rgvarg[i];
+ wxConvertVariantToOle(vx, va);
+ }
+ }
}
if(event.GetSkipped())
}
};
+namespace
+{
+// just a unique global variable
+const int invalid_entry_marker = 0;
+}
+
+wxVariant wxActiveXEvents::ms_invalidEntryMarker((void*)&invalid_entry_marker);
+
+size_t wxActiveXEvent::ParamCount() const
+{
+ wxActiveXEventNativeMSW *native=GetNativeParameters();
+ // 'native' will always be != if the event has been created
+ // for an actual active X event.
+ // But it may be zero if the event has been created by wx program code.
+ if (native)
+ return native->pDispParams ? native->pDispParams->cArgs : 0;
+
+ return m_params.GetCount();
+}
+
+wxVariant &wxActiveXEvent::operator [](size_t idx)
+{
+ wxASSERT(idx < ParamCount());
+ wxActiveXEventNativeMSW *native=GetNativeParameters();
+ // 'native' will always be != if the event has been created
+ // for an actual active X event.
+ // But it may be zero if the event has been created by wx program code.
+ if (native)
+ {
+ while ( m_params.GetCount()<=idx )
+ {
+ m_params.Append(wxActiveXEvents::ms_invalidEntryMarker);
+ }
+
+ wxVariant& vx = m_params[idx];
+ if ( vx.IsType(wxActiveXEvents::ms_invalidEntryMarker.GetType()) &&
+ vx == wxActiveXEvents::ms_invalidEntryMarker)
+ {
+ // copy the _real_ parameter into this one
+ // NOTE: m_params stores the parameters in *reverse* order.
+ // Whyever, but this was the case in the original implementation of
+ // wxActiveXEvents::Invoke
+ // Keep this convention.
+ VARIANTARG& va = native->pDispParams->rgvarg[ native->pDispParams->cArgs - idx - 1 ];
+ wxConvertOleToVariant(va, vx);
+ }
+ return vx;
+ }
+ return m_params[idx];
+}
+
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;
m_oleObject->Close(OLECLOSE_NOSAVE);
m_oleObject->SetClientSite(NULL);
}
+
+ // m_clientSite uses m_frameSite so destroy it first
+ m_clientSite.Free();
+ delete m_frameSite;
+
+ // our window doesn't belong to us, don't destroy it
+ m_hWnd = NULL;
}
+// VZ: we might want to really report an error instead of just asserting here
+#if wxDEBUG_LEVEL
+ #define CHECK_HR(hr) \
+ wxASSERT_LEVEL_2_MSG( SUCCEEDED(hr), \
+ wxString::Format("HRESULT = %X", (unsigned)(hr)) )
+#else
+ #define CHECK_HR(hr) wxUnusedVar(hr)
+#endif
+
//---------------------------------------------------------------------------
// wxActiveXContainer::CreateActiveX
//
{
HRESULT hret;
hret = m_ActiveX.QueryInterface(iid, pUnk);
- wxASSERT(SUCCEEDED(hret));
+ CHECK_HR(hret);
// FrameSite
- FrameSite *frame = new FrameSite(m_realparent, this);
+ m_frameSite = new FrameSite(m_realparent, this);
// oleClientSite
hret = m_clientSite.QueryInterface(
- IID_IOleClientSite, (IDispatch *) frame);
- wxASSERT(SUCCEEDED(hret));
+ IID_IOleClientSite, (IDispatch *) m_frameSite);
+ CHECK_HR(hret);
// adviseSink
- wxAutoIAdviseSink adviseSink(IID_IAdviseSink, (IDispatch *) frame);
+ wxAutoIAdviseSink adviseSink(IID_IAdviseSink, (IDispatch *) m_frameSite);
wxASSERT(adviseSink.Ok());
// Get Dispatch interface
hret = m_Dispatch.QueryInterface(IID_IDispatch, m_ActiveX);
+ CHECK_HR(hret);
//
// SETUP TYPEINFO AND ACTIVEX EVENTS
// type info
wxAutoITypeInfo typeInfo;
hret = classInfo->GetClassInfo(typeInfo.GetRef());
+ CHECK_HR(hret);
wxASSERT(typeInfo.Ok());
// TYPEATTR
TYPEATTR *ta = NULL;
hret = typeInfo->GetTypeAttr(&ta);
- wxASSERT(ta);
+ CHECK_HR(hret);
// this should be a TKIND_COCLASS
wxASSERT(ta->typekind == TKIND_COCLASS);
if (! ti.Ok())
continue;
+ CHECK_HR(hret);
+
// check if default event sink
bool defEventSink = false;
int impTypeFlags = 0;
// TYPEATTR
TYPEATTR *ta = NULL;
hret = ti->GetTypeAttr(&ta);
- wxASSERT(ta);
+ CHECK_HR(hret);
if (ta->typekind == TKIND_DISPATCH)
{
HRESULT hret =
cpContainer->FindConnectionPoint(ta->guid, cp.GetRef());
- wxASSERT ( SUCCEEDED(hret));
-
- IDispatch* disp;
- frame->QueryInterface(IID_IDispatch, (void**)&disp);
- hret = cp->Advise(new wxActiveXEvents(this, ta->guid),
- &adviseCookie);
- wxASSERT_MSG( SUCCEEDED(hret),
- wxString::Format(wxT("Cannot connect!\nHRESULT:%X"), (unsigned int)hret)
- );
+
+ // Notice that the return value of CONNECT_E_NOCONNECTION is
+ // expected if the interface doesn't support connection points.
+ if ( hret != CONNECT_E_NOCONNECTION )
+ {
+ CHECK_HR(hret);
+ }
+
+ if ( cp )
+ {
+ wxActiveXEvents * const
+ events = new wxActiveXEvents(this, ta->guid);
+ hret = cp->Advise(events, &adviseCookie);
+
+ // We don't need this object any more and cp will keep a
+ // reference to it if it needs it, i.e. if Advise()
+ // succeeded.
+ events->Release();
+
+ CHECK_HR(hret);
+ }
}
}
// Get IOleObject interface
hret = m_oleObject.QueryInterface(IID_IOleObject, m_ActiveX);
- wxASSERT(SUCCEEDED(hret));
+ CHECK_HR(hret);
// get IViewObject Interface
hret = m_viewObject.QueryInterface(IID_IViewObject, m_ActiveX);
- wxASSERT(SUCCEEDED(hret));
+ CHECK_HR(hret);
// document advise
m_docAdviseCookie = 0;
hret = m_oleObject->Advise(adviseSink, &m_docAdviseCookie);
+ CHECK_HR(hret);
+
// TODO:Needed?
// hret = m_viewObject->SetAdvise(DVASPECT_CONTENT, 0, adviseSink);
m_oleObject->SetHostNames(L"wxActiveXContainer", NULL);
// Get IOleInPlaceObject interface
hret = m_oleInPlaceObject.QueryInterface(
IID_IOleInPlaceObject, m_ActiveX);
- wxASSERT(SUCCEEDED(hret));
+ CHECK_HR(hret);
// status
DWORD dwMiscStatus;
m_oleObject->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus);
- wxASSERT(SUCCEEDED(hret));
+ CHECK_HR(hret);
// set client site first ?
if (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
if (pPersistStreamInit.Ok())
{
hret = pPersistStreamInit->InitNew();
+ CHECK_HR(hret);
}
if (! (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
m_oleObject->SetClientSite(m_clientSite);
- RECT posRect;
- ::GetClientRect((HWND)m_realparent->GetHWND(), &posRect);
-
m_oleObjectHWND = 0;
if (m_oleInPlaceObject.Ok())
if (! (dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME))
{
+ RECT posRect;
+ wxCopyRectToRECT(m_realparent->GetClientSize(), posRect);
+
if (posRect.right > 0 && posRect.bottom > 0 &&
m_oleInPlaceObject.Ok())
- m_oleInPlaceObject->SetObjectRects(&posRect, &posRect);
+ {
+ m_oleInPlaceObject->SetObjectRects(&posRect, &posRect);
+ }
hret = m_oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL,
m_clientSite, 0, (HWND)m_realparent->GetHWND(), &posRect);
+ CHECK_HR(hret);
+
hret = m_oleObject->DoVerb(OLEIVERB_SHOW, 0, m_clientSite, 0,
(HWND)m_realparent->GetHWND(), &posRect);
+ CHECK_HR(hret);
}
if (! m_oleObjectHWND && m_oleInPlaceObject.Ok())
{
hret = m_oleInPlaceObject->GetWindow(&m_oleObjectHWND);
+ CHECK_HR(hret);
}
if (m_oleObjectHWND)