]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/ole/activex.cpp
added a section about Connect(), improve/streamline the one about event tables
[wxWidgets.git] / src / msw / ole / activex.cpp
index 991e7c9870807927bb545978563f8e760a409085..e8e7647a4850c8cc6ccfc25a1ff095d4455a9dac 100644 (file)
     #pragma hdrstop
 #endif
 
-#include "wx/dcclient.h"
-#include "wx/math.h"
-#include "wx/msw/ole/activex.h"
+#if wxUSE_ACTIVEX
 
+#ifndef WX_PRECOMP
+    #include "wx/dcclient.h"
+    #include "wx/math.h"
+#endif
 
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-//
-// wxActiveXContainer
-//
-//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+#include "wx/msw/dc.h"
 
+#include "wx/msw/ole/activex.h"
+// 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)
+
+DEFINE_EVENT_TYPE(wxEVT_ACTIVEX)
+
+// Ole class helpers (sort of MFC-like) from wxActiveX
 #define DECLARE_OLE_UNKNOWN(cls)\
     private:\
     class TAutoInitInt\
 #define END_OLE_TABLE\
     }
 
+// ============================================================================
+// implementation
+// ============================================================================
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+// PixelsToHimetric
+//
+// Utility to convert from pixels to the himetric values in some COM methods
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+#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)   wxMulDivInt32(HIMETRIC_INCH, (x), (logpixels))
+
+    sz.cx = CONVERT(sz.cx, logX);
+    sz.cy = CONVERT(sz.cy, logY);
+
+#undef CONVERT
+#undef HIMETRIC_INCH
+}
 
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// FrameSite
+//
+// Handles the actual wxActiveX container implementation
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 class FrameSite :
     public IOleClientSite,
     public IOleInPlaceSiteEx,
@@ -207,7 +264,7 @@ public:
             case DISPID_AMBIENT_SILENT:
                 V_BOOL(pVarResult)= TRUE;
                 return S_OK;
-#ifndef __WINE__
+
             case DISPID_AMBIENT_APPEARANCE:
                 pVarResult->vt = VT_BOOL;
                 pVarResult->boolVal = m_bAmbientAppearance;
@@ -242,7 +299,7 @@ public:
                 pVarResult->vt = VT_BOOL;
                 pVarResult->boolVal = m_bAmbientShowHatching;
                 break;
-#endif
+
             default:
                 return DISP_E_MEMBERNOTFOUND;
         }
