user32: Don't crash in DrawTextEx when tab length is zero.
[wine.git] / dlls / oleaut32 / connpt.c
blob0405d3857c8f45a86593b0a38b7ed00dc4014e5e
1 /*
2 * Implementation of a generic ConnectionPoint object.
4 * Copyright 2000 Huw D M Davies for CodeWeavers
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * NOTES:
21 * See one exported function here is CreateConnectionPoint, see
22 * comments just above that function for information.
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <string.h>
29 #define COBJMACROS
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"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(ole);
44 #define MAXSINKS 10
46 /************************************************************************
47 * Implementation of IConnectionPoint
49 typedef struct ConnectionPointImpl {
51 IConnectionPoint IConnectionPoint_iface;
53 /* IUnknown of our main object*/
54 IUnknown *Obj;
56 /* Reference count */
57 LONG ref;
59 /* IID of sink interface */
60 IID iid;
62 /* Array of sink IUnknowns */
63 IUnknown **sinks;
64 DWORD maxSinks;
66 DWORD nSinks;
67 } ConnectionPointImpl;
69 /************************************************************************
70 * Implementation of IEnumConnections
72 typedef struct EnumConnectionsImpl {
74 IEnumConnections IEnumConnections_iface;
76 LONG ref;
78 /* IUnknown of ConnectionPoint, used for ref counting */
79 IUnknown *pUnk;
81 /* Connection Data */
82 CONNECTDATA *pCD;
83 DWORD nConns;
85 /* Next connection to enumerate from */
86 DWORD nCur;
88 } EnumConnectionsImpl;
90 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
91 DWORD nSinks,
92 CONNECTDATA *pCD);
94 static inline ConnectionPointImpl *impl_from_IConnectionPoint(IConnectionPoint *iface)
96 return CONTAINING_RECORD(iface, ConnectionPointImpl, IConnectionPoint_iface);
99 static inline EnumConnectionsImpl *impl_from_IEnumConnections(IEnumConnections *iface)
101 return CONTAINING_RECORD(iface, EnumConnectionsImpl, IEnumConnections_iface);
104 /************************************************************************
105 * ConnectionPointImpl_Destroy
107 static void ConnectionPointImpl_Destroy(ConnectionPointImpl *Obj)
109 DWORD i;
110 for(i = 0; i < Obj->maxSinks; i++) {
111 if(Obj->sinks[i]) {
112 IUnknown_Release(Obj->sinks[i]);
113 Obj->sinks[i] = NULL;
116 HeapFree(GetProcessHeap(), 0, Obj->sinks);
117 HeapFree(GetProcessHeap(), 0, Obj);
118 return;
121 /************************************************************************
122 * ConnectionPointImpl_QueryInterface (IUnknown)
124 * See Windows documentation for more details on IUnknown methods.
126 static HRESULT WINAPI ConnectionPointImpl_QueryInterface(
127 IConnectionPoint* iface,
128 REFIID riid,
129 void** ppvObject)
131 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
132 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
135 * Perform a sanity check on the parameters.
137 if (!ppvObject)
138 return E_INVALIDARG;
141 * Initialize the return parameter.
143 *ppvObject = 0;
146 if (IsEqualIID(&IID_IConnectionPoint, riid) || IsEqualIID(&IID_IUnknown, riid))
147 *ppvObject = iface;
150 * Check that we obtained an interface.
152 if ((*ppvObject)==0)
154 FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid));
155 return E_NOINTERFACE;
158 IUnknown_AddRef((IUnknown*)*ppvObject);
160 return S_OK;
164 /************************************************************************
165 * ConnectionPointImpl_AddRef (IUnknown)
167 * See Windows documentation for more details on IUnknown methods.
169 static ULONG WINAPI ConnectionPointImpl_AddRef(IConnectionPoint* iface)
171 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
172 ULONG refCount = InterlockedIncrement(&This->ref);
174 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
176 return refCount;
179 /************************************************************************
180 * ConnectionPointImpl_Release (IUnknown)
182 * See Windows documentation for more details on IUnknown methods.
184 static ULONG WINAPI ConnectionPointImpl_Release(
185 IConnectionPoint* iface)
187 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
188 ULONG refCount = InterlockedDecrement(&This->ref);
190 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
193 * If the reference count goes down to 0, perform suicide.
195 if (!refCount) ConnectionPointImpl_Destroy(This);
197 return refCount;
200 /************************************************************************
201 * ConnectionPointImpl_GetConnectionInterface (IConnectionPoint)
204 static HRESULT WINAPI ConnectionPointImpl_GetConnectionInterface(
205 IConnectionPoint *iface,
206 IID *piid)
208 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
209 TRACE("(%p)->(%p) returning %s\n", This, piid, debugstr_guid(&(This->iid)));
210 *piid = This->iid;
211 return S_OK;
214 /************************************************************************
215 * ConnectionPointImpl_GetConnectionPointContainer (IConnectionPoint)
218 static HRESULT WINAPI ConnectionPointImpl_GetConnectionPointContainer(
219 IConnectionPoint *iface,
220 IConnectionPointContainer **ppCPC)
222 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
223 TRACE("(%p)->(%p)\n", This, ppCPC);
225 return IUnknown_QueryInterface(This->Obj, &IID_IConnectionPointContainer, (void**)ppCPC);
228 /************************************************************************
229 * ConnectionPointImpl_Advise (IConnectionPoint)
232 static HRESULT WINAPI ConnectionPointImpl_Advise(IConnectionPoint *iface,
233 IUnknown *lpUnk,
234 DWORD *pdwCookie)
236 DWORD i;
237 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
238 IUnknown *lpSink;
239 TRACE("(%p)->(%p, %p)\n", This, lpUnk, pdwCookie);
241 *pdwCookie = 0;
242 if(FAILED(IUnknown_QueryInterface(lpUnk, &This->iid, (void**)&lpSink)))
243 return CONNECT_E_CANNOTCONNECT;
245 for(i = 0; i < This->maxSinks; i++) {
246 if(This->sinks[i] == NULL)
247 break;
249 if(i == This->maxSinks) {
250 This->maxSinks += MAXSINKS;
251 This->sinks = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->sinks,
252 This->maxSinks * sizeof(IUnknown *));
254 This->sinks[i] = lpSink;
255 This->nSinks++;
256 *pdwCookie = i + 1;
257 return S_OK;
261 /************************************************************************
262 * ConnectionPointImpl_Unadvise (IConnectionPoint)
265 static HRESULT WINAPI ConnectionPointImpl_Unadvise(IConnectionPoint *iface,
266 DWORD dwCookie)
268 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
269 TRACE("(%p)->(%d)\n", This, dwCookie);
271 if(dwCookie == 0 || dwCookie > This->maxSinks) return E_INVALIDARG;
273 if(This->sinks[dwCookie-1] == NULL) return CONNECT_E_NOCONNECTION;
275 IUnknown_Release(This->sinks[dwCookie-1]);
276 This->sinks[dwCookie-1] = NULL;
277 This->nSinks--;
278 return S_OK;
281 /************************************************************************
282 * ConnectionPointImpl_EnumConnections (IConnectionPoint)
285 static HRESULT WINAPI ConnectionPointImpl_EnumConnections(
286 IConnectionPoint *iface,
287 LPENUMCONNECTIONS *ppEnum)
289 ConnectionPointImpl *This = impl_from_IConnectionPoint(iface);
290 CONNECTDATA *pCD;
291 DWORD i, nextslot;
292 EnumConnectionsImpl *EnumObj;
293 HRESULT hr;
295 TRACE("(%p)->(%p)\n", This, ppEnum);
297 *ppEnum = NULL;
299 if(This->nSinks == 0) return OLE_E_NOCONNECTION;
301 pCD = HeapAlloc(GetProcessHeap(), 0, sizeof(CONNECTDATA) * This->nSinks);
303 for(i = 0, nextslot = 0; i < This->maxSinks; i++) {
304 if(This->sinks[i] != NULL) {
305 pCD[nextslot].pUnk = This->sinks[i];
306 pCD[nextslot].dwCookie = i + 1;
307 nextslot++;
310 assert(nextslot == This->nSinks);
312 /* Bump the ref count of this object up by one. It gets Released in
313 IEnumConnections_Release */
314 IConnectionPoint_AddRef(iface);
316 EnumObj = EnumConnectionsImpl_Construct((IUnknown*)iface, This->nSinks, pCD);
317 hr = IEnumConnections_QueryInterface(&EnumObj->IEnumConnections_iface,
318 &IID_IEnumConnections, (void**)ppEnum);
319 IEnumConnections_Release(&EnumObj->IEnumConnections_iface);
321 HeapFree(GetProcessHeap(), 0, pCD);
322 return hr;
325 static const IConnectionPointVtbl ConnectionPointImpl_VTable =
327 ConnectionPointImpl_QueryInterface,
328 ConnectionPointImpl_AddRef,
329 ConnectionPointImpl_Release,
330 ConnectionPointImpl_GetConnectionInterface,
331 ConnectionPointImpl_GetConnectionPointContainer,
332 ConnectionPointImpl_Advise,
333 ConnectionPointImpl_Unadvise,
334 ConnectionPointImpl_EnumConnections
338 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable;
340 /************************************************************************
341 * EnumConnectionsImpl_Construct
343 static EnumConnectionsImpl *EnumConnectionsImpl_Construct(IUnknown *pUnk,
344 DWORD nSinks,
345 CONNECTDATA *pCD)
347 EnumConnectionsImpl *Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
348 DWORD i;
350 Obj->IEnumConnections_iface.lpVtbl = &EnumConnectionsImpl_VTable;
351 Obj->ref = 1;
352 Obj->pUnk = pUnk;
353 Obj->pCD = HeapAlloc(GetProcessHeap(), 0, nSinks * sizeof(CONNECTDATA));
354 Obj->nConns = nSinks;
355 Obj->nCur = 0;
357 for(i = 0; i < nSinks; i++) {
358 Obj->pCD[i] = pCD[i];
359 IUnknown_AddRef(Obj->pCD[i].pUnk);
361 return Obj;
364 /************************************************************************
365 * EnumConnectionsImpl_Destroy
367 static void EnumConnectionsImpl_Destroy(EnumConnectionsImpl *Obj)
369 DWORD i;
371 for(i = 0; i < Obj->nConns; i++)
372 IUnknown_Release(Obj->pCD[i].pUnk);
374 HeapFree(GetProcessHeap(), 0, Obj->pCD);
375 HeapFree(GetProcessHeap(), 0, Obj);
376 return;
379 /************************************************************************
380 * EnumConnectionsImpl_QueryInterface (IUnknown)
382 * See Windows documentation for more details on IUnknown methods.
384 static HRESULT WINAPI EnumConnectionsImpl_QueryInterface(
385 IEnumConnections* iface,
386 REFIID riid,
387 void** ppvObject)
389 ConnectionPointImpl *This = (ConnectionPointImpl *)iface;
390 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
393 * Perform a sanity check on the parameters.
395 if (!ppvObject)
396 return E_INVALIDARG;
399 * Initialize the return parameter.
401 *ppvObject = 0;
403 if (IsEqualIID(&IID_IEnumConnections, riid) || IsEqualIID(&IID_IUnknown, riid))
404 *ppvObject = iface;
407 * Check that we obtained an interface.
409 if ((*ppvObject)==0)
411 FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid));
412 return E_NOINTERFACE;
415 IUnknown_AddRef((IUnknown*)*ppvObject);
417 return S_OK;
421 /************************************************************************
422 * EnumConnectionsImpl_AddRef (IUnknown)
424 * See Windows documentation for more details on IUnknown methods.
426 static ULONG WINAPI EnumConnectionsImpl_AddRef(IEnumConnections* iface)
428 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
429 ULONG refCount = InterlockedIncrement(&This->ref);
431 TRACE("(%p)->(ref before=%d)\n", This, refCount - 1);
433 IUnknown_AddRef(This->pUnk);
434 return refCount;
437 /************************************************************************
438 * EnumConnectionsImpl_Release (IUnknown)
440 * See Windows documentation for more details on IUnknown methods.
442 static ULONG WINAPI EnumConnectionsImpl_Release(IEnumConnections* iface)
444 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
445 ULONG refCount = InterlockedDecrement(&This->ref);
447 TRACE("(%p)->(ref before=%d)\n", This, refCount + 1);
449 IUnknown_Release(This->pUnk);
452 * If the reference count goes down to 0, perform suicide.
454 if (!refCount) EnumConnectionsImpl_Destroy(This);
456 return refCount;
459 /************************************************************************
460 * EnumConnectionsImpl_Next (IEnumConnections)
463 static HRESULT WINAPI EnumConnectionsImpl_Next(IEnumConnections* iface,
464 ULONG cConn, LPCONNECTDATA pCD,
465 ULONG *pEnum)
467 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
468 DWORD nRet = 0;
469 TRACE("(%p)->(%d, %p, %p)\n", This, cConn, pCD, pEnum);
471 if(pEnum == NULL) {
472 if(cConn != 1)
473 return E_POINTER;
474 } else
475 *pEnum = 0;
477 if(This->nCur >= This->nConns)
478 return S_FALSE;
480 while(This->nCur < This->nConns && cConn) {
481 *pCD++ = This->pCD[This->nCur];
482 IUnknown_AddRef(This->pCD[This->nCur].pUnk);
483 This->nCur++;
484 cConn--;
485 nRet++;
488 if(pEnum)
489 *pEnum = nRet;
491 return S_OK;
495 /************************************************************************
496 * EnumConnectionsImpl_Skip (IEnumConnections)
499 static HRESULT WINAPI EnumConnectionsImpl_Skip(IEnumConnections* iface,
500 ULONG cSkip)
502 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
503 TRACE("(%p)->(%d)\n", This, cSkip);
505 if(This->nCur + cSkip >= This->nConns)
506 return S_FALSE;
508 This->nCur += cSkip;
510 return S_OK;
514 /************************************************************************
515 * EnumConnectionsImpl_Reset (IEnumConnections)
518 static HRESULT WINAPI EnumConnectionsImpl_Reset(IEnumConnections* iface)
520 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
521 TRACE("(%p)\n", This);
523 This->nCur = 0;
525 return S_OK;
529 /************************************************************************
530 * EnumConnectionsImpl_Clone (IEnumConnections)
533 static HRESULT WINAPI EnumConnectionsImpl_Clone(IEnumConnections* iface,
534 LPENUMCONNECTIONS *ppEnum)
536 EnumConnectionsImpl *This = impl_from_IEnumConnections(iface);
537 EnumConnectionsImpl *newObj;
538 TRACE("(%p)->(%p)\n", This, ppEnum);
540 newObj = EnumConnectionsImpl_Construct(This->pUnk, This->nConns, This->pCD);
541 newObj->nCur = This->nCur;
542 *ppEnum = &newObj->IEnumConnections_iface;
543 IUnknown_AddRef(This->pUnk);
544 return S_OK;
547 static const IEnumConnectionsVtbl EnumConnectionsImpl_VTable =
549 EnumConnectionsImpl_QueryInterface,
550 EnumConnectionsImpl_AddRef,
551 EnumConnectionsImpl_Release,
552 EnumConnectionsImpl_Next,
553 EnumConnectionsImpl_Skip,
554 EnumConnectionsImpl_Reset,
555 EnumConnectionsImpl_Clone
558 /************************************************************************
560 * The exported function to create the connection point.
561 * NB not a windows API
563 * PARAMS
564 * pUnk [in] IUnknown of object to which the ConnectionPoint is associated.
565 * Needed to access IConnectionPointContainer.
567 * riid [in] IID of sink interface that this ConnectionPoint manages
569 * pCP [out] returns IConnectionPoint
572 HRESULT CreateConnectionPoint(IUnknown *pUnk, REFIID riid,
573 IConnectionPoint **pCP)
575 ConnectionPointImpl *Obj;
577 TRACE("(%p %s %p)\n", pUnk, debugstr_guid(riid), pCP);
579 *pCP = NULL;
580 Obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*Obj));
581 if (!Obj)
582 return E_OUTOFMEMORY;
584 Obj->IConnectionPoint_iface.lpVtbl = &ConnectionPointImpl_VTable;
585 Obj->Obj = pUnk;
586 Obj->ref = 1;
587 Obj->iid = *riid;
588 Obj->maxSinks = MAXSINKS;
589 Obj->sinks = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IUnknown*) * MAXSINKS);
590 Obj->nSinks = 0;
592 *pCP = &Obj->IConnectionPoint_iface;
593 return S_OK;