-/*****************************************************************************\r
- * connectioncontainer.cpp: ActiveX control for VLC\r
- *****************************************************************************\r
- * Copyright (C) 2005 VideoLAN\r
- *\r
- * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>\r
- *\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.\r
- *****************************************************************************/\r
-\r
-#include "plugin.h"\r
-#include "connectioncontainer.h"\r
-\r
-#include "utils.h"\r
-\r
-using namespace std;\r
-\r
-////////////////////////////////////////////////////////////////////////////////////////////////\r
-\r
-class VLCEnumConnections : public IEnumConnections\r
-{\r
-public:\r
- VLCEnumConnections(vector<CONNECTDATA> &v) :\r
- e(VLCEnum<CONNECTDATA>(IID_IEnumConnections, v))\r
- { e.setRetainOperation((VLCEnum<CONNECTDATA>::retainer)&retain); };\r
-\r
- VLCEnumConnections(const VLCEnumConnections &vlcEnum) : e(vlcEnum.e) {};\r
-\r
- virtual ~VLCEnumConnections() {};\r
-\r
- // IUnknown methods\r
- STDMETHODIMP QueryInterface(REFIID riid, void **ppv)\r
- { return e.QueryInterface(riid, ppv); };\r
- STDMETHODIMP_(ULONG) AddRef(void)\r
- { return e.AddRef(); };\r
- STDMETHODIMP_(ULONG) Release(void)\r
- {return e.Release(); };\r
-\r
- //IEnumConnectionPoints\r
- STDMETHODIMP Next(ULONG celt, LPCONNECTDATA rgelt, ULONG *pceltFetched)\r
- { return e.Next(celt, rgelt, pceltFetched); };\r
- STDMETHODIMP Skip(ULONG celt)\r
- { return e.Skip(celt);};\r
- STDMETHODIMP Reset(void)\r
- { return e.Reset();};\r
- STDMETHODIMP Clone(LPENUMCONNECTIONS *ppenum)\r
- { if( NULL == ppenum ) return E_POINTER;\r
- *ppenum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(*this));\r
- return (NULL != *ppenum) ? S_OK : E_OUTOFMEMORY;\r
- };\r
-\r
-private:\r
-\r
- static void retain(CONNECTDATA cd)\r
- {\r
- cd.pUnk->AddRef();\r
- };\r
-\r
- VLCEnum<CONNECTDATA> e;\r
-};\r
-\r
-////////////////////////////////////////////////////////////////////////////////////////////////\r
-\r
-STDMETHODIMP VLCConnectionPoint::GetConnectionInterface(IID *iid)\r
-{\r
- if( NULL == iid )\r
- return E_POINTER;\r
-\r
- *iid = _iid;\r
- return S_OK;\r
-};\r
-\r
-STDMETHODIMP VLCConnectionPoint::GetConnectionPointContainer(LPCONNECTIONPOINTCONTAINER *ppCPC)\r
-{\r
- if( NULL == ppCPC )\r
- return E_POINTER;\r
-\r
- _p_cpc->AddRef();\r
- *ppCPC = _p_cpc;\r
- return S_OK;\r
-};\r
-\r
-STDMETHODIMP VLCConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie)\r
-{\r
- if( (NULL == pUnk) || (NULL == pdwCookie) )\r
- return E_POINTER;\r
-\r
- CONNECTDATA cd;\r
-\r
- pUnk->AddRef();\r
- cd.pUnk = pUnk;\r
- *pdwCookie = cd.dwCookie = _connections.size();\r
-\r
- _connections.push_back(cd);\r
-\r
- return S_OK;\r
-};\r
-\r
-STDMETHODIMP VLCConnectionPoint::Unadvise(DWORD pdwCookie)\r
-{\r
- if( pdwCookie < _connections.size() )\r
- {\r
- CONNECTDATA cd = _connections[pdwCookie];\r
- if( NULL != cd.pUnk )\r
- {\r
- cd.pUnk->Release();\r
- cd.pUnk = NULL;\r
- return S_OK;\r
- }\r
- }\r
- return CONNECT_E_NOCONNECTION;\r
-};\r
-\r
-STDMETHODIMP VLCConnectionPoint::EnumConnections(IEnumConnections **ppEnum)\r
-{\r
- if( NULL == ppEnum )\r
- return E_POINTER;\r
-\r
- *ppEnum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(_connections));\r
-\r
- return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;\r
-};\r
-\r
-void VLCConnectionPoint::fireEvent(DISPID dispId, LCID lcid, DISPPARAMS* pDispParams)\r
-{\r
- vector<CONNECTDATA>::iterator end = _connections.end();\r
- vector<CONNECTDATA>::iterator iter = _connections.begin();\r
-\r
- while( iter != end )\r
- {\r
- CONNECTDATA cd = *iter;\r
- if( NULL != cd.pUnk )\r
- {\r
- IDispatch *pDisp;\r
- if( SUCCEEDED(cd.pUnk->QueryInterface(IID_IDispatch, (LPVOID *)&pDisp)) )\r
- {\r
- unsigned int puArgErr;\r
- VARIANT vRes;\r
-\r
- if( SUCCEEDED(pDisp->Invoke(dispId, IID_NULL, lcid, DISPATCH_METHOD, pDispParams, &vRes, NULL, &puArgErr)) )\r
- {\r
- VariantClear(&vRes);\r
- }\r
- pDisp->Release();\r
- }\r
- }\r
- ++iter;\r
- }\r
-};\r
-\r
-void VLCConnectionPoint::firePropChangedEvent(DISPID dispId)\r
-{\r
- vector<CONNECTDATA>::iterator end = _connections.end();\r
- vector<CONNECTDATA>::iterator iter = _connections.begin();\r
-\r
- while( iter != end )\r
- {\r
- CONNECTDATA cd = *iter;\r
- if( NULL != cd.pUnk )\r
- {\r
- IPropertyNotifySink *pPropSink;\r
- if( SUCCEEDED(cd.pUnk->QueryInterface(IID_IPropertyNotifySink, (LPVOID *)&pPropSink)) )\r
- {\r
- pPropSink->OnChanged(dispId);\r
- pPropSink->Release();\r
- }\r
- }\r
- ++iter;\r
- }\r
-};\r
-\r
-////////////////////////////////////////////////////////////////////////////////////////////////\r
-\r
-class VLCEnumConnectionPoints : public IEnumConnectionPoints\r
-{\r
-public:\r
- VLCEnumConnectionPoints(vector<LPCONNECTIONPOINT> &v) :\r
- e(VLCEnum<LPCONNECTIONPOINT>(IID_IEnumConnectionPoints, v))\r
- { e.setRetainOperation((VLCEnum<LPCONNECTIONPOINT>::retainer)&retain); };\r
-\r
- VLCEnumConnectionPoints(const VLCEnumConnectionPoints &vlcEnum) : e(vlcEnum.e) {};\r
-\r
- virtual ~VLCEnumConnectionPoints() {};\r
-\r
- // IUnknown methods\r
- STDMETHODIMP QueryInterface(REFIID riid, void **ppv)\r
- { return e.QueryInterface(riid, ppv); };\r
- STDMETHODIMP_(ULONG) AddRef(void)\r
- { return e.AddRef(); };\r
- STDMETHODIMP_(ULONG) Release(void)\r
- {return e.Release(); };\r
-\r
- //IEnumConnectionPoints\r
- STDMETHODIMP Next(ULONG celt, LPCONNECTIONPOINT *rgelt, ULONG *pceltFetched)\r
- { return e.Next(celt, rgelt, pceltFetched); };\r
- STDMETHODIMP Skip(ULONG celt)\r
- { return e.Skip(celt);};\r
- STDMETHODIMP Reset(void)\r
- { return e.Reset();};\r
- STDMETHODIMP Clone(LPENUMCONNECTIONPOINTS *ppenum)\r
- { if( NULL == ppenum ) return E_POINTER;\r
- *ppenum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(*this));\r
- return (NULL != *ppenum) ? S_OK : E_OUTOFMEMORY;\r
- };\r
-\r
-private:\r
-\r
- static void retain(LPCONNECTIONPOINT cp)\r
- {\r
- cp->AddRef();\r
- };\r
-\r
- VLCEnum<LPCONNECTIONPOINT> e;\r
-};\r
-\r
-////////////////////////////////////////////////////////////////////////////////////////////////\r
-\r
-VLCConnectionPointContainer::VLCConnectionPointContainer(VLCPlugin *p_instance) :\r
- _p_instance(p_instance)\r
-{\r
- _p_events = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),\r
- _p_instance->getDispEventID());\r
-\r
- _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_events));\r
-\r
- _p_props = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),\r
- IID_IPropertyNotifySink);\r
-\r
- _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_props));\r
-};\r
-\r
-VLCConnectionPointContainer::~VLCConnectionPointContainer()\r
-{\r
- _v_cps.clear();\r
- delete _p_props;\r
- delete _p_events;\r
-};\r
-\r
-STDMETHODIMP VLCConnectionPointContainer::EnumConnectionPoints(LPENUMCONNECTIONPOINTS *ppEnum)\r
-{\r
- if( NULL == ppEnum )\r
- return E_POINTER;\r
-\r
- *ppEnum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(_v_cps));\r
-\r
- return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;\r
-};\r
-\r
-STDMETHODIMP VLCConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP)\r
-{\r
- if( NULL == ppCP )\r
- return E_POINTER;\r
-\r
- *ppCP = NULL;\r
-\r
- if( IID_IPropertyNotifySink == riid )\r
- {\r
- _p_props->AddRef();\r
- *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_props);\r
- }\r
- else if( _p_instance->getDispEventID() == riid )\r
- {\r
- _p_events->AddRef();\r
- *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_events);\r
- }\r
- else\r
- return CONNECT_E_NOCONNECTION;\r
-\r
- return NOERROR;\r
-};\r
-\r
-void VLCConnectionPointContainer::fireEvent(DISPID dispId, LCID lcid, DISPPARAMS* pDispParams)\r
-{\r
- _p_events->fireEvent(dispId,lcid, pDispParams);\r
-};\r
-\r
-void VLCConnectionPointContainer::firePropChangedEvent(DISPID dispId)\r
-{\r
- _p_props->firePropChangedEvent(dispId);\r
-};\r
-\r
+/*****************************************************************************
+ * connectioncontainer.cpp: ActiveX control for VLC
+ *****************************************************************************
+ * Copyright (C) 2005 the VideoLAN team
+ *
+ * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#include "plugin.h"
+#include "connectioncontainer.h"
+
+#include "utils.h"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+class VLCEnumConnections : public IEnumConnections
+{
+public:
+ VLCEnumConnections(vector<CONNECTDATA> &v) :
+ e(VLCEnum<CONNECTDATA>(IID_IEnumConnections, v))
+ { e.setRetainOperation((VLCEnum<CONNECTDATA>::retainer)&retain); };
+
+ VLCEnumConnections(const VLCEnumConnections &vlcEnum) : e(vlcEnum.e) {};
+
+ virtual ~VLCEnumConnections() {};
+
+ // IUnknown methods
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ { return e.QueryInterface(riid, ppv); };
+ STDMETHODIMP_(ULONG) AddRef(void)
+ { return e.AddRef(); };
+ STDMETHODIMP_(ULONG) Release(void)
+ {return e.Release(); };
+
+ //IEnumConnectionPoints
+ STDMETHODIMP Next(ULONG celt, LPCONNECTDATA rgelt, ULONG *pceltFetched)
+ { return e.Next(celt, rgelt, pceltFetched); };
+ STDMETHODIMP Skip(ULONG celt)
+ { return e.Skip(celt);};
+ STDMETHODIMP Reset(void)
+ { return e.Reset();};
+ STDMETHODIMP Clone(LPENUMCONNECTIONS *ppenum)
+ { if( NULL == ppenum ) return E_POINTER;
+ *ppenum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(*this));
+ return (NULL != *ppenum) ? S_OK : E_OUTOFMEMORY;
+ };
+
+private:
+
+ static void retain(CONNECTDATA cd)
+ {
+ cd.pUnk->AddRef();
+ };
+
+ VLCEnum<CONNECTDATA> e;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+STDMETHODIMP VLCConnectionPoint::GetConnectionInterface(IID *iid)
+{
+ if( NULL == iid )
+ return E_POINTER;
+
+ *iid = _iid;
+ return S_OK;
+};
+
+STDMETHODIMP VLCConnectionPoint::GetConnectionPointContainer(LPCONNECTIONPOINTCONTAINER *ppCPC)
+{
+ if( NULL == ppCPC )
+ return E_POINTER;
+
+ _p_cpc->AddRef();
+ *ppCPC = _p_cpc;
+ return S_OK;
+};
+
+STDMETHODIMP VLCConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie)
+{
+ if( (NULL == pUnk) || (NULL == pdwCookie) )
+ return E_POINTER;
+
+ CONNECTDATA cd;
+
+ pUnk->AddRef();
+ cd.pUnk = pUnk;
+ *pdwCookie = cd.dwCookie = _connections.size();
+
+ _connections.push_back(cd);
+
+ return S_OK;
+};
+
+STDMETHODIMP VLCConnectionPoint::Unadvise(DWORD pdwCookie)
+{
+ if( pdwCookie < _connections.size() )
+ {
+ CONNECTDATA cd = _connections[pdwCookie];
+ if( NULL != cd.pUnk )
+ {
+ cd.pUnk->Release();
+ cd.pUnk = NULL;
+ return S_OK;
+ }
+ }
+ return CONNECT_E_NOCONNECTION;
+};
+
+STDMETHODIMP VLCConnectionPoint::EnumConnections(IEnumConnections **ppEnum)
+{
+ if( NULL == ppEnum )
+ return E_POINTER;
+
+ *ppEnum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(_connections));
+
+ return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
+};
+
+void VLCConnectionPoint::fireEvent(DISPID dispId, DISPPARAMS *pDispParams)
+{
+ vector<CONNECTDATA>::iterator end = _connections.end();
+ vector<CONNECTDATA>::iterator iter = _connections.begin();
+
+ while( iter != end )
+ {
+ CONNECTDATA cd = *iter;
+ if( NULL != cd.pUnk )
+ {
+ IDispatch *pDisp;
+ if( SUCCEEDED(cd.pUnk->QueryInterface(IID_IDispatch, (LPVOID *)&pDisp)) )
+ {
+ pDisp->Invoke(dispId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, pDispParams, NULL, NULL, NULL);
+ pDisp->Release();
+ }
+ }
+ ++iter;
+ }
+};
+
+void VLCConnectionPoint::firePropChangedEvent(DISPID dispId)
+{
+ vector<CONNECTDATA>::iterator end = _connections.end();
+ vector<CONNECTDATA>::iterator iter = _connections.begin();
+
+ while( iter != end )
+ {
+ CONNECTDATA cd = *iter;
+ if( NULL != cd.pUnk )
+ {
+ IPropertyNotifySink *pPropSink;
+ if( SUCCEEDED(cd.pUnk->QueryInterface(IID_IPropertyNotifySink, (LPVOID *)&pPropSink)) )
+ {
+ pPropSink->OnChanged(dispId);
+ pPropSink->Release();
+ }
+ }
+ ++iter;
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+class VLCEnumConnectionPoints : public IEnumConnectionPoints
+{
+public:
+ VLCEnumConnectionPoints(vector<LPCONNECTIONPOINT> &v) :
+ e(VLCEnum<LPCONNECTIONPOINT>(IID_IEnumConnectionPoints, v))
+ { e.setRetainOperation((VLCEnum<LPCONNECTIONPOINT>::retainer)&retain); };
+
+ VLCEnumConnectionPoints(const VLCEnumConnectionPoints &vlcEnum) : e(vlcEnum.e) {};
+
+ virtual ~VLCEnumConnectionPoints() {};
+
+ // IUnknown methods
+ STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
+ { return e.QueryInterface(riid, ppv); };
+ STDMETHODIMP_(ULONG) AddRef(void)
+ { return e.AddRef(); };
+ STDMETHODIMP_(ULONG) Release(void)
+ {return e.Release(); };
+
+ //IEnumConnectionPoints
+ STDMETHODIMP Next(ULONG celt, LPCONNECTIONPOINT *rgelt, ULONG *pceltFetched)
+ { return e.Next(celt, rgelt, pceltFetched); };
+ STDMETHODIMP Skip(ULONG celt)
+ { return e.Skip(celt);};
+ STDMETHODIMP Reset(void)
+ { return e.Reset();};
+ STDMETHODIMP Clone(LPENUMCONNECTIONPOINTS *ppenum)
+ { if( NULL == ppenum ) return E_POINTER;
+ *ppenum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(*this));
+ return (NULL != *ppenum) ? S_OK : E_OUTOFMEMORY;
+ };
+
+private:
+
+ static void retain(LPCONNECTIONPOINT cp)
+ {
+ cp->AddRef();
+ };
+
+ VLCEnum<LPCONNECTIONPOINT> e;
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+VLCDispatchEvent::~VLCDispatchEvent()
+{
+ //clear event arguments
+ if( NULL != _dispParams.rgvarg )
+ {
+ for(unsigned int c=0; c<_dispParams.cArgs; ++c)
+ VariantClear(_dispParams.rgvarg+c);
+ CoTaskMemFree(_dispParams.rgvarg);
+ }
+ if( NULL != _dispParams.rgdispidNamedArgs )
+ CoTaskMemFree(_dispParams.rgdispidNamedArgs);
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+VLCConnectionPointContainer::VLCConnectionPointContainer(VLCPlugin *p_instance) :
+ _p_instance(p_instance), _b_freeze(FALSE)
+{
+ _p_events = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
+ _p_instance->getDispEventID());
+
+ _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_events));
+
+ _p_props = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
+ IID_IPropertyNotifySink);
+
+ _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_props));
+};
+
+VLCConnectionPointContainer::~VLCConnectionPointContainer()
+{
+ delete _p_props;
+ delete _p_events;
+};
+
+STDMETHODIMP VLCConnectionPointContainer::EnumConnectionPoints(LPENUMCONNECTIONPOINTS *ppEnum)
+{
+ if( NULL == ppEnum )
+ return E_POINTER;
+
+ *ppEnum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(_v_cps));
+
+ return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
+};
+
+STDMETHODIMP VLCConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP)
+{
+ if( NULL == ppCP )
+ return E_POINTER;
+
+ *ppCP = NULL;
+
+ if( IID_IPropertyNotifySink == riid )
+ {
+ _p_props->AddRef();
+ *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_props);
+ }
+ else if( _p_instance->getDispEventID() == riid )
+ {
+ _p_events->AddRef();
+ *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_events);
+ }
+ else
+ return CONNECT_E_NOCONNECTION;
+
+ return NOERROR;
+};
+
+void VLCConnectionPointContainer::freezeEvents(BOOL freeze)
+{
+ if( ! freeze )
+ {
+ // release queued events
+ while( ! _q_events.empty() )
+ {
+ VLCDispatchEvent *ev = _q_events.front();
+ _q_events.pop();
+ _p_events->fireEvent(ev->_dispId, &ev->_dispParams);
+ delete ev;
+ }
+ }
+ _b_freeze = freeze;
+};
+
+void VLCConnectionPointContainer::fireEvent(DISPID dispId, DISPPARAMS* pDispParams)
+{
+ if( _b_freeze )
+ {
+ // queue event for later use when container is ready
+ _q_events.push(new VLCDispatchEvent(dispId, *pDispParams));
+ if( _q_events.size() > 10 )
+ {
+ // too many events in queue, get rid of older one
+ delete _q_events.front();
+ _q_events.pop();
+ }
+ }
+ else
+ {
+ _p_events->fireEvent(dispId, pDispParams);
+ }
+};
+
+void VLCConnectionPointContainer::firePropChangedEvent(DISPID dispId)
+{
+ if( ! _b_freeze )
+ _p_props->firePropChangedEvent(dispId);
+};
+