Improved support for vm86 mode.
[wine.git] / dlls / oleaut32 / connpt.c
blobdcbaa8adc0f57ee313e94112c11de0ee2137a9a8
1 /*
2 * Implementation of a generic ConnectionPoint object.
4 * Copyright 2000 Huw D M Davies for CodeWeavers
6 * See one exported function here is CreateConnectionPoint, see
7 * comments just above that function for information.
8 */
10 #include <assert.h>
11 #include "winerror.h"
12 #include "olectl.h"
13 #include "wine/obj_base.h"
14 #include "wine/obj_connection.h"
15 #include "connpt.h"
17 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(ole)
21 #define MAXSINKS 10
23 /************************************************************************
24 * Implementation of IConnectionPoint
26 typedef struct ConnectionPointImpl {
28 ICOM_VTABLE(IConnectionPoint) *lpvtbl;
30 /* IUnknown of our main object*/
31 IUnknown *Obj;
33 /* Reference count */
34 DWORD ref;
36 /* IID of sink interface */
37 IID iid;
39 /* Array of sink IUnknowns */
40 IUnknown **sinks;
41 DWORD maxSinks;
43 DWORD nSinks;
44 } ConnectionPointImpl;
46 static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable;
49 /************************************************************************
50 * Implementation of IEnumConnections
52 typedef struct EnumConnectionsImpl {
54 ICOM_VTABLE(IEnumConnections) *lpvtbl;
56 DWORD ref;
58 /* IUnknown of ConnectionPoint, used for ref counting */
59 IUnknown *pUnk;
61 /* Connection Data */
62 CONNECTDATA *pCD;
63 DWORD nConns;
65 /* Next connection to enumerate from */
66 DWORD nCur;
68 } EnumConnectionsImpl;
70 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
71 DWORD nSinks,
72 CONNECTDATA *pCD);
75 /************************************************************************
76 * ConnectionPointImpl_Construct
78 static ConnectionPointImpl *ConnectionPointImpl_Construct(IUnknown *pUnk,
79 REFIID riid)
81 ConnectionPointImpl *Obj;
83 Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
84 Obj->lpvtbl = &ConnectionPointImpl_VTable;
85 Obj->Obj = pUnk;
86 Obj->ref = 1;
87 Obj->iid = *riid;
88 Obj->maxSinks = MAXSINKS;
89 Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
90 sizeof(IUnknown*) * MAXSINKS);
91 Obj->nSinks = 0;
92 return Obj;
95 /************************************************************************
96 * ConnectionPointImpl_Destroy
98 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
100 DWORD i;
101 for(i = 0; i < Obj->maxSinks; i++) {
102 if(Obj->sinks[i]) {
103 IUnknown_Release(Obj->sinks[i]);
104 Obj->sinks[i] = NULL;
107 HeapFree(GetProcessHeap(), 0, Obj->sinks);
108 HeapFree(GetProcessHeap(), 0, Obj);
109 return;
112 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface);
113 /************************************************************************
114 * ConnectionPointImpl_QueryInterface (IUnknown)
116 * See Windows documentation for more details on IUnknown methods.
118 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
119 IConnectionPoint* iface,
120 REFIID riid,
121 void** ppvObject)
123 ICOM_THIS(ConnectionPointImpl, iface);
124 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
127 * Perform a sanity check on the parameters.
129 if ( (This==0) || (ppvObject==0) )
130 return E_INVALIDARG;
133 * Initialize the return parameter.
135 *ppvObject = 0;
138 * Compare the riid with the interface IDs implemented by this object.
140 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
142 *ppvObject = (IConnectionPoint*)This;
144 else if (memcmp(&IID_IConnectionPoint, riid, sizeof(IID_IConnectionPoint)) == 0)
146 *ppvObject = (IConnectionPoint*)This;
150 * Check that we obtained an interface.
152 if ((*ppvObject)==0)
154 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
155 return E_NOINTERFACE;
159 * Query Interface always increases the reference count by one when it is
160 * successful
162 ConnectionPointImpl_AddRef((IConnectionPoint*)This);
164 return S_OK;;
168 /************************************************************************
169 * ConnectionPointImpl_AddRef (IUnknown)
171 * See Windows documentation for more details on IUnknown methods.
173 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
175 ICOM_THIS(ConnectionPointImpl, iface);
176 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
177 This->ref++;
179 return This->ref;
182 /************************************************************************
183 * ConnectionPointImpl_Release (IUnknown)
185 * See Windows documentation for more details on IUnknown methods.
187 static ULONG WINAPI ConnectionPointImpl_Release(
188 IConnectionPoint* iface)
190 ICOM_THIS(ConnectionPointImpl, iface);
191 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
194 * Decrease the reference count on this object.
196 This->ref--;
199 * If the reference count goes down to 0, perform suicide.
201 if (This->ref==0)
203 ConnectionPointImpl_Destroy(This);
205 return 0;
208 return This->ref;
211 /************************************************************************
212 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
215 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
216 IConnectionPoint *iface,
217 IID *piid)
219 ICOM_THIS(ConnectionPointImpl, iface);
220 TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
221 *piid = This->iid;
222 return S_OK;
225 /************************************************************************
226 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
229 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
230 IConnectionPoint *iface,
231 IConnectionPointContainer **ppCPC)
233 ICOM_THIS(ConnectionPointImpl, iface);
234 TRACE("(%p)->(%p)\n", This, ppCPC);
236 return IUnknown_QueryInterface(This->Obj,
237 &IID_IConnectionPointContainer,
238 (LPVOID)ppCPC);
241 /************************************************************************
242 * ConnectionPointImpl_Advise (IConnectionPoint)
245 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
246 IUnknown *lpUnk,
247 DWORD *pdwCookie)
249 DWORD i;
250 ICOM_THIS(ConnectionPointImpl, iface);
251 IUnknown *lpSink;
252 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
254 *pdwCookie = 0;
255 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (LPVOID)&lpSink)))
256 return CONNECT_E_CANNOTCONNECT;
258 for(i = 0; i < This->maxSinks; i++) {
259 if(This->sinks[i] == NULL)
260 break;
262 if(i == This->maxSinks) {
263 This->maxSinks += MAXSINKS;
264 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
265 This->maxSinks * sizeof(IUnknown *));
267 This->sinks[i] = lpSink;
268 This->nSinks++;
269 *pdwCookie = i + 1;
270 return S_OK;
274 /************************************************************************
275 * ConnectionPointImpl_Unadvise (IConnectionPoint)
278 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
279 DWORD dwCookie)
281 ICOM_THIS(ConnectionPointImpl, iface);
282 TRACE("(%p)->(%ld)\n", This, dwCookie);
284 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
286 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
288 IUnknown_Release(This->sinks[dwCookie-1]);
289 This->sinks[dwCookie-1] = NULL;
290 This->nSinks--;
291 return S_OK;
294 /************************************************************************
295 * ConnectionPointImpl_EnumConnections (IConnectionPoint)
298 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
299 IConnectionPoint *iface,
300 LPENUMCONNECTIONS *ppEnum)
302 ICOM_THIS(ConnectionPointImpl, iface);
303 CONNECTDATA *pCD;
304 DWORD i, nextslot;
305 EnumConnectionsImpl *EnumObj;
306 HRESULT hr;
308 TRACE("(%p)->(%p)\n", This, ppEnum);
310 *ppEnum = NULL;
312 if(This->nSinks == 0) return OLE_E_NOCONNECTION;
314 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
316 for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
317 if(This->sinks[i] != NULL) {
318 pCD[nextslot].pUnk = This->sinks[i];
319 pCD[nextslot].dwCookie = i + 1;
320 nextslot++;
323 assert(nextslot == This->nSinks);
325 /* Bump the ref count of this object up by one. It gets Released in
326 IEnumConnections_Release */
327 IUnknown_AddRef((IUnknown*)This);
329 EnumObj = EnumConnectionsImpl_Construct((IUnknown*)This, This->nSinks, pCD);
330 hr = IEnumConnections_QueryInterface((IEnumConnections*)EnumObj,
331 &IID_IEnumConnections, (LPVOID)ppEnum);
332 IEnumConnections_Release((IEnumConnections*)EnumObj);
334 HeapFree(GetProcessHeap(), 0, pCD);
335 return hr;
338 static ICOM_VTABLE(IConnectionPoint) ConnectionPointImpl_VTable =
340 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
341 ConnectionPointImpl_QueryInterface,
342 ConnectionPointImpl_AddRef,
343 ConnectionPointImpl_Release,
344 ConnectionPointImpl_GetConnectionInterface,
345 ConnectionPointImpl_GetConnectionPointContainer,
346 ConnectionPointImpl_Advise,
347 ConnectionPointImpl_Unadvise,
348 ConnectionPointImpl_EnumConnections
352 static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable;
353 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface);
355 /************************************************************************
356 * EnumConnectionsImpl_Construct
358 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
359 DWORD nSinks,
360 CONNECTDATA *pCD)
362 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
363 DWORD i;
365 Obj->lpvtbl = &EnumConnectionsImpl_VTable;
366 Obj->ref = 1;
367 Obj->pUnk = pUnk;
368 Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
369 Obj->nConns = nSinks;
370 Obj->nCur = 0;
372 for(i = 0; i < nSinks; i++) {
373 Obj->pCD[i] = pCD[i];
374 IUnknown_AddRef(Obj->pCD[i].pUnk);
376 return Obj;
379 /************************************************************************
380 * EnumConnectionsImpl_Destroy
382 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
384 DWORD i;
386 for(i = 0; i < Obj->nConns; i++)
387 IUnknown_Release(Obj->pCD[i].pUnk);
389 HeapFree(GetProcessHeap(), 0, Obj->pCD);
390 HeapFree(GetProcessHeap(), 0, Obj);
391 return;
394 /************************************************************************
395 * EnumConnectionsImpl_QueryInterface (IUnknown)
397 * See Windows documentation for more details on IUnknown methods.
399 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
400 IEnumConnections* iface,
401 REFIID riid,
402 void** ppvObject)
404 ICOM_THIS(ConnectionPointImpl, iface);
405 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
408 * Perform a sanity check on the parameters.
410 if ( (This==0) || (ppvObject==0) )
411 return E_INVALIDARG;
414 * Initialize the return parameter.
416 *ppvObject = 0;
419 * Compare the riid with the interface IDs implemented by this object.
421 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
423 *ppvObject = (IEnumConnections*)This;
425 else if (memcmp(&IID_IEnumConnections, riid, sizeof(IID_IEnumConnections)) == 0)
427 *ppvObject = (IEnumConnections*)This;
431 * Check that we obtained an interface.
433 if ((*ppvObject)==0)
435 FIXME("() : asking for un supported interface %s\n",debugstr_guid(riid));
436 return E_NOINTERFACE;
440 * Query Interface always increases the reference count by one when it is
441 * successful
443 EnumConnectionsImpl_AddRef((IEnumConnections*)This);
445 return S_OK;;
449 /************************************************************************
450 * EnumConnectionsImpl_AddRef (IUnknown)
452 * See Windows documentation for more details on IUnknown methods.
454 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
456 ICOM_THIS(EnumConnectionsImpl, iface);
457 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
458 This->ref++;
459 IUnknown_AddRef(This->pUnk);
460 return This->ref;
463 /************************************************************************
464 * EnumConnectionsImpl_Release (IUnknown)
466 * See Windows documentation for more details on IUnknown methods.
468 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
470 ICOM_THIS(EnumConnectionsImpl, iface);
471 TRACE("(%p)->(ref=%ld)\n", This, This->ref);
473 IUnknown_Release(This->pUnk);
476 * Decrease the reference count on this object.
478 This->ref--;
481 * If the reference count goes down to 0, perform suicide.
483 if (This->ref==0)
485 EnumConnectionsImpl_Destroy(This);
487 return 0;
490 return This->ref;
493 /************************************************************************
494 * EnumConnectionsImpl_Next (IEnumConnections)
497 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
498 ULONG cConn, LPCONNECTDATA pCD,
499 ULONG *pEnum)
501 ICOM_THIS(EnumConnectionsImpl, iface);
502 DWORD nRet = 0;
503 TRACE("(%p)->(%ld, %p, %p)\n", This, cConn, pCD, pEnum);
505 if(pEnum == NULL) {
506 if(cConn != 1)
507 return E_POINTER;
508 } else
509 *pEnum = 0;
511 if(This->nCur >= This->nConns)
512 return S_FALSE;
514 while(This->nCur < This->nConns && cConn) {
515 *pCD++ = This->pCD[This->nCur];
516 IUnknown_AddRef(This->pCD[This->nCur].pUnk);
517 This->nCur++;
518 cConn--;
519 nRet++;
522 if(pEnum)
523 *pEnum = nRet;
525 return S_OK;
529 /************************************************************************
530 * EnumConnectionsImpl_Skip (IEnumConnections)
533 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
534 ULONG cSkip)
536 ICOM_THIS(EnumConnectionsImpl, iface);
537 TRACE("(%p)->(%ld)\n", This, cSkip);
539 if(This->nCur + cSkip >= This->nConns)
540 return S_FALSE;
542 This->nCur += cSkip;
544 return S_OK;
548 /************************************************************************
549 * EnumConnectionsImpl_Reset (IEnumConnections)
552 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
554 ICOM_THIS(EnumConnectionsImpl, iface);
555 TRACE("(%p)\n", This);
557 This->nCur = 0;
559 return S_OK;
563 /************************************************************************
564 * EnumConnectionsImpl_Clone (IEnumConnections)
567 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
568 LPENUMCONNECTIONS *ppEnum)
570 ICOM_THIS(EnumConnectionsImpl, iface);
571 EnumConnectionsImpl *newObj;
572 TRACE("(%p)->(%p)\n", This, ppEnum);
574 newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
575 newObj->nCur = This->nCur;
576 *ppEnum = (LPENUMCONNECTIONS)newObj;
577 IUnknown_AddRef(This->pUnk);
578 return S_OK;
581 static ICOM_VTABLE(IEnumConnections) EnumConnectionsImpl_VTable =
583 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
584 EnumConnectionsImpl_QueryInterface,
585 EnumConnectionsImpl_AddRef,
586 EnumConnectionsImpl_Release,
587 EnumConnectionsImpl_Next,
588 EnumConnectionsImpl_Skip,
589 EnumConnectionsImpl_Reset,
590 EnumConnectionsImpl_Clone
593 /************************************************************************
595 * The exported function to create the connection point.
596 * NB not a windows API
598 * PARAMS
599 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
600 * Needed to access IConnectionPointContainer.
602 * riid [in] IID of sink interface that this ConnectionPoint manages
604 * pCP [out] returns IConnectionPoint
607 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
608 IConnectionPoint **pCP)
610 ConnectionPointImpl *Obj;
611 HRESULT hr;
613 Obj = ConnectionPointImpl_Construct(pUnk, riid);
614 if(!Obj) return E_OUTOFMEMORY;
616 hr = IConnectionPoint_QueryInterface((IConnectionPoint *)Obj,
617 &IID_IConnectionPoint, (LPVOID)pCP);
618 IConnectionPoint_Release((IConnectionPoint *)Obj);
619 return hr;