@@ -368,15 +425,35 @@ public:
     {
         if (m_window->m_oleInPlaceObject.Ok() && lprcPosRect)
         {
+           //
+           // Result of several hours and days of bug hunting -
+           // this is called by an object when it wants to resize
+           // itself to something different then our parent window -
+           // don't let it :)
+           //
+//            m_window->m_oleInPlaceObject->SetObjectRects(
+//                lprcPosRect, lprcPosRect);
+           RECT rcClient;
+           ::GetClientRect(m_hWndParent, &rcClient);
             m_window->m_oleInPlaceObject->SetObjectRects(
-                lprcPosRect, lprcPosRect);
+                &rcClient, &rcClient);
         }
         return S_OK;
     }
     //*************************IOleInPlaceSiteEx***********************
     HRESULT STDMETHODCALLTYPE OnInPlaceActivateEx(BOOL * pfNoRedraw, DWORD)
     {
+#ifdef __WXWINCE__
+        IRunnableObject* runnable = NULL;
+        HRESULT hr = QueryInterface(
+            IID_IRunnableObject, (void**)(& runnable));
+        if (SUCCEEDED(hr))
+        {
+            runnable->LockRunning(TRUE, FALSE);
+        }
+#else
         OleLockRunning(m_window->m_ActiveX, TRUE, FALSE);
+#endif
         if (pfNoRedraw)
             (*pfNoRedraw) = FALSE;
         return S_OK;
@@ -384,7 +461,17 @@ public:
 
     HRESULT STDMETHODCALLTYPE OnInPlaceDeactivateEx(BOOL)
     {
+#ifdef __WXWINCE__
+        IRunnableObject* runnable = NULL;
+        HRESULT hr = QueryInterface(
+            IID_IRunnableObject, (void**)(& runnable));
+        if (SUCCEEDED(hr))
+        {
+            runnable->LockRunning(FALSE, FALSE);
+        }
+#else
         OleLockRunning(m_window->m_ActiveX, FALSE, FALSE);
+#endif
         return S_OK;
     }
     STDMETHOD(RequestUIActivate)(){ return S_OK;}
@@ -438,7 +525,7 @@ public:
     HRESULT STDMETHODCALLTYPE LockContainer(BOOL){return S_OK;}
     //********************IOleItemContainer***************************
     HRESULT STDMETHODCALLTYPE
-    #if defined(__WXWINCE__)
+    #if 0 // defined(__WXWINCE__) && __VISUALC__ < 1400
     GetObject
     #elif defined(_UNICODE)
     GetObjectW
@@ -584,7 +671,132 @@ DEFINE_OLE_TABLE(FrameSite)
 END_OLE_TABLE
 
 
-wxActiveXContainer::wxActiveXContainer(wxWindow * parent, REFIID iid, IUnknown* pUnk)
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// wxActiveXEvents
+//
+// Handles and sends activex events received from the ActiveX control
+// to the appropriate wxEvtHandler
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+class wxActiveXEvents : public IDispatch
+{
+private:
+    DECLARE_OLE_UNKNOWN(wxActiveXEvents);
+
+
+    wxActiveXContainer *m_activeX;
+    IID m_customId;
+    bool m_haveCustomId;
+
+    friend bool wxActiveXEventsInterface(wxActiveXEvents *self, REFIID iid, void **_interface, const char *&desc);
+
+public:
+    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()
+    {
+    }
+
+    // IDispatch
+    STDMETHODIMP GetIDsOfNames(REFIID, OLECHAR**, unsigned int, LCID, DISPID*)
+    {
+        return E_NOTIMPL;
+    }
+
+    STDMETHODIMP GetTypeInfo(unsigned int, LCID, ITypeInfo**)
+    {
+        return E_NOTIMPL;
+    }
+
+    STDMETHODIMP GetTypeInfoCount(unsigned int*)
+    {
+        return E_NOTIMPL;
+    }
+
+
+    STDMETHODIMP Invoke(DISPID dispIdMember, REFIID WXUNUSED(riid),
+                        LCID WXUNUSED(lcid),
+                          WORD wFlags, DISPPARAMS * pDispParams,
+                          VARIANT * WXUNUSED(pVarResult), EXCEPINFO * WXUNUSED(pExcepInfo),
+                          unsigned int * WXUNUSED(puArgErr))
+    {
+        if (wFlags & (DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
+            return E_NOTIMPL;
+
+        wxASSERT(m_activeX);
+
+        // ActiveX Event
+
+        // Dispatch Event
+        wxActiveXEvent  event;
+        event.SetEventType(wxEVT_ACTIVEX);
+        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;
+
+//                        vx.SetName(px.name);
+                wxConvertOleToVariant(va, vx);
+                event.m_params.Append(vx);
+            }
+        }
+
+        // process the events from the activex method
+           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);
+        }
+
+        if(event.GetSkipped())
+            return DISP_E_MEMBERNOTFOUND;
+
+        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
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// wxActiveXContainer
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+//---------------------------------------------------------------------------
+// wxActiveXContainer Constructor
+//
+// Initializes members and creates the native ActiveX container
+//---------------------------------------------------------------------------
+wxActiveXContainer::wxActiveXContainer(wxWindow * parent,
+                                       REFIID iid, IUnknown* pUnk)
     : m_realparent(parent)
 {
     m_bAmbientUserMode = true;
@@ -592,6 +804,12 @@ wxActiveXContainer::wxActiveXContainer(wxWindow * parent, REFIID iid, IUnknown*
     CreateActiveX(iid, pUnk);
 }
 
+//---------------------------------------------------------------------------
+// wxActiveXContainer Destructor
+//
+// Destroys members (the FrameSite et al. are destroyed implicitly
+// through COM ref counting)
+//---------------------------------------------------------------------------
 wxActiveXContainer::~wxActiveXContainer()
 {
     // disconnect connection points
@@ -613,6 +831,14 @@ wxActiveXContainer::~wxActiveXContainer()
     }
 }
 
+//---------------------------------------------------------------------------
+// wxActiveXContainer::CreateActiveX
+//
+// Actually creates the ActiveX container through the FrameSite
+// and sets up ActiveX events
+//
+// TODO: Document this more
+//---------------------------------------------------------------------------
 void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
 {
     HRESULT hret;
@@ -632,6 +858,105 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
     // Get Dispatch interface
     hret = m_Dispatch.QueryInterface(IID_IDispatch, m_ActiveX);
 
+    //
+    // SETUP TYPEINFO AND ACTIVEX EVENTS
+    //
+
+    // get type info via class info
+    wxAutoIProvideClassInfo classInfo(IID_IProvideClassInfo, m_ActiveX);
+    wxASSERT(classInfo.Ok());
+
+    // type info
+    wxAutoITypeInfo typeInfo;
+    hret = classInfo->GetClassInfo(typeInfo.GetRef());
+    wxASSERT(typeInfo.Ok());
+
+    // TYPEATTR
+    TYPEATTR *ta = NULL;
+    hret = typeInfo->GetTypeAttr(&ta);
+    wxASSERT(ta);
+
+    // 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
+        wxAutoITypeInfo  ti;
+        hret = typeInfo->GetRefTypeInfo(rt, ti.GetRef());
+        if (! ti.Ok())
+            continue;
+
+        // check if default event sink
+        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;
+                    wxFAIL_MSG(wxT("Default event sink is in vtable!"));
+                }
+            }
+        }
+
+
+        // wxAutoOleInterface<> assumes a ref has already been added
+        // TYPEATTR
+        TYPEATTR *ta = NULL;
+        hret = ti->GetTypeAttr(&ta);
+        wxASSERT(ta);
+
+        if (ta->typekind == TKIND_DISPATCH)
+        {
+            // WXOLE_TRACEOUT("GUID = " << GetIIDName(ta->guid).c_str());
+            if (defEventSink)
+            {
+                wxAutoIConnectionPoint    cp;
+                DWORD                    adviseCookie = 0;
+
+                wxAutoIConnectionPointContainer cpContainer(IID_IConnectionPointContainer, m_ActiveX);
+                wxASSERT( cpContainer.Ok());
+
+                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)
+                            );
+            }
+        }
+
+        ti->ReleaseTypeAttr(ta);
+    }
+
+    // free
+    typeInfo->ReleaseTypeAttr(ta);
+
+    //
+    // END
+    //
+
     // Get IOleObject interface
     hret = m_oleObject.QueryInterface(IID_IOleObject, m_ActiveX);
     wxASSERT(SUCCEEDED(hret));
