]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/ole/activex.cpp
Don't close arcs drawn in wxPostScriptDC.
[wxWidgets.git] / src / msw / ole / activex.cpp
index e8e7647a4850c8cc6ccfc25a1ff095d4455a9dac..71bbed04508a21acff9a1c54d5cf5fa5801423d0 100644 (file)
 #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)\
@@ -52,7 +54,7 @@ DEFINE_EVENT_TYPE(wxEVT_ACTIVEX)
     {\
         public:\
         LONG l;\
-        TAutoInitInt() : l(0) {}\
+        TAutoInitInt() : l(1) {}\
     };\
     TAutoInitInt refCount, lockCount;\
     static void _GetInterface(cls *self, REFIID iid, void **_interface, const char *&desc);\
@@ -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;
@@ -829,8 +894,24 @@ wxActiveXContainer::~wxActiveXContainer()
         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
 //
@@ -843,20 +924,21 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
 {
     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
@@ -869,12 +951,13 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
     // 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);
@@ -895,6 +978,8 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
         if (! ti.Ok())
             continue;
 
+        CHECK_HR(hret);
+
         // check if default event sink
         bool defEventSink = false;
         int impTypeFlags = 0;
@@ -920,7 +1005,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
         // TYPEATTR
         TYPEATTR *ta = NULL;
         hret = ti->GetTypeAttr(&ta);
-        wxASSERT(ta);
+        CHECK_HR(hret);
 
         if (ta->typekind == TKIND_DISPATCH)
         {
@@ -935,15 +1020,27 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
 
                 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);
+                }
             }
         }
 
@@ -959,15 +1056,17 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
 
     // 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);
@@ -978,12 +1077,12 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
     // 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)
@@ -997,15 +1096,13 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
     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())
@@ -1018,19 +1115,28 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
 
     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)