X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/07a971eeffd1b868e80c54e462a5acec27ca96bf..e28cc3ca0aa9bb1c7e9613c447ca94b13a8bc858:/src/msw/ole/activex.cpp?ds=sidebyside diff --git a/src/msw/ole/activex.cpp b/src/msw/ole/activex.cpp index c8383a509c..8a08625124 100644 --- a/src/msw/ole/activex.cpp +++ b/src/msw/ole/activex.cpp @@ -33,17 +33,19 @@ #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 wxAutoIOleInPlaceSite; +typedef wxAutoOleInterface wxAutoIOleDocument; +typedef wxAutoOleInterface wxAutoIPersistStreamInit; +typedef wxAutoOleInterface wxAutoIAdviseSink; +typedef wxAutoOleInterface wxAutoIProvideClassInfo; +typedef wxAutoOleInterface wxAutoITypeInfo; +typedef wxAutoOleInterface wxAutoIConnectionPoint; +typedef wxAutoOleInterface wxAutoIConnectionPointContainer; -wxDEFINE_EVENT( wxEVT_ACTIVEX, wxActiveXEvent ) +wxDEFINE_EVENT( wxEVT_ACTIVEX, wxActiveXEvent ); // Ole class helpers (sort of MFC-like) from wxActiveX #define DECLARE_OLE_UNKNOWN(cls)\ @@ -52,7 +54,7 @@ wxDEFINE_EVENT( wxEVT_ACTIVEX, wxActiveXEvent ) {\ public:\ LONG l;\ - TAutoInitInt() : l(0) {}\ + TAutoInitInt() : l(1) {}\ };\ TAutoInitInt refCount, lockCount;\ static void _GetInterface(cls *self, REFIID iid, void **_interface, const char *&desc);\ @@ -352,7 +354,7 @@ public: HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD) { // TODO: send an event with this id - if (m_window->m_oleInPlaceActiveObject.Ok()) + if (m_window->m_oleInPlaceActiveObject.IsOk()) m_window->m_oleInPlaceActiveObject->TranslateAccelerator(lpmsg); return S_FALSE; } @@ -423,7 +425,7 @@ public: HRESULT STDMETHODCALLTYPE DeactivateAndUndo(){return S_OK; } HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect) { - if (m_window->m_oleInPlaceObject.Ok() && lprcPosRect) + if (m_window->m_oleInPlaceObject.IsOk() && lprcPosRect) { // // Result of several hours and days of bug hunting - @@ -604,7 +606,7 @@ public: { wxAutoIOleInPlaceSite inPlaceSite( IID_IOleInPlaceSite, (IDispatch *) this); - if (!inPlaceSite.Ok()) + if (!inPlaceSite.IsOk()) return E_FAIL; if (pViewToActivate) @@ -616,7 +618,7 @@ public: { wxAutoIOleDocument oleDoc( IID_IOleDocument, m_window->m_oleObject); - if (! oleDoc.Ok()) + if (! oleDoc.IsOk()) return E_FAIL; HRESULT hr = oleDoc->CreateView(inPlaceSite, NULL, @@ -692,6 +694,13 @@ private: 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() @@ -715,11 +724,11 @@ public: } - 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; @@ -731,31 +740,37 @@ public: // 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()) @@ -765,11 +780,61 @@ public: } }; +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; @@ -813,13 +878,13 @@ wxActiveXContainer::wxActiveXContainer(wxWindow * parent, wxActiveXContainer::~wxActiveXContainer() { // disconnect connection points - if (m_oleInPlaceObject.Ok()) + if (m_oleInPlaceObject.IsOk()) { m_oleInPlaceObject->InPlaceDeactivate(); m_oleInPlaceObject->UIDeactivate(); } - if (m_oleObject.Ok()) + if (m_oleObject.IsOk()) { if (m_docAdviseCookie != 0) m_oleObject->Unadvise(m_docAdviseCookie); @@ -839,10 +904,10 @@ wxActiveXContainer::~wxActiveXContainer() } // VZ: we might want to really report an error instead of just asserting here -#ifdef __WXDEBUG__ +#if wxDEBUG_LEVEL #define CHECK_HR(hr) \ - wxASSERT_MSG( SUCCEEDED(hr), \ - wxString::Format("HRESULT = %X", (unsigned)(hr)) ) + wxASSERT_LEVEL_2_MSG( SUCCEEDED(hr), \ + wxString::Format("HRESULT = %X", (unsigned)(hr)) ) #else #define CHECK_HR(hr) wxUnusedVar(hr) #endif @@ -869,7 +934,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) CHECK_HR(hret); // adviseSink wxAutoIAdviseSink adviseSink(IID_IAdviseSink, (IDispatch *) m_frameSite); - wxASSERT(adviseSink.Ok()); + wxASSERT(adviseSink.IsOk()); // Get Dispatch interface hret = m_Dispatch.QueryInterface(IID_IDispatch, m_ActiveX); @@ -881,13 +946,13 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) // get type info via class info wxAutoIProvideClassInfo classInfo(IID_IProvideClassInfo, m_ActiveX); - wxASSERT(classInfo.Ok()); + wxASSERT(classInfo.IsOk()); // type info wxAutoITypeInfo typeInfo; hret = classInfo->GetClassInfo(typeInfo.GetRef()); CHECK_HR(hret); - wxASSERT(typeInfo.Ok()); + wxASSERT(typeInfo.IsOk()); // TYPEATTR TYPEATTR *ta = NULL; @@ -910,7 +975,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) // get dispatch type info interface wxAutoITypeInfo ti; hret = typeInfo->GetRefTypeInfo(rt, ti.GetRef()); - if (! ti.Ok()) + if (! ti.IsOk()) continue; CHECK_HR(hret); @@ -951,17 +1016,31 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) DWORD adviseCookie = 0; wxAutoIConnectionPointContainer cpContainer(IID_IConnectionPointContainer, m_ActiveX); - wxASSERT( cpContainer.Ok()); + wxASSERT( cpContainer.IsOk()); HRESULT hret = cpContainer->FindConnectionPoint(ta->guid, cp.GetRef()); - CHECK_HR(hret); - IDispatch* disp; - m_frameSite->QueryInterface(IID_IDispatch, (void**)&disp); - hret = cp->Advise(new wxActiveXEvents(this, ta->guid), - &adviseCookie); - CHECK_HR(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); + } } } @@ -1014,7 +1093,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) wxAutoIPersistStreamInit pPersistStreamInit(IID_IPersistStreamInit, m_oleObject); - if (pPersistStreamInit.Ok()) + if (pPersistStreamInit.IsOk()) { hret = pPersistStreamInit->InitNew(); CHECK_HR(hret); @@ -1026,7 +1105,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) m_oleObjectHWND = 0; - if (m_oleInPlaceObject.Ok()) + if (m_oleInPlaceObject.IsOk()) { hret = m_oleInPlaceObject->GetWindow(&m_oleObjectHWND); if (SUCCEEDED(hret)) @@ -1040,7 +1119,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) wxCopyRectToRECT(m_realparent->GetClientSize(), posRect); if (posRect.right > 0 && posRect.bottom > 0 && - m_oleInPlaceObject.Ok()) + m_oleInPlaceObject.IsOk()) { m_oleInPlaceObject->SetObjectRects(&posRect, &posRect); } @@ -1054,7 +1133,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk) CHECK_HR(hret); } - if (! m_oleObjectHWND && m_oleInPlaceObject.Ok()) + if (! m_oleObjectHWND && m_oleInPlaceObject.IsOk()) { hret = m_oleInPlaceObject->GetWindow(&m_oleObjectHWND); CHECK_HR(hret); @@ -1103,7 +1182,7 @@ void wxActiveXContainer::OnSize(wxSizeEvent& event) return; // extents are in HIMETRIC units - if (m_oleObject.Ok()) + if (m_oleObject.IsOk()) { m_oleObject->DoVerb(OLEIVERB_HIDE, 0, m_clientSite, 0, (HWND)m_realparent->GetHWND(), &posRect); @@ -1121,7 +1200,7 @@ void wxActiveXContainer::OnSize(wxSizeEvent& event) (HWND)m_realparent->GetHWND(), &posRect); } - if (m_oleInPlaceObject.Ok()) + if (m_oleInPlaceObject.IsOk()) m_oleInPlaceObject->SetObjectRects(&posRect, &posRect); event.Skip(); @@ -1165,7 +1244,7 @@ void wxActiveXContainer::OnPaint(wxPaintEvent& WXUNUSED(event)) //--------------------------------------------------------------------------- void wxActiveXContainer::OnSetFocus(wxFocusEvent& event) { - if (m_oleInPlaceActiveObject.Ok()) + if (m_oleInPlaceActiveObject.IsOk()) m_oleInPlaceActiveObject->OnFrameWindowActivate(TRUE); event.Skip(); @@ -1179,7 +1258,7 @@ void wxActiveXContainer::OnSetFocus(wxFocusEvent& event) //--------------------------------------------------------------------------- void wxActiveXContainer::OnKillFocus(wxFocusEvent& event) { - if (m_oleInPlaceActiveObject.Ok()) + if (m_oleInPlaceActiveObject.IsOk()) m_oleInPlaceActiveObject->OnFrameWindowActivate(FALSE); event.Skip();