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