]> git.sesse.net Git - vlc/blob - activex/connectioncontainer.cpp
FSF address change.
[vlc] / activex / connectioncontainer.cpp
1 /*****************************************************************************
2  * connectioncontainer.cpp: ActiveX control for VLC
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  *
6  * Authors: Damien Fouilleul <Damien.Fouilleul@laposte.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #include "plugin.h"
24 #include "connectioncontainer.h"
25
26 #include "utils.h"
27
28 using namespace std;
29
30 ////////////////////////////////////////////////////////////////////////////////////////////////
31
32 class VLCEnumConnections : public IEnumConnections
33 {
34 public:
35     VLCEnumConnections(vector<CONNECTDATA> &v) :
36         e(VLCEnum<CONNECTDATA>(IID_IEnumConnections, v))
37     { e.setRetainOperation((VLCEnum<CONNECTDATA>::retainer)&retain); };
38
39     VLCEnumConnections(const VLCEnumConnections &vlcEnum) : e(vlcEnum.e) {};
40
41     virtual ~VLCEnumConnections() {};
42
43     // IUnknown methods
44     STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
45         { return e.QueryInterface(riid, ppv); };
46     STDMETHODIMP_(ULONG) AddRef(void)
47         { return e.AddRef(); };
48     STDMETHODIMP_(ULONG) Release(void)
49         {return e.Release(); };
50
51     //IEnumConnectionPoints
52     STDMETHODIMP Next(ULONG celt, LPCONNECTDATA rgelt, ULONG *pceltFetched)
53         { return e.Next(celt, rgelt, pceltFetched); };
54     STDMETHODIMP Skip(ULONG celt)
55         { return e.Skip(celt);};
56     STDMETHODIMP Reset(void)
57         { return e.Reset();};
58     STDMETHODIMP Clone(LPENUMCONNECTIONS *ppenum)
59         { if( NULL == ppenum ) return E_POINTER;
60           *ppenum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(*this));
61           return (NULL != *ppenum) ? S_OK : E_OUTOFMEMORY;
62         };
63
64 private:
65
66     static void retain(CONNECTDATA cd)
67     {
68         cd.pUnk->AddRef();
69     };
70
71     VLCEnum<CONNECTDATA> e;
72 };
73
74 ////////////////////////////////////////////////////////////////////////////////////////////////
75
76 STDMETHODIMP VLCConnectionPoint::GetConnectionInterface(IID *iid)
77 {
78     if( NULL == iid )
79         return E_POINTER;
80
81     *iid = _iid;
82     return S_OK;
83 };
84
85 STDMETHODIMP VLCConnectionPoint::GetConnectionPointContainer(LPCONNECTIONPOINTCONTAINER *ppCPC)
86 {
87     if( NULL == ppCPC )
88         return E_POINTER;
89
90     _p_cpc->AddRef();
91     *ppCPC = _p_cpc;
92     return S_OK;
93 };
94
95 STDMETHODIMP VLCConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie)
96 {
97     if( (NULL == pUnk) || (NULL == pdwCookie) )
98         return E_POINTER;
99
100     CONNECTDATA cd;
101
102     pUnk->AddRef();
103     cd.pUnk = pUnk;
104     *pdwCookie = cd.dwCookie = _connections.size();
105
106     _connections.push_back(cd);
107
108     return S_OK;
109 };
110
111 STDMETHODIMP VLCConnectionPoint::Unadvise(DWORD pdwCookie)
112 {
113     if( pdwCookie < _connections.size() )
114     {
115         CONNECTDATA cd = _connections[pdwCookie];
116         if( NULL != cd.pUnk )
117         {
118             cd.pUnk->Release();
119             cd.pUnk = NULL;
120             return S_OK;
121         }
122     }
123     return CONNECT_E_NOCONNECTION;
124 };
125
126 STDMETHODIMP VLCConnectionPoint::EnumConnections(IEnumConnections **ppEnum)
127 {
128     if( NULL == ppEnum )
129         return E_POINTER;
130
131     *ppEnum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(_connections));
132
133     return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
134 };
135
136 void VLCConnectionPoint::fireEvent(DISPID dispId, DISPPARAMS *pDispParams)
137 {
138     vector<CONNECTDATA>::iterator end = _connections.end();
139     vector<CONNECTDATA>::iterator iter = _connections.begin();
140
141     while( iter != end )
142     {
143         CONNECTDATA cd = *iter;
144         if( NULL != cd.pUnk )
145         {
146             IDispatch *pDisp;
147             if( SUCCEEDED(cd.pUnk->QueryInterface(IID_IDispatch, (LPVOID *)&pDisp)) )
148             {
149                 pDisp->Invoke(dispId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, pDispParams, NULL, NULL, NULL);
150                 pDisp->Release();
151             }
152         }
153         ++iter;
154     }
155 };
156
157 void VLCConnectionPoint::firePropChangedEvent(DISPID dispId)
158 {
159     vector<CONNECTDATA>::iterator end = _connections.end();
160     vector<CONNECTDATA>::iterator iter = _connections.begin();
161
162     while( iter != end )
163     {
164         CONNECTDATA cd = *iter;
165         if( NULL != cd.pUnk )
166         {
167             IPropertyNotifySink *pPropSink;
168             if( SUCCEEDED(cd.pUnk->QueryInterface(IID_IPropertyNotifySink, (LPVOID *)&pPropSink)) )
169             {
170                 pPropSink->OnChanged(dispId);
171                 pPropSink->Release();
172             }
173         }
174         ++iter;
175     }
176 };
177
178 ////////////////////////////////////////////////////////////////////////////////////////////////
179
180 class VLCEnumConnectionPoints : public IEnumConnectionPoints
181 {
182 public:
183     VLCEnumConnectionPoints(vector<LPCONNECTIONPOINT> &v) :
184         e(VLCEnum<LPCONNECTIONPOINT>(IID_IEnumConnectionPoints, v))
185     { e.setRetainOperation((VLCEnum<LPCONNECTIONPOINT>::retainer)&retain); };
186
187     VLCEnumConnectionPoints(const VLCEnumConnectionPoints &vlcEnum) : e(vlcEnum.e) {};
188
189     virtual ~VLCEnumConnectionPoints() {};
190
191     // IUnknown methods
192     STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
193         { return e.QueryInterface(riid, ppv); };
194     STDMETHODIMP_(ULONG) AddRef(void)
195         { return e.AddRef(); };
196     STDMETHODIMP_(ULONG) Release(void)
197         {return e.Release(); };
198
199     //IEnumConnectionPoints
200     STDMETHODIMP Next(ULONG celt, LPCONNECTIONPOINT *rgelt, ULONG *pceltFetched)
201         { return e.Next(celt, rgelt, pceltFetched); };
202     STDMETHODIMP Skip(ULONG celt)
203         { return e.Skip(celt);};
204     STDMETHODIMP Reset(void)
205         { return e.Reset();};
206     STDMETHODIMP Clone(LPENUMCONNECTIONPOINTS *ppenum)
207         { if( NULL == ppenum ) return E_POINTER;
208           *ppenum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(*this));
209           return (NULL != *ppenum) ? S_OK : E_OUTOFMEMORY;
210         };
211
212 private:
213
214     static void retain(LPCONNECTIONPOINT cp)
215     {
216         cp->AddRef();
217     };
218
219     VLCEnum<LPCONNECTIONPOINT> e;
220 };
221
222 ////////////////////////////////////////////////////////////////////////////////////////////////
223
224 VLCDispatchEvent::~VLCDispatchEvent()
225 {
226     //clear event arguments
227     if( NULL != _dispParams.rgvarg )
228     {
229         for(unsigned int c=0; c<_dispParams.cArgs; ++c)
230             VariantClear(_dispParams.rgvarg+c);
231         CoTaskMemFree(_dispParams.rgvarg);
232     }
233     if( NULL != _dispParams.rgdispidNamedArgs )
234         CoTaskMemFree(_dispParams.rgdispidNamedArgs);
235 };
236
237 ////////////////////////////////////////////////////////////////////////////////////////////////
238
239 VLCConnectionPointContainer::VLCConnectionPointContainer(VLCPlugin *p_instance) :
240     _p_instance(p_instance), _b_freeze(FALSE)
241 {
242     _p_events = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
243             _p_instance->getDispEventID());
244
245     _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_events));
246
247     _p_props = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
248             IID_IPropertyNotifySink);
249
250     _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_props));
251 };
252
253 VLCConnectionPointContainer::~VLCConnectionPointContainer()
254 {
255     delete _p_props;
256     delete _p_events;
257 };
258
259 STDMETHODIMP VLCConnectionPointContainer::EnumConnectionPoints(LPENUMCONNECTIONPOINTS *ppEnum)
260 {
261     if( NULL == ppEnum )
262         return E_POINTER;
263
264     *ppEnum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(_v_cps));
265
266     return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
267 };
268
269 STDMETHODIMP VLCConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP)
270 {
271     if( NULL == ppCP )
272         return E_POINTER;
273
274     *ppCP = NULL;
275
276     if( IID_IPropertyNotifySink == riid )
277     {
278         _p_props->AddRef();
279         *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_props);
280     }
281     else if( _p_instance->getDispEventID() == riid )
282     {
283         _p_events->AddRef();
284         *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_events);
285     }
286     else
287         return CONNECT_E_NOCONNECTION;
288
289     return NOERROR;
290 };
291
292 void VLCConnectionPointContainer::freezeEvents(BOOL freeze)
293 {
294     if( ! freeze )
295     {
296         // release queued events
297         while( ! _q_events.empty() )
298         {
299             VLCDispatchEvent *ev = _q_events.front();
300             _q_events.pop();
301             _p_events->fireEvent(ev->_dispId, &ev->_dispParams);
302             delete ev;
303         }
304     }
305     _b_freeze = freeze;
306 };
307
308 void VLCConnectionPointContainer::fireEvent(DISPID dispId, DISPPARAMS* pDispParams)
309 {
310     if( _b_freeze )
311     {
312         // queue event for later use when container is ready
313         _q_events.push(new VLCDispatchEvent(dispId, *pDispParams));
314         if( _q_events.size() > 10 )
315         {
316             // too many events in queue, get rid of older one
317             delete _q_events.front();
318             _q_events.pop();
319         }
320     }
321     else
322     {
323         _p_events->fireEvent(dispId, pDispParams);
324     }
325 };
326
327 void VLCConnectionPointContainer::firePropChangedEvent(DISPID dispId)
328 {
329     if( ! _b_freeze )
330         _p_props->firePropChangedEvent(dispId);
331 };
332