]> git.sesse.net Git - vlc/blob - activex/connectioncontainer.cpp
* destroy some mutex'es once in a while to prevent memleaks. Suggested by a forumuser...
[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 /* this function object is used to return the value from a map pair */
33 struct VLCEnumConnectionsDereference
34 {
35     CONNECTDATA operator()(const map<DWORD,LPUNKNOWN>::iterator& i)
36     {
37         CONNECTDATA cd;
38         
39         cd.dwCookie = i->first;
40         cd.pUnk     = i->second;
41         return cd;
42     };
43 };
44
45 class VLCEnumConnections : public VLCEnumIterator<IID_IEnumConnections,
46     IEnumConnections,
47     CONNECTDATA,
48     map<DWORD,LPUNKNOWN>::iterator,
49     VLCEnumConnectionsDereference>
50 {
51 public:
52     VLCEnumConnections(map<DWORD,LPUNKNOWN> &m) :
53         VLCEnumIterator<IID_IEnumConnections,
54             IEnumConnections,
55             CONNECTDATA,
56             map<DWORD,LPUNKNOWN>::iterator,
57             VLCEnumConnectionsDereference> (m.begin(), m.end())
58     {};
59 };
60
61 ////////////////////////////////////////////////////////////////////////////////////////////////
62
63 /* this function object is used to retain the dereferenced iterator value */
64 struct VLCEnumConnectionPointsDereference
65 {
66     LPCONNECTIONPOINT operator()(const vector<LPCONNECTIONPOINT>::iterator& i)
67     {
68         LPCONNECTIONPOINT cp = *i;
69         cp->AddRef();
70         return cp;
71     }
72 };
73
74 class VLCEnumConnectionPoints: public VLCEnumIterator<IID_IEnumConnectionPoints,
75     IEnumConnectionPoints,
76     LPCONNECTIONPOINT,
77     vector<LPCONNECTIONPOINT>::iterator,
78     VLCEnumConnectionPointsDereference>
79 {
80 public:
81     VLCEnumConnectionPoints(vector<LPCONNECTIONPOINT>& v) :
82         VLCEnumIterator<IID_IEnumConnectionPoints,
83             IEnumConnectionPoints,
84             LPCONNECTIONPOINT,
85             vector<LPCONNECTIONPOINT>::iterator,
86             VLCEnumConnectionPointsDereference> (v.begin(), v.end())
87     {};
88 };
89
90 ////////////////////////////////////////////////////////////////////////////////////////////////
91
92 STDMETHODIMP VLCConnectionPoint::GetConnectionInterface(IID *iid)
93 {
94     if( NULL == iid )
95         return E_POINTER;
96
97     *iid = _iid;
98     return S_OK;
99 };
100
101 STDMETHODIMP VLCConnectionPoint::GetConnectionPointContainer(LPCONNECTIONPOINTCONTAINER *ppCPC)
102 {
103     if( NULL == ppCPC )
104         return E_POINTER;
105
106     _p_cpc->AddRef();
107     *ppCPC = _p_cpc;
108     return S_OK;
109 };
110
111 STDMETHODIMP VLCConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie)
112 {
113     static DWORD dwCookieCounter = 0;
114
115     if( (NULL == pUnk) || (NULL == pdwCookie) )
116         return E_POINTER;
117
118     pUnk->AddRef();
119
120     *pdwCookie = ++dwCookieCounter;
121     _connections[*pdwCookie] = pUnk;
122
123     return S_OK;
124 };
125
126 STDMETHODIMP VLCConnectionPoint::Unadvise(DWORD pdwCookie)
127 {
128     map<DWORD,LPUNKNOWN>::iterator pcd = _connections.find((DWORD)pdwCookie);
129     if( pcd != _connections.end() )
130     {
131         pcd->second->Release();
132
133         _connections.erase(pdwCookie);
134         return S_OK;
135     }
136     return CONNECT_E_NOCONNECTION;
137 };
138
139 STDMETHODIMP VLCConnectionPoint::EnumConnections(IEnumConnections **ppEnum)
140 {
141     if( NULL == ppEnum )
142         return E_POINTER;
143
144     *ppEnum = dynamic_cast<LPENUMCONNECTIONS>(new VLCEnumConnections(_connections));
145
146     return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
147 };
148
149 void VLCConnectionPoint::fireEvent(DISPID dispId, DISPPARAMS *pDispParams)
150 {
151     map<DWORD,LPUNKNOWN>::iterator end = _connections.end();
152     map<DWORD,LPUNKNOWN>::iterator iter = _connections.begin();
153
154     while( iter != end )
155     {
156         LPUNKNOWN pUnk = iter->second;
157         if( NULL != pUnk )
158         {
159             IDispatch *pDisp;
160             if( SUCCEEDED(pUnk->QueryInterface(IID_IDispatch, (LPVOID *)&pDisp)) )
161             {
162                 pDisp->Invoke(dispId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, pDispParams, NULL, NULL, NULL);
163                 pDisp->Release();
164             }
165         }
166         ++iter;
167     }
168 };
169
170 void VLCConnectionPoint::firePropChangedEvent(DISPID dispId)
171 {
172     map<DWORD,LPUNKNOWN>::iterator end = _connections.end();
173     map<DWORD,LPUNKNOWN>::iterator iter = _connections.begin();
174
175     while( iter != end )
176     {
177         LPUNKNOWN pUnk = iter->second;
178         if( NULL != pUnk )
179         {
180             IPropertyNotifySink *pPropSink;
181             if( SUCCEEDED(pUnk->QueryInterface(IID_IPropertyNotifySink, (LPVOID *)&pPropSink)) )
182             {
183                 pPropSink->OnChanged(dispId);
184                 pPropSink->Release();
185             }
186         }
187         ++iter;
188     }
189 };
190
191 ////////////////////////////////////////////////////////////////////////////////////////////////
192
193 VLCDispatchEvent::~VLCDispatchEvent()
194 {
195     //clear event arguments
196     if( NULL != _dispParams.rgvarg )
197     {
198         for(unsigned int c=0; c<_dispParams.cArgs; ++c)
199             VariantClear(_dispParams.rgvarg+c);
200         CoTaskMemFree(_dispParams.rgvarg);
201     }
202     if( NULL != _dispParams.rgdispidNamedArgs )
203         CoTaskMemFree(_dispParams.rgdispidNamedArgs);
204 };
205
206 ////////////////////////////////////////////////////////////////////////////////////////////////
207
208 VLCConnectionPointContainer::VLCConnectionPointContainer(VLCPlugin *p_instance) :
209     _p_instance(p_instance), _b_freeze(FALSE)
210 {
211     _p_events = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
212             _p_instance->getDispEventID());
213
214     _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_events));
215
216     _p_props = new VLCConnectionPoint(dynamic_cast<LPCONNECTIONPOINTCONTAINER>(this),
217             IID_IPropertyNotifySink);
218
219     _v_cps.push_back(dynamic_cast<LPCONNECTIONPOINT>(_p_props));
220 };
221
222 VLCConnectionPointContainer::~VLCConnectionPointContainer()
223 {
224     delete _p_props;
225     delete _p_events;
226 };
227
228 STDMETHODIMP VLCConnectionPointContainer::EnumConnectionPoints(LPENUMCONNECTIONPOINTS *ppEnum)
229 {
230     if( NULL == ppEnum )
231         return E_POINTER;
232
233     *ppEnum = dynamic_cast<LPENUMCONNECTIONPOINTS>(new VLCEnumConnectionPoints(_v_cps));
234
235     return (NULL != *ppEnum ) ? S_OK : E_OUTOFMEMORY;
236 };
237
238 STDMETHODIMP VLCConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint **ppCP)
239 {
240     if( NULL == ppCP )
241         return E_POINTER;
242
243     *ppCP = NULL;
244
245     if( IID_IPropertyNotifySink == riid )
246     {
247         _p_props->AddRef();
248         *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_props);
249     }
250     else if( _p_instance->getDispEventID() == riid )
251     {
252         _p_events->AddRef();
253         *ppCP = dynamic_cast<LPCONNECTIONPOINT>(_p_events);
254     }
255     else
256         return CONNECT_E_NOCONNECTION;
257
258     return NOERROR;
259 };
260
261 void VLCConnectionPointContainer::freezeEvents(BOOL freeze)
262 {
263     if( ! freeze )
264     {
265         // release queued events
266         while( ! _q_events.empty() )
267         {
268             VLCDispatchEvent *ev = _q_events.front();
269             _q_events.pop();
270             _p_events->fireEvent(ev->_dispId, &ev->_dispParams);
271             delete ev;
272         }
273     }
274     _b_freeze = freeze;
275 };
276
277 void VLCConnectionPointContainer::fireEvent(DISPID dispId, DISPPARAMS* pDispParams)
278 {
279     if( _b_freeze )
280     {
281         // queue event for later use when container is ready
282         _q_events.push(new VLCDispatchEvent(dispId, *pDispParams));
283         if( _q_events.size() > 10 )
284         {
285             // too many events in queue, get rid of older one
286             delete _q_events.front();
287             _q_events.pop();
288         }
289     }
290     else
291     {
292         _p_events->fireEvent(dispId, pDispParams);
293     }
294 };
295
296 void VLCConnectionPointContainer::firePropChangedEvent(DISPID dispId)
297 {
298     if( ! _b_freeze )
299         _p_props->firePropChangedEvent(dispId);
300 };
301