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