]> git.saurik.com Git - wxWidgets.git/commitdiff
convert COM arguments to wx lazily to improve performance and allow calling Invoke...
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 25 Jan 2009 12:25:43 +0000 (12:25 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 25 Jan 2009 12:25:43 +0000 (12:25 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@58384 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/ole/activex.h
interface/wx/msw/ole/activex.h
src/msw/ole/activex.cpp

index 8f557c82152731d6385c7a2c1f5cef61a819073f..fa91f27f6c8febc30f26fe17ea84bd2cd45c9978 100644 (file)
@@ -174,6 +174,27 @@ protected:
     void CreateActiveX(REFIID, IUnknown*);
 };
 
+///\brief Store native event parameters.
+///\detail Store OLE 'Invoke' parameters for event handlers that need to access them.
+/// These are the exact values for the event as they are passed to the wxActiveXContainer.
+struct wxActiveXEventNativeMSW
+{
+    DISPID  dispIdMember;
+    REFIID  riid;
+    LCID    lcid;
+    WORD    wFlags;
+    DISPPARAMS  *pDispParams;
+    VARIANT     *pVarResult;
+    EXCEPINFO   *pExcepInfo;
+    unsigned int *puArgErr;
+
+    wxActiveXEventNativeMSW
+        (DISPID a_dispIdMember, REFIID a_riid, LCID a_lcid, WORD a_wFlags, DISPPARAMS  *a_pDispParams,
+        VARIANT *a_pVarResult, EXCEPINFO *a_pExcepInfo, unsigned int *a_puArgErr)
+        :dispIdMember(a_dispIdMember), riid(a_riid), lcid(a_lcid), wFlags(a_wFlags), pDispParams(a_pDispParams),
+        pVarResult(a_pVarResult), pExcepInfo(a_pExcepInfo), puArgErr(a_puArgErr)
+    { }
+};
 
 // Events
 class WXDLLIMPEXP_CORE wxActiveXEvent : public wxCommandEvent
@@ -187,29 +208,27 @@ public:
     virtual wxEvent *Clone() const
     { return new wxActiveXEvent(*this); }
 
-    size_t ParamCount() const
-    {   return m_params.GetCount();  }
+    size_t ParamCount() const;
 
     wxString ParamType(size_t idx) const
     {
-        wxASSERT(idx < m_params.GetCount());
+        wxASSERT(idx < ParamCount());
         return m_params[idx].GetType();
     }
 
     wxString ParamName(size_t idx) const
     {
-        wxASSERT(idx < m_params.GetCount());
+        wxASSERT(idx < ParamCount());
         return m_params[idx].GetName();
     }
 
-    wxVariant& operator[] (size_t idx)
-    {
-        wxASSERT(idx < ParamCount());
-        return m_params[idx];
-    }
+    wxVariant& operator[] (size_t idx);
 
     DISPID GetDispatchId() const
     {   return m_dispid;    }
+
+    wxActiveXEventNativeMSW *GetNativeParameters() const
+    {   return (wxActiveXEventNativeMSW*)GetClientData(); }
 };
 
 // #define wxACTIVEX_ID    14001
index 5bfeab0d715e446c80d81d7e6c7bc03897c025e9..19f50d265d73e0f110a8ff9917e5f6ca4b117104 100644 (file)
         ActiveX event.
     @endEventTable
 
+    ActiveX event parameters can get extremely complex and may be beyond the
+    abilities of wxVariant. If 'operator[]' fails, prints an error messages or
+    crashes the application, event handlers should use GetNativeParameters()
+    instead to obtain the original event information.
+    Calls to operator[] and GetNativeParmeters() can be mixed. It is valid
+    to handle some parameters of an event with operator[] and others directly
+    through GetNativeParameters(). It is \b not valid however to manipulate
+    the same parameter using both approaches at the same time.
+
     @onlyfor{wxmsw}
 
     @library{wxcore}
@@ -55,6 +64,16 @@ public:
         Obtains the actual parameter value specified by idx.
     */
     wxVariant operator[](size_t idx);
+
+    /**
+        Obtain the original MSW parameters for the event.
+        Event handlers can use this information to handle complex event parameters
+        that are beyond the scope of wxVariant.
+        The information returned here is the information passed to the original
+        'Invoke' method call.
+        \return a pointer to a struct containing the original MSW event parameters
+    */
+    wxActiveXEventNativeMSW *GetNativeParameters() const;
 };
 
 
index c5ea0cb8e95fc589b98343ea775acb1038c08253..caacde5b4f510582dc755656a21c66e40d2d3ab4 100644 (file)
@@ -694,6 +694,14 @@ 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 const int ptr_invalid_entry_marker = 0;
+    static wxVariant g_invalid_entry_marker;
+
     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()
@@ -717,11 +725,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;
@@ -733,31 +741,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 != g_invalid_entry_marker
+                if (!vx.IsType(wxActiveXEvents::g_invalid_entry_marker.GetType()) || vx!=g_invalid_entry_marker) {
+                    VARIANTARG& va = pDispParams->rgvarg[i];
+                    wxConvertVariantToOle(vx, va);
+                }
+            }
         }
 
         if(event.GetSkipped())
@@ -767,6 +781,46 @@ public:
     }
 };
 
+wxVariant wxActiveXEvents::g_invalid_entry_marker((void*)&wxActiveXEvents::ptr_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::g_invalid_entry_marker);
+        }
+        wxVariant &vx(m_params[idx]);
+        if (vx.IsType(wxActiveXEvents::g_invalid_entry_marker.GetType()) && vx==wxActiveXEvents::g_invalid_entry_marker) {
+            // 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))