Put size check before data dereference
[vlc/asuraparaju-public.git] / projects / activex / connectioncontainer.cpp
blob91fd0b6ce2a1bfe5154ae82ce75a49b7b3699124
1 /*****************************************************************************
2 * connectioncontainer.cpp: ActiveX control for VLC
3 *****************************************************************************
4 * Copyright (C) 2005 the VideoLAN team
5 * Copyright (C) 2010 M2X BV
7 * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
8 * Jean-Paul Saman <jpsaman@videolan.org>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 #include "plugin.h"
26 #include "connectioncontainer.h"
28 #include "utils.h"
30 #include <assert.h>
31 #include <rpc.h>
32 #include <rpcndr.h>
34 using namespace std;
36 ////////////////////////////////////////////////////////////////////////////////////////////////
37 DEFINE_GUID(IID_IGlobalInterfaceTable, 0x00000146, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
38 DEFINE_GUID(CLSID_StdGlobalInterfaceTable, 0x00000323, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
40 const GUID IID_IGlobalInterfaceTable = { 0x00000146, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
41 const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
42 ////////////////////////////////////////////////////////////////////////////////////////////////
44 /* this function object is used to return the value from a map pair */
45 struct VLCEnumConnectionsDereference
47 CONNECTDATA operator()(const map<DWORD,LPUNKNOWN>::iterator& i)
49 CONNECTDATA cd;
51 i->second->AddRef();
53 cd.dwCookie = i->first;
54 cd.pUnk = i->second;
55 return cd;
59 class VLCEnumConnections : public VLCEnumIterator<IID_IEnumConnections,
60 IEnumConnections,
61 CONNECTDATA,
62 map<DWORD,LPUNKNOWN>::iterator,
63 VLCEnumConnectionsDereference>
65 public:
66 VLCEnumConnections(map<DWORD,LPUNKNOWN> &m) :
67 VLCEnumIterator<IID_IEnumConnections,
68 IEnumConnections,
69 CONNECTDATA,
70 map<DWORD,LPUNKNOWN>::iterator,
71 VLCEnumConnectionsDereference> (m.begin(), m.end())
72 {};
75 ////////////////////////////////////////////////////////////////////////////////////////////////
77 /* this function object is used to retain the dereferenced iterator value */
78 struct VLCEnumConnectionPointsDereference
80 LPCONNECTIONPOINT operator()(const vector<LPCONNECTIONPOINT>::iterator& i)
82 LPCONNECTIONPOINT cp = *i;
83 cp->AddRef();
84 return cp;
88 class VLCEnumConnectionPoints: public VLCEnumIterator<IID_IEnumConnectionPoints,
89 IEnumConnectionPoints,
90 LPCONNECTIONPOINT,
91 vector<LPCONNECTIONPOINT>::iterator,
92 VLCEnumConnectionPointsDereference>
94 public:
95 VLCEnumConnectionPoints(vector<LPCONNECTIONPOINT>& v) :
96 VLCEnumIterator<IID_IEnumConnectionPoints,
97 IEnumConnectionPoints,
98 LPCONNECTIONPOINT,
99 vector<LPCONNECTIONPOINT>::iterator,
100 VLCEnumConnectionPointsDereference> (v.begin(), v.end())
104 ////////////////////////////////////////////////////////////////////////////////////////////////
105 // Condition variable emulation
106 ////////////////////////////////////////////////////////////////////////////////////////////////
108 static void ConditionInit(HANDLE *handle)
110 *handle = CreateEvent(NULL, TRUE, FALSE, NULL);
111 assert(*handle != NULL);
114 static void ConditionDestroy(HANDLE *handle)
116 CloseHandle(*handle);
119 static void ConditionWait(HANDLE *handle, CRITICAL_SECTION *lock)
121 DWORD dwWaitResult;
123 do {
124 LeaveCriticalSection(lock);
125 dwWaitResult = WaitForSingleObjectEx(*handle, INFINITE, TRUE);
126 EnterCriticalSection(lock);
127 } while(dwWaitResult == WAIT_IO_COMPLETION);
129 assert(dwWaitResult != WAIT_ABANDONED); /* another thread failed to cleanup! */
130 assert(dwWaitResult != WAIT_FAILED);
131 ResetEvent(*handle);
134 static void ConditionSignal(HANDLE *handle)
136 SetEvent(*handle);
139 ////////////////////////////////////////////////////////////////////////////////////////////////
140 // Event handling thread
142 // It bridges the gap between libvlc thread context and ActiveX/COM thread context.
143 ////////////////////////////////////////////////////////////////////////////////////////////////
144 DWORD WINAPI ThreadProcEventHandler(LPVOID lpParam)
146 CoInitialize(NULL);
147 VLCConnectionPointContainer *pCPC = (VLCConnectionPointContainer *)lpParam;
149 while(pCPC->isRunning)
151 EnterCriticalSection(&(pCPC->csEvents));
152 ConditionWait(&(pCPC->sEvents), &(pCPC->csEvents));
154 if (!pCPC->isRunning)
156 LeaveCriticalSection(&(pCPC->csEvents));
157 break;
160 while(!pCPC->_q_events.empty())
162 VLCDispatchEvent *ev = pCPC->_q_events.front();
163 pCPC->_q_events.pop();
164 pCPC->_p_events->fireEvent(ev->_dispId, &ev->_dispParams);
165 delete ev;
168 if (!pCPC->isRunning)
170 LeaveCriticalSection(&(pCPC->csEvents));
171 goto out;
174 LeaveCriticalSection(&(pCPC->csEvents));
176 out:
177 CoUninitialize();
178 return 0;
181 ////////////////////////////////////////////////////////////////////////////////////////////////
182 // VLCConnectionPoint
183 ////////////////////////////////////////////////////////////////////////////////////////////////
185 VLCConnectionPoint::VLCConnectionPoint(IConnectionPointContainer *p_cpc, REFIID iid) :
186 _iid(iid), _p_cpc(p_cpc)
188 // Get the Global Interface Table per-process singleton:
189 CoCreateInstance(CLSID_StdGlobalInterfaceTable, 0,
190 CLSCTX_INPROC_SERVER,
191 IID_IGlobalInterfaceTable,
192 reinterpret_cast<void**>(&m_pGIT));
195 VLCConnectionPoint::~VLCConnectionPoint()
197 // Revoke interfaces from the GIT:
198 map<DWORD,LPUNKNOWN>::iterator end = _connections.end();
199 map<DWORD,LPUNKNOWN>::iterator iter = _connections.begin();
201 while( iter != end )
203 m_pGIT->RevokeInterfaceFromGlobal((DWORD)iter->second);
204 ++iter;
206 m_pGIT->Release();
209 STDMETHODIMP VLCConnectionPoint::GetConnectionInterface(IID *iid)
211 if( NULL == iid )
212 return E_POINTER;
214 *iid = _iid;
215 return S_OK;
218 STDMETHODIMP VLCConnectionPoint::GetConnectionPointContainer(LPCONNECTIONPOINTCONTAINER *ppCPC)
220 if( NULL == ppCPC )
221 return E_POINTER;
223 _p_cpc->AddRef();
224 *ppCPC = _p_cpc;
225 return S_OK;
228 STDMETHODIMP VLCConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie)
230 static DWORD dwCookieCounter = 0;
231 HRESULT hr;
233 if( (NULL == pUnk) || (NULL == pdwCookie) )
234 return E_POINTER;
236 hr = pUnk->QueryInterface(_iid, (LPVOID *)&pUnk);
237 if( SUCCEEDED(hr) )
239 DWORD dwGITCookie;
240 hr = m_pGIT->RegisterInterfaceInGlobal( pUnk, _iid, &dwGITCookie );
241 if( SUCCEEDED(hr) )
243 *pdwCookie = ++dwCookieCounter;
244 _connections[*pdwCookie] = (LPUNKNOWN) dwGITCookie;
246 pUnk->Release();
248 return hr;
251 STDMETHODIMP VLCConnectionPoint::Unadvise(DWORD pdwCookie)
253 map<DWORD,LPUNKNOWN>::iterator pcd = _connections.find((DWORD)pdwCookie);
254 if( pcd != _connections.end() )
256 m_pGIT->RevokeInterfaceFromGlobal((DWORD)pcd->second);
257 _connections.erase(pdwCookie);
258 return S_OK;
260 return CONNECT_E_NOCONNECTION;
263 STDMETHODIMP VLCConnectionPoint::EnumConnections(IEnumConnections **ppEnum)
265 if( NULL == ppEnum )
266 return E_POINTER;
268 *ppEnum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(_connections));
270 return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
273 void VLCConnectionPoint::fireEvent(DISPID dispId, DISPPARAMS *pDispParams)
275 map<DWORD,LPUNKNOWN>::iterator end = _connections.end();
276 map<DWORD,LPUNKNOWN>::iterator iter = _connections.begin();
278 HRESULT hr = S_OK;
280 while( iter != end )
282 DWORD dwCookie = (DWORD)iter->second;
283 LPUNKNOWN pUnk;
285 hr = m_pGIT->GetInterfaceFromGlobal( dwCookie, _iid,
286 reinterpret_cast<void **>(&pUnk) );
287 if( SUCCEEDED(hr) )
289 IDispatch *pDisp;
290 hr = pUnk->QueryInterface(_iid, (LPVOID *)&pDisp);
291 if( SUCCEEDED(hr) )
293 pDisp->Invoke(dispId, IID_NULL, LOCALE_USER_DEFAULT,
294 DISPATCH_METHOD, pDispParams, NULL, NULL, NULL);
295 pDisp->Release();
297 pUnk->Release();
299 ++iter;
303 void VLCConnectionPoint::firePropChangedEvent(DISPID dispId)
305 map<DWORD,LPUNKNOWN>::iterator end = _connections.end();
306 map<DWORD,LPUNKNOWN>::iterator iter = _connections.begin();
308 while( iter != end )
310 LPUNKNOWN pUnk;
311 HRESULT hr;
313 hr = m_pGIT->GetInterfaceFromGlobal( (DWORD)iter->second, IID_IUnknown,
314 reinterpret_cast<void **>(&pUnk) );
315 if( SUCCEEDED(hr) )
317 IPropertyNotifySink *pPropSink;
318 hr = pUnk->QueryInterface( IID_IPropertyNotifySink, (LPVOID *)&pPropSink );
319 if( SUCCEEDED(hr) )
321 pPropSink->OnChanged(dispId);
322 pPropSink->Release();
324 pUnk->Release();
326 ++iter;
330 ////////////////////////////////////////////////////////////////////////////////////////////////
332 VLCDispatchEvent::~VLCDispatchEvent()
334 //clear event arguments
335 if( NULL != _dispParams.rgvarg )
337 for(unsigned int c = 0; c < _dispParams.cArgs; ++c)
338 VariantClear(_dispParams.rgvarg + c);
339 CoTaskMemFree(_dispParams.rgvarg);
341 if( NULL != _dispParams.rgdispidNamedArgs )
342 CoTaskMemFree(_dispParams.rgdispidNamedArgs);
345 ////////////////////////////////////////////////////////////////////////////////////////////////
346 // VLCConnectionPointContainer
347 ////////////////////////////////////////////////////////////////////////////////////////////////
349 VLCConnectionPointContainer::VLCConnectionPointContainer(VLCPlugin *p_instance) :
350 _p_instance(p_instance), freeze(FALSE), isRunning(TRUE)
352 _p_events = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
353 _p_instance->getDispEventID());
355 _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_events));
357 _p_props = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
358 IID_IPropertyNotifySink);
360 _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_props));
362 // init protection
363 InitializeCriticalSection(&csEvents);
364 ConditionInit(&sEvents);
366 // create thread
367 hThread = CreateThread(NULL, NULL, ThreadProcEventHandler,
368 dynamic_cast<LPVOID>(this), NULL, NULL);
371 VLCConnectionPointContainer::~VLCConnectionPointContainer()
373 EnterCriticalSection(&csEvents);
374 isRunning = FALSE;
375 freeze = TRUE;
376 ConditionSignal(&sEvents);
377 LeaveCriticalSection(&csEvents);
379 do {
380 /* nothing wait for thread to finish */;
381 } while(WaitForSingleObjectEx (hThread, INFINITE, TRUE) == WAIT_IO_COMPLETION);
382 CloseHandle(hThread);
384 ConditionDestroy(&sEvents);
385 DeleteCriticalSection(&csEvents);
387 _v_cps.clear();
388 while(!_q_events.empty()) {
389 _q_events.pop();
392 delete _p_props;
393 delete _p_events;
396 STDMETHODIMP VLCConnectionPointContainer::EnumConnectionPoints(LPENUMCONNECTIONPOINTS *ppEnum)
398 if( NULL == ppEnum )
399 return E_POINTER;
401 *ppEnum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(_v_cps));
403 return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
406 STDMETHODIMP VLCConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP)
408 if( NULL == ppCP )
409 return E_POINTER;
411 *ppCP = NULL;
413 if( IID_IPropertyNotifySink == riid )
415 _p_props->AddRef();
416 *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_props);
418 else if( _p_instance->getDispEventID() == riid )
420 _p_events->AddRef();
421 *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_events);
423 else
424 return CONNECT_E_NOCONNECTION;
426 return NOERROR;
429 void VLCConnectionPointContainer::freezeEvents(BOOL bFreeze)
431 EnterCriticalSection(&csEvents);
432 freeze = bFreeze;
433 LeaveCriticalSection(&csEvents);
436 void VLCConnectionPointContainer::fireEvent(DISPID dispId, DISPPARAMS* pDispParams)
438 EnterCriticalSection(&csEvents);
440 // queue event for later use when container is ready
441 _q_events.push(new VLCDispatchEvent(dispId, *pDispParams));
442 if( _q_events.size() > 1024 )
444 // too many events in queue, get rid of older one
445 delete _q_events.front();
446 _q_events.pop();
448 ConditionSignal(&sEvents);
449 LeaveCriticalSection(&csEvents);
452 void VLCConnectionPointContainer::firePropChangedEvent(DISPID dispId)
454 if( ! freeze )
455 _p_props->firePropChangedEvent(dispId);