reshuffling of dlls
[reactos.git] / reactos / dll / oleaut32 / connpt.c
1 /*
2 * Implementation of a generic ConnectionPoint object.
3 *
4 * Copyright 2000 Huw D M Davies for CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * NOTES:
21 * See one exported function here is CreateConnectionPoint, see
22 * comments just above that function for information.
23 */
24
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <string.h>
28
29 #define COBJMACROS
30
31 #include "winerror.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "wingdi.h"
35 #include "winuser.h"
36 #include "ole2.h"
37 #include "olectl.h"
38 #include "connpt.h"
39
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
43
44 #define MAXSINKS 10
45
46 /************************************************************************
47 * Implementation of IConnectionPoint
48 */
49 typedef struct ConnectionPointImpl {
50
51 const IConnectionPointVtbl *lpvtbl;
52
53 /* IUnknown of our main object*/
54 IUnknown *Obj;
55
56 /* Reference count */
57 LONG ref;
58
59 /* IID of sink interface */
60 IID iid;
61
62 /* Array of sink IUnknowns */
63 IUnknown **sinks;
64 DWORD maxSinks;
65
66 DWORD nSinks;
67 } ConnectionPointImpl;
68
69 static const IConnectionPointVtbl ConnectionPointImpl_VTable;
70
71
72 /************************************************************************
73 * Implementation of IEnumConnections
74 */
75 typedef struct EnumConnectionsImpl {
76
77 const IEnumConnectionsVtbl *lpvtbl;
78
79 LONG ref;
80
81 /* IUnknown of ConnectionPoint, used for ref counting */
82 IUnknown *pUnk;
83
84 /* Connection Data */
85 CONNECTDATA *pCD;
86 DWORD nConns;
87
88 /* Next connection to enumerate from */
89 DWORD nCur;
90
91 } EnumConnectionsImpl;
92
93 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
94 DWORD nSinks,
95 CONNECTDATA *pCD);
96
97
98 /************************************************************************
99 * ConnectionPointImpl_Construct
100 */
101 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
102 REFIID riid)
103 {
104 ConnectionPointImpl *Obj;
105
106 Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
107 Obj->lpvtbl = &ConnectionPointImpl_VTable;
108 Obj->Obj = pUnk;
109 Obj->ref = 1;
110 Obj->iid = *riid;
111 Obj->maxSinks = MAXSINKS;
112 Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
113 sizeof(IUnknown*) * MAXSINKS);
114 Obj->nSinks = 0;
115 return Obj;
116 }
117
118 /************************************************************************
119 * ConnectionPointImpl_Destroy
120 */
121 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
122 {
123 DWORD i;
124 for(i = 0; i < Obj->maxSinks; i++) {
125 if(Obj->sinks[i]) {
126 IUnknown_Release(Obj->sinks[i]);
127 Obj->sinks[i] = NULL;
128 }
129 }
130 HeapFree(GetProcessHeap(), 0, Obj->sinks);
131 HeapFree(GetProcessHeap(), 0, Obj);
132 return;
133 }
134
135 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
136 /************************************************************************
137 * ConnectionPointImpl_QueryInterface (IUnknown)
138 *
139 * See Windows documentation for more details on IUnknown methods.
140 */
141 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
142 IConnectionPoint* iface,
143 REFIID riid,
144 void** ppvObject)
145 {
146 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
147 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
148
149 /*
150 * Perform a sanity check on the parameters.
151 */
152 if ( (This==0) || (ppvObject==0) )
153 return E_INVALIDARG;
154
155 /*
156 * Initialize the return parameter.
157 */
158 *ppvObject = 0;
159
160 /*
161 * Compare the riid with the interface IDs implemented by this object.
162 */
163 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
164 {
165 *ppvObject = (IConnectionPoint*)This;
166 }
167 else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0)
168 {
169 *ppvObject = (IConnectionPoint*)This;
170 }
171
172 /*
173 * Check that we obtained an interface.
174 */
175 if ((*ppvObject)==0)
176 {
177 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
178 return E_NOINTERFACE;
179 }
180
181 /*
182 * Query Interface always increases the reference count by one when it is
183 * successful
184 */
185 ConnectionPointImpl_AddRef((IConnectionPoint*)This);
186
187 return S_OK;
188 }
189
190
191 /************************************************************************
192 * ConnectionPointImpl_AddRef (IUnknown)
193 *
194 * See Windows documentation for more details on IUnknown methods.
195 */
196 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
197 {
198 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
199 ULONG refCount = InterlockedIncrement(&This->ref);
200
201 TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1);
202
203 return refCount;
204 }
205
206 /************************************************************************
207 * ConnectionPointImpl_Release (IUnknown)
208 *
209 * See Windows documentation for more details on IUnknown methods.
210 */
211 static ULONG WINAPI ConnectionPointImpl_Release(
212 IConnectionPoint* iface)
213 {
214 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
215 ULONG refCount = InterlockedDecrement(&This->ref);
216
217 TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1);
218
219 /*
220 * If the reference count goes down to 0, perform suicide.
221 */
222 if (!refCount) ConnectionPointImpl_Destroy(This);
223
224 return refCount;
225 }
226
227 /************************************************************************
228 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
229 *
230 */
231 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
232 IConnectionPoint *iface,
233 IID *piid)
234 {
235 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
236 TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
237 *piid = This->iid;
238 return S_OK;
239 }
240
241 /************************************************************************
242 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
243 *
244 */
245 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
246 IConnectionPoint *iface,
247 IConnectionPointContainer **ppCPC)
248 {
249 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
250 TRACE("(%p)->(%p)\n", This, ppCPC);
251
252 return IUnknown_QueryInterface(This->Obj,
253 &IID_IConnectionPointContainer,
254 (LPVOID)ppCPC);
255 }
256
257 /************************************************************************
258 * ConnectionPointImpl_Advise (IConnectionPoint)
259 *
260 */
261 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
262 IUnknown *lpUnk,
263 DWORD *pdwCookie)
264 {
265 DWORD i;
266 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
267 IUnknown *lpSink;
268 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
269
270 *pdwCookie = 0;
271 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
272 return CONNECT_E_CANNOTCONNECT;
273
274 for(i = 0; i < This->maxSinks; i++) {
275 if(This->sinks[i] == NULL)
276 break;
277 }
278 if(i == This->maxSinks) {
279 This->maxSinks += MAXSINKS;
280 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
281 This->maxSinks * sizeof(IUnknown *));
282 }
283 This->sinks[i] = lpSink;
284 This->nSinks++;
285 *pdwCookie = i + 1;
286 return S_OK;
287 }
288
289
290 /************************************************************************
291 * ConnectionPointImpl_Unadvise (IConnectionPoint)
292 *
293 */
294 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
295 DWORD dwCookie)
296 {
297 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
298 TRACE("(%p)->(%ld)\n", This, dwCookie);
299
300 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
301
302 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
303
304 IUnknown_Release(This->sinks[dwCookie-1]);
305 This->sinks[dwCookie-1] = NULL;
306 This->nSinks--;
307 return S_OK;
308 }
309
310 /************************************************************************
311 * ConnectionPointImpl_EnumConnections (IConnectionPoint)
312 *
313 */
314 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
315 IConnectionPoint *iface,
316 LPENUMCONNECTIONS *ppEnum)
317 {
318 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
319 CONNECTDATA *pCD;
320 DWORD i, nextslot;
321 EnumConnectionsImpl *EnumObj;
322 HRESULT hr;
323
324 TRACE("(%p)->(%p)\n", This, ppEnum);
325
326 *ppEnum = NULL;
327
328 if(This->nSinks == 0) return OLE_E_NOCONNECTION;
329
330 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
331
332 for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
333 if(This->sinks[i] != NULL) {
334 pCD[nextslot].pUnk = This->sinks[i];
335 pCD[nextslot].dwCookie = i + 1;
336 nextslot++;
337 }
338 }
339 assert(nextslot == This->nSinks);
340
341 /* Bump the ref count of this object up by one. It gets Released in
342 IEnumConnections_Release */
343 IUnknown_AddRef((IUnknown*)This);
344
345 EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
346 hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj,
347 &IID_IEnumConnections, (LPVOID)ppEnum);
348 IEnumConnections_Release((IEnumConnections*)EnumObj);
349
350 HeapFree(GetProcessHeap(), 0, pCD);
351 return hr;
352 }
353
354 static const IConnectionPointVtbl ConnectionPointImpl_VTable =
355 {
356 ConnectionPointImpl_QueryInterface,
357 ConnectionPointImpl_AddRef,
358 ConnectionPointImpl_Release,
359 ConnectionPointImpl_GetConnectionInterface,
360 ConnectionPointImpl_GetConnectionPointContainer,
361 ConnectionPointImpl_Advise,
362 ConnectionPointImpl_Unadvise,
363 ConnectionPointImpl_EnumConnections
364 };
365
366
367 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
368 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
369
370 /************************************************************************
371 * EnumConnectionsImpl_Construct
372 */
373 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
374 DWORD nSinks,
375 CONNECTDATA *pCD)
376 {
377 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
378 DWORD i;
379
380 Obj->lpvtbl = &EnumConnectionsImpl_VTable;
381 Obj->ref = 1;
382 Obj->pUnk = pUnk;
383 Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
384 Obj->nConns = nSinks;
385 Obj->nCur = 0;
386
387 for(i = 0; i < nSinks; i++) {
388 Obj->pCD[i] = pCD[i];
389 IUnknown_AddRef(Obj->pCD[i].pUnk);
390 }
391 return Obj;
392 }
393
394 /************************************************************************
395 * EnumConnectionsImpl_Destroy
396 */
397 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
398 {
399 DWORD i;
400
401 for(i = 0; i < Obj->nConns; i++)
402 IUnknown_Release(Obj->pCD[i].pUnk);
403
404 HeapFree(GetProcessHeap(), 0, Obj->pCD);
405 HeapFree(GetProcessHeap(), 0, Obj);
406 return;
407 }
408
409 /************************************************************************
410 * EnumConnectionsImpl_QueryInterface (IUnknown)
411 *
412 * See Windows documentation for more details on IUnknown methods.
413 */
414 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
415 IEnumConnections* iface,
416 REFIID riid,
417 void** ppvObject)
418 {
419 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
420 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
421
422 /*
423 * Perform a sanity check on the parameters.
424 */
425 if ( (This==0) || (ppvObject==0) )
426 return E_INVALIDARG;
427
428 /*
429 * Initialize the return parameter.
430 */
431 *ppvObject = 0;
432
433 /*
434 * Compare the riid with the interface IDs implemented by this object.
435 */
436 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
437 {
438 *ppvObject = (IEnumConnections*)This;
439 }
440 else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0)
441 {
442 *ppvObject = (IEnumConnections*)This;
443 }
444
445 /*
446 * Check that we obtained an interface.
447 */
448 if ((*ppvObject)==0)
449 {
450 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
451 return E_NOINTERFACE;
452 }
453
454 /*
455 * Query Interface always increases the reference count by one when it is
456 * successful
457 */
458 EnumConnectionsImpl_AddRef((IEnumConnections*)This);
459
460 return S_OK;
461 }
462
463
464 /************************************************************************
465 * EnumConnectionsImpl_AddRef (IUnknown)
466 *
467 * See Windows documentation for more details on IUnknown methods.
468 */
469 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
470 {
471 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
472 ULONG refCount = InterlockedIncrement(&This->ref);
473
474 TRACE("(%p)->(ref before=%ld)\n", This, refCount - 1);
475
476 IUnknown_AddRef(This->pUnk);
477 return refCount;
478 }
479
480 /************************************************************************
481 * EnumConnectionsImpl_Release (IUnknown)
482 *
483 * See Windows documentation for more details on IUnknown methods.
484 */
485 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
486 {
487 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
488 ULONG refCount = InterlockedDecrement(&This->ref);
489
490 TRACE("(%p)->(ref before=%ld)\n", This, refCount + 1);
491
492 IUnknown_Release(This->pUnk);
493
494 /*
495 * If the reference count goes down to 0, perform suicide.
496 */
497 if (!refCount) EnumConnectionsImpl_Destroy(This);
498
499 return refCount;
500 }
501
502 /************************************************************************
503 * EnumConnectionsImpl_Next (IEnumConnections)
504 *
505 */
506 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
507 ULONG cConn, LPCONNECTDATA pCD,
508 ULONG *pEnum)
509 {
510 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
511 DWORD nRet = 0;
512 TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum);
513
514 if(pEnum == NULL) {
515 if(cConn != 1)
516 return E_POINTER;
517 } else
518 *pEnum = 0;
519
520 if(This->nCur >= This->nConns)
521 return S_FALSE;
522
523 while(This->nCur < This->nConns && cConn) {
524 *pCD++ = This->pCD[This->nCur];
525 IUnknown_AddRef(This->pCD[This->nCur].pUnk);
526 This->nCur++;
527 cConn--;
528 nRet++;
529 }
530
531 if(pEnum)
532 *pEnum = nRet;
533
534 return S_OK;
535 }
536
537
538 /************************************************************************
539 * EnumConnectionsImpl_Skip (IEnumConnections)
540 *
541 */
542 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
543 ULONG cSkip)
544 {
545 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
546 TRACE("(%p)->(%ld)\n", This, cSkip);
547
548 if(This->nCur + cSkip >= This->nConns)
549 return S_FALSE;
550
551 This->nCur += cSkip;
552
553 return S_OK;
554 }
555
556
557 /************************************************************************
558 * EnumConnectionsImpl_Reset (IEnumConnections)
559 *
560 */
561 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
562 {
563 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
564 TRACE("(%p)\n", This);
565
566 This->nCur = 0;
567
568 return S_OK;
569 }
570
571
572 /************************************************************************
573 * EnumConnectionsImpl_Clone (IEnumConnections)
574 *
575 */
576 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
577 LPENUMCONNECTIONS *ppEnum)
578 {
579 EnumConnectionsImpl *This = (EnumConnectionsImpl *)iface;
580 EnumConnectionsImpl *newObj;
581 TRACE("(%p)->(%p)\n", This, ppEnum);
582
583 newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
584 newObj->nCur = This->nCur;
585 *ppEnum = (LPENUMCONNECTIONS)newObj;
586 IUnknown_AddRef(This->pUnk);
587 return S_OK;
588 }
589
590 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable =
591 {
592 EnumConnectionsImpl_QueryInterface,
593 EnumConnectionsImpl_AddRef,
594 EnumConnectionsImpl_Release,
595 EnumConnectionsImpl_Next,
596 EnumConnectionsImpl_Skip,
597 EnumConnectionsImpl_Reset,
598 EnumConnectionsImpl_Clone
599 };
600
601 /************************************************************************
602 *
603 * The exported function to create the connection point.
604 * NB not a windows API
605 *
606 * PARAMS
607 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
608 * Needed to access IConnectionPointContainer.
609 *
610 * riid [in] IID of sink interface that this ConnectionPoint manages
611 *
612 * pCP [out] returns IConnectionPoint
613 *
614 */
615 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
616 IConnectionPoint **pCP)
617 {
618 ConnectionPointImpl *Obj;
619 HRESULT hr;
620
621 Obj = ConnectionPointImpl_Construct(pUnk, riid);
622 if(!Obj) return E_OUTOFMEMORY;
623
624 hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj,
625 &IID_IConnectionPoint, (LPVOID)pCP);
626 IConnectionPoint_Release((IConnectionPoint *)Obj);
627 return hr;
628 }