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