@@ -643,6 +968,8 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
     // document advise
     m_docAdviseCookie = 0;
     hret = m_oleObject->Advise(adviseSink, &m_docAdviseCookie);
+    // TODO:Needed?
+//    hret = m_viewObject->SetAdvise(DVASPECT_CONTENT, 0, adviseSink);
     m_oleObject->SetHostNames(L"wxActiveXContainer", NULL);
     OleSetContainedObject(m_oleObject, TRUE);
     OleRun(m_oleObject);
@@ -711,10 +1038,7 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
         ::SetActiveWindow(m_oleObjectHWND);
         ::ShowWindow(m_oleObjectHWND, SW_SHOW);
 
-        {
-            wxLogNull  noLog;
-            this->AssociateHandle(m_oleObjectHWND);
-        }
+        this->AssociateHandle(m_oleObjectHWND);
         this->Reparent(m_realparent);
 
         wxWindow* pWnd = m_realparent;
@@ -722,6 +1046,8 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
 
         pWnd->Connect(id, wxEVT_SIZE,
             wxSizeEventHandler(wxActiveXContainer::OnSize), 0, this);
+//        this->Connect(GetId(), wxEVT_PAINT,
+//            wxPaintEventHandler(wxActiveXContainer::OnPaint), 0, this);
         pWnd->Connect(id, wxEVT_SET_FOCUS,
             wxFocusEventHandler(wxActiveXContainer::OnSetFocus), 0, this);
         pWnd->Connect(id, wxEVT_KILL_FOCUS,
@@ -729,34 +1055,12 @@ void wxActiveXContainer::CreateActiveX(REFIID iid, IUnknown* pUnk)
     }
 }
 
-#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)   wxMulDivInt32(HIMETRIC_INCH, (x), (logpixels))
-
-    sz.cx = CONVERT(sz.cx, logX);
-    sz.cy = CONVERT(sz.cy, logY);
-
-#undef CONVERT
-#undef HIMETRIC_INCH
-}
-
-
+//---------------------------------------------------------------------------
+// wxActiveXContainer::OnSize
+//
+// Called when the parent is resized - we need to do this to actually
+// move the ActiveX control to where the parent is
+//---------------------------------------------------------------------------
 void wxActiveXContainer::OnSize(wxSizeEvent& event)
 {
     int w, h;
@@ -774,6 +1078,9 @@ void wxActiveXContainer::OnSize(wxSizeEvent& event)
     // extents are in HIMETRIC units
     if (m_oleObject.Ok())
     {
+        m_oleObject->DoVerb(OLEIVERB_HIDE, 0, m_clientSite, 0,
+            (HWND)m_realparent->GetHWND(), &posRect);
+
         SIZEL sz = {w, h};
         PixelsToHimetric(sz);
 
@@ -782,7 +1089,10 @@ void wxActiveXContainer::OnSize(wxSizeEvent& event)
         m_oleObject->GetExtent(DVASPECT_CONTENT, &sz2);
         if (sz2.cx !=  sz.cx || sz.cy != sz2.cy)
             m_oleObject->SetExtent(DVASPECT_CONTENT, &sz);
-    };
+
+        m_oleObject->DoVerb(OLEIVERB_SHOW, 0, m_clientSite, 0,
+            (HWND)m_realparent->GetHWND(), &posRect);
+    }
 
     if (m_oleInPlaceObject.Ok())
         m_oleInPlaceObject->SetObjectRects(&posRect, &posRect);
@@ -790,13 +1100,17 @@ void wxActiveXContainer::OnSize(wxSizeEvent& event)
     event.Skip();
 }
 
+//---------------------------------------------------------------------------
+// wxActiveXContainer::OnPaint
+//
+// Called when the parent is resized - repaints the ActiveX control
+//---------------------------------------------------------------------------
 void wxActiveXContainer::OnPaint(wxPaintEvent& WXUNUSED(event))
 {
     wxPaintDC dc(this);
     // Draw only when control is windowless or deactivated
     if (m_viewObject)
     {
-        dc.BeginDrawing();
         int w, h;
         GetParent()->GetSize(&w, &h);
         RECT posRect;
@@ -805,22 +1119,23 @@ void wxActiveXContainer::OnPaint(wxPaintEvent& WXUNUSED(event))
         posRect.right = w;
         posRect.bottom = h;
 
-#if defined(_WIN32_WCE) && _WIN32_WCE < 400
-        ::InvalidateRect(m_oleObjectHWND, NULL, false);
-#else
+#if !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
         ::RedrawWindow(m_oleObjectHWND, NULL, NULL, RDW_INTERNALPAINT);
+#else
+        ::InvalidateRect(m_oleObjectHWND, NULL, false);
 #endif
         RECTL *prcBounds = (RECTL *) &posRect;
+        wxMSWDCImpl *msw = wxDynamicCast( dc.GetImpl() , wxMSWDCImpl );
         m_viewObject->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL,
-            (HDC)dc.GetHDC(), prcBounds, NULL, NULL, 0);
-
-        dc.EndDrawing();
+            (HDC)msw->GetHDC(), prcBounds, NULL, NULL, 0);
     }
-
-//  We've got this one I think
-//    event.Skip();
 }
 
+//---------------------------------------------------------------------------
+// wxActiveXContainer::OnSetFocus
+//
+// Called when the focus is set on the parent - activates the activex control
+//---------------------------------------------------------------------------
 void wxActiveXContainer::OnSetFocus(wxFocusEvent& event)
 {
     if (m_oleInPlaceActiveObject.Ok())
@@ -829,6 +1144,12 @@ void wxActiveXContainer::OnSetFocus(wxFocusEvent& event)
     event.Skip();
 }
 
+//---------------------------------------------------------------------------
+// wxActiveXContainer::OnKillFocus
+//
+// Called when the focus is killed on the parent -
+// deactivates the activex control
+//---------------------------------------------------------------------------
 void wxActiveXContainer::OnKillFocus(wxFocusEvent& event)
 {
     if (m_oleInPlaceActiveObject.Ok())
@@ -836,3 +1157,5 @@ void wxActiveXContainer::OnKillFocus(wxFocusEvent& event)
 
     event.Skip();
 }
+
+#endif // wxUSE_ACTIVEX