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 *****************************************************************************/
26 #include "connectioncontainer.h"
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
)
53 cd
.dwCookie
= i
->first
;
59 class VLCEnumConnections
: public VLCEnumIterator
<IID_IEnumConnections
,
62 map
<DWORD
,LPUNKNOWN
>::iterator
,
63 VLCEnumConnectionsDereference
>
66 VLCEnumConnections(map
<DWORD
,LPUNKNOWN
> &m
) :
67 VLCEnumIterator
<IID_IEnumConnections
,
70 map
<DWORD
,LPUNKNOWN
>::iterator
,
71 VLCEnumConnectionsDereference
> (m
.begin(), m
.end())
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
;
88 class VLCEnumConnectionPoints
: public VLCEnumIterator
<IID_IEnumConnectionPoints
,
89 IEnumConnectionPoints
,
91 vector
<LPCONNECTIONPOINT
>::iterator
,
92 VLCEnumConnectionPointsDereference
>
95 VLCEnumConnectionPoints(vector
<LPCONNECTIONPOINT
>& v
) :
96 VLCEnumIterator
<IID_IEnumConnectionPoints
,
97 IEnumConnectionPoints
,
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
)
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
);
134 static void ConditionSignal(HANDLE
*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
)
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
));
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
);
168 if (!pCPC
->isRunning
)
170 LeaveCriticalSection(&(pCPC
->csEvents
));
174 LeaveCriticalSection(&(pCPC
->csEvents
));
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();
203 m_pGIT
->RevokeInterfaceFromGlobal((DWORD
)iter
->second
);
209 STDMETHODIMP
VLCConnectionPoint::GetConnectionInterface(IID
*iid
)
218 STDMETHODIMP
VLCConnectionPoint::GetConnectionPointContainer(LPCONNECTIONPOINTCONTAINER
*ppCPC
)
228 STDMETHODIMP
VLCConnectionPoint::Advise(IUnknown
*pUnk
, DWORD
*pdwCookie
)
230 static DWORD dwCookieCounter
= 0;
233 if( (NULL
== pUnk
) || (NULL
== pdwCookie
) )
236 hr
= pUnk
->QueryInterface(_iid
, (LPVOID
*)&pUnk
);
240 hr
= m_pGIT
->RegisterInterfaceInGlobal( pUnk
, _iid
, &dwGITCookie
);
243 *pdwCookie
= ++dwCookieCounter
;
244 _connections
[*pdwCookie
] = (LPUNKNOWN
) dwGITCookie
;
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
);
260 return CONNECT_E_NOCONNECTION
;
263 STDMETHODIMP
VLCConnectionPoint::EnumConnections(IEnumConnections
**ppEnum
)
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();
282 DWORD dwCookie
= (DWORD
)iter
->second
;
285 hr
= m_pGIT
->GetInterfaceFromGlobal( dwCookie
, _iid
,
286 reinterpret_cast<void **>(&pUnk
) );
290 hr
= pUnk
->QueryInterface(_iid
, (LPVOID
*)&pDisp
);
293 pDisp
->Invoke(dispId
, IID_NULL
, LOCALE_USER_DEFAULT
,
294 DISPATCH_METHOD
, pDispParams
, NULL
, NULL
, NULL
);
303 void VLCConnectionPoint::firePropChangedEvent(DISPID dispId
)
305 map
<DWORD
,LPUNKNOWN
>::iterator end
= _connections
.end();
306 map
<DWORD
,LPUNKNOWN
>::iterator iter
= _connections
.begin();
313 hr
= m_pGIT
->GetInterfaceFromGlobal( (DWORD
)iter
->second
, IID_IUnknown
,
314 reinterpret_cast<void **>(&pUnk
) );
317 IPropertyNotifySink
*pPropSink
;
318 hr
= pUnk
->QueryInterface( IID_IPropertyNotifySink
, (LPVOID
*)&pPropSink
);
321 pPropSink
->OnChanged(dispId
);
322 pPropSink
->Release();
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
));
363 InitializeCriticalSection(&csEvents
);
364 ConditionInit(&sEvents
);
367 hThread
= CreateThread(NULL
, NULL
, ThreadProcEventHandler
,
368 dynamic_cast<LPVOID
>(this), NULL
, NULL
);
371 VLCConnectionPointContainer::~VLCConnectionPointContainer()
373 EnterCriticalSection(&csEvents
);
376 ConditionSignal(&sEvents
);
377 LeaveCriticalSection(&csEvents
);
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
);
388 while(!_q_events
.empty()) {
396 STDMETHODIMP
VLCConnectionPointContainer::EnumConnectionPoints(LPENUMCONNECTIONPOINTS
*ppEnum
)
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
)
413 if( IID_IPropertyNotifySink
== riid
)
416 *ppCP
= dynamic_cast<LPCONNECTIONPOINT
>(_p_props
);
418 else if( _p_instance
->getDispEventID() == riid
)
421 *ppCP
= dynamic_cast<LPCONNECTIONPOINT
>(_p_events
);
424 return CONNECT_E_NOCONNECTION
;
429 void VLCConnectionPointContainer::freezeEvents(BOOL bFreeze
)
431 EnterCriticalSection(&csEvents
);
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();
448 ConditionSignal(&sEvents
);
449 LeaveCriticalSection(&csEvents
);
452 void VLCConnectionPointContainer::firePropChangedEvent(DISPID dispId
)
455 _p_props
->firePropChangedEvent(dispId
);