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