diff --git a/idl/comrogue/objectbase.idl b/idl/comrogue/objectbase.idl index dfd462c..215ea8a 100644 --- a/idl/comrogue/objectbase.idl +++ b/idl/comrogue/objectbase.idl @@ -69,3 +69,20 @@ interface IServiceProvider : IUnknown [unique] typedef IServiceProvider *PSERVICEPROVIDER; HRESULT QueryService([in] REFGUID guidService, [in] REFIID riid, [out, iid_is(riid)] PPVOID ppvObject); } + +/*------------------------ + * IEnumUnknown interface + *------------------------ + */ + +[object, uuid(00000100-0000-0000-C000-000000000046), pointer_default(unique)] +interface IEnumUnknown: IUnknown +{ + [unique] typedef IEnumUnknown *PENUMUNKNOWN; + + HRESULT Next([in] UINT32 celt, [out, size_is(celt), length_is(*pceltFetched)] IUnknown **rgelt, + [out] UINT32 *pceltFetched); + HRESULT Skip([in] UINT32 celt); + HRESULT Reset(void); + HRESULT Clone([out] IEnumUnknown **ppEnum); +} diff --git a/include/comrogue/heap.h b/include/comrogue/heap.h index 18220c9..d4506aa 100644 --- a/include/comrogue/heap.h +++ b/include/comrogue/heap.h @@ -46,10 +46,10 @@ typedef struct tagRAWHEAPDATA { - UINT32 opaque[8]; + UINT32 opaque[32]; /* opaque data, do not modify */ } RAWHEAPDATA, *PRAWHEAPDATA; -typedef void (*PFNRAWHEAPDATAFREE)(PRAWHEAPDATA prhd); +typedef void (*PFNRAWHEAPDATAFREE)(PRAWHEAPDATA prhd); /* function that optionally frees the heap data */ /*-------------------- * External functions diff --git a/include/comrogue/objhelp.h b/include/comrogue/objhelp.h index e856b35..ee64d6d 100644 --- a/include/comrogue/objhelp.h +++ b/include/comrogue/objhelp.h @@ -51,8 +51,9 @@ typedef struct tagFIXEDCPDATA PUNKNOWN punkOuter; /* outer unknown used for reference counts */ REFIID riidConnection; /* IID of outgoing interface for this connection point */ IUnknown **ppSlots; /* pointer to actual slots used for connection point storage */ - INT32 ncpSize; /* number of connection points actually connected */ - INT32 ncpCapacity; /* maximum number of connection points connectable */ + UINT32 ncpSize; /* number of connection points actually connected */ + UINT32 ncpCapacity; /* maximum number of connection points connectable */ + IMalloc *pAllocator; /* pointer to allocator */ } FIXEDCPDATA, *PFIXEDCPDATA; /*--------------------- @@ -64,6 +65,7 @@ CDECL_BEGIN /* QueryInterface helpers */ extern HRESULT ObjHlpStandardQueryInterface_IConnectionPoint(IUnknown *pThis, REFIID riid, PPVOID ppvObject); +extern HRESULT ObjHlpStandardQueryInterface_IEnumConnections(IUnknown *pThis, REFIID riid, PPVOID ppvObject); extern HRESULT ObjHlpStandardQueryInterface_IMalloc(IUnknown *pThis, REFIID riid, PPVOID ppvObject); extern HRESULT ObjHlpStandardQueryInterface_ISequentialStream(IUnknown *pThis, REFIID riid, PPVOID ppvObject); @@ -72,7 +74,7 @@ extern UINT32 ObjHlpStaticAddRefRelease(IUnknown *pThis); /* Connection point helpers */ extern void ObjHlpFixedCpSetup(PFIXEDCPDATA pData, PUNKNOWN punkOuter, REFIID riidConnection, - IUnknown **ppSlots, INT32 nSlots); + IUnknown **ppSlots, UINT32 nSlots, IMalloc *pAllocator); extern void ObjHlpFixedCpTeardown(PFIXEDCPDATA pData); /* Other helpers */ diff --git a/include/comrogue/scode.h b/include/comrogue/scode.h index 8d6aab8..f89da16 100644 --- a/include/comrogue/scode.h +++ b/include/comrogue/scode.h @@ -93,6 +93,10 @@ #define STG_S_CONSOLIDATIONFAILED SCODE_CAST(0x00030205) /* consolidation failed but commit OK */ #define STG_S_CANNOTCONSOLIDATE SCODE_CAST(0x00030206) /* cannot consolidate but commit OK */ +/* Connection success codes */ +#define CONNECT_S_FIRST SCODE_CAST(0x00040200) /* first connection success code */ +#define CONNECT_S_LAST SCODE_CAST(0x0004020F) /* last connection success code */ + /* Memory manager success codes */ #define MEMMGR_S_NONZEROED SCODE_CAST(0x06010001) /* returned memory is non-zeroed */ @@ -158,6 +162,15 @@ #define STG_E_CSSINVALIDREGION SCODE_CAST(0x8003030A) /* region identifier mismatch */ #define STG_E_NOMOREREGIONRESETS SCODE_CAST(0x8003030B) /* can't reset drive region anymore */ +/* Connection error codes */ +#define CONNECT_E_FIRST SCODE_CAST(0x80040200) /* first connection error code */ +#define CONNECT_E_LAST SCODE_CAST(0x8004020F) /* last connection error code */ + +#define CONNECT_E_NOCONNECTION (CONNECT_E_FIRST+0) /* no connection found */ +#define CONNECT_E_ADVISELIMIT (CONNECT_E_FIRST+1) /* limit for number of connections reached */ +#define CONNECT_E_CANNOTCONNECT (CONNECT_E_FIRST+2) /* connection attempt failed */ +#define CONNECT_E_OVERRIDDEN (CONNECT_E_FIRST+3) /* interface overridden, must use derived */ + /* Memory manager error codes */ #define MEMMGR_E_NOPGTBL SCODE_CAST(0x86010001) /* no page tables available */ #define MEMMGR_E_BADTTBFLG SCODE_CAST(0x86010002) /* bad TTB flags encountered */ diff --git a/kernel/lib/Makefile b/kernel/lib/Makefile index c06c9e9..0e1b243 100644 --- a/kernel/lib/Makefile +++ b/kernel/lib/Makefile @@ -32,8 +32,8 @@ MAKEFLAGS += -rR CRBASEDIR := $(abspath ../..) include $(CRBASEDIR)/armcompile.mk -LIB_OBJS = divide.o qdivrem.o heap_toplevel.o intlib.o objhelp.o objhelp_fixedcp.o rbtree.o str.o \ - strcopymem.o strcomparemem.o strsetmem.o lib_guids.o +LIB_OBJS = divide.o qdivrem.o heap_toplevel.o intlib.o objhelp.o objhelp_enumconn.o objhelp_enumgeneric.o \ + objhelp_fixedcp.o rbtree.o str.o strcopymem.o strcomparemem.o strsetmem.o lib_guids.o all: kernel-lib.o diff --git a/kernel/lib/enumconn.h b/kernel/lib/enumconn.h new file mode 100644 index 0000000..ed5cfd7 --- /dev/null +++ b/kernel/lib/enumconn.h @@ -0,0 +1,77 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#ifndef __ENUMCONN_H_INCLUDED +#define __ENUMCONN_H_INCLUDED + +#ifdef __COMROGUE_INTERNALS__ + +#ifndef __ASM__ + +#include +#include +#include +#include + +/*--------------------------------------------------- + * Data structures for implementing IEnumConnections + *--------------------------------------------------- + */ + +typedef struct tagENUMCONNDATA { + UINT32 uiRefCount; /* reference count */ + UINT32 nConnectData; /* count of CONNECTDATA */ + CONNECTDATA rgConnectData[0]; /* array of CONNECTDATA */ +} ENUMCONNDATA, *PENUMCONNDATA; + +typedef struct tagENUMCONN { + IEnumConnections enumConnections; /* interface pointer */ + UINT32 uiRefCount; /* reference count */ + UINT32 nCurrent; /* current pointer into array */ + PENUMCONNDATA pPayload; /* payload array */ + IMalloc *pAllocator; /* allocator pointer */ +} ENUMCONN, *PENUMCONN; + +/*--------------------------------------------------- + * Functions for implementing IEnumConnections + *--------------------------------------------------- + */ + +extern PENUMCONNDATA _ObjHlpAllocateEnumConnData(IMalloc *pAllocator, UINT32 nCapacity); +extern void _ObjHlpAddToEnumConnData(PENUMCONNDATA pecd, IUnknown *pUnk, UINT32 uiCookie); +extern void _ObjHlpDiscardEnumConnData(PENUMCONNDATA pecd); +extern PENUMCONN _ObjHlpAllocateEnumConn(IMalloc *pAllocator, PENUMCONNDATA pecd, UINT32 nCurrent); + +#endif /* __ASM__ */ + +#endif /* __COMROGUE_INTERNALS__ */ + +#endif /* __ENUMCONN_H_INCLUDED */ diff --git a/kernel/lib/enumgeneric.h b/kernel/lib/enumgeneric.h new file mode 100644 index 0000000..4e57928 --- /dev/null +++ b/kernel/lib/enumgeneric.h @@ -0,0 +1,78 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#ifndef __ENUMGENERIC_H_INCLUDED +#define __ENUMGENERIC_H_INCLUDED + +#ifdef __COMROGUE_INTERNALS__ + +#ifndef __ASM__ + +#include +#include +#include + +/*--------------------------------------------------------------------------------------------------- + * Data structures for implementing IEnumUnknown or any interface that enumerates interface pointers + *--------------------------------------------------------------------------------------------------- + */ + +typedef struct tagENUMGENERICDATA { + UINT32 uiRefCount; /* reference count */ + UINT32 nObjects; /* count of IUnknown pointers */ + PUNKNOWN rgObjects[0]; /* array of IUnknown pointers */ +} ENUMGENERICDATA, *PENUMGENERICDATA; + +typedef struct tagENUMGENERIC { + IEnumUnknown enumUnknown; /* interface pointer */ + UINT32 uiRefCount; /* reference count */ + REFIID riidActual; /* IID of actual interface */ + UINT32 nCurrent; /* current pointer into array */ + PENUMGENERICDATA pPayload; /* payload array */ + IMalloc *pAllocator; /* allocator pointer */ +} ENUMGENERIC, *PENUMGENERIC; + +/*--------------------------------------------------------------------------------------------- + * Functions for implementing IEnumUnknown or any interface that enumerates interface pointers + *--------------------------------------------------------------------------------------------- + */ + +extern PENUMGENERICDATA _ObjHlpAllocateEnumGenericData(IMalloc *pAllocator, UINT32 nCapacity); +extern void _ObjHlpAddToEnumGenericData(PENUMGENERICDATA pegd, IUnknown *pUnk); +extern void _ObjHlpDiscardEnumGenericData(PENUMGENERICDATA pecd); +extern PENUMGENERIC _ObjHlpAllocateEnumGeneric(IMalloc *pAllocator, REFIID riidActual, PENUMGENERICDATA pegd, + UINT32 nCurrent); + +#endif /* __ASM__ */ + +#endif /* __COMROGUE_INTERNALS__ */ + +#endif /* __ENUMGENERIC_H_INCLUDED */ diff --git a/kernel/lib/heap_internals.h b/kernel/lib/heap_internals.h index 88f5261..2ba5854 100644 --- a/kernel/lib/heap_internals.h +++ b/kernel/lib/heap_internals.h @@ -35,10 +35,15 @@ #ifndef __HEAP_INTERNALS_H_INCLUDED #define __HEAP_INTERNALS_H_INCLUDED +#ifdef __COMROGUE_INTERNALS__ + +#ifndef __ASM__ + #include #include #include #include +#include /*---------------------------------- * The actual heap data declaration @@ -49,8 +54,17 @@ typedef struct tagHEAPDATA { IMalloc mallocInterface; /* pointer to IMalloc interface - MUST BE FIRST! */ IConnectionPointContainer cpContainerInterface; /* pointer to IConnectionPointContainer interface */ UINT32 uiRefCount; /* reference count */ + UINT32 uiFlags; /* flags word */ PFNRAWHEAPDATAFREE pfnFreeRawHeapData; /* pointer to function that frees the raw heap data, if any */ IChunkAllocator *pChunkAllocator; /* chunk allocator pointer */ + FIXEDCPDATA fcpMallocSpy; /* connection point for IMallocSpy */ + FIXEDCPDATA fcpSequentialStream; /* connection point for ISequentialStream for debugging */ + IMallocSpy *pMallocSpy; /* IMallocSpy interface for the allocator */ + ISequentialStream *pDebugStream; /* debugging output stream */ } HEAPDATA, *PHEAPDATA; +#endif /* __ASM__ */ + +#endif /* __COMROGUE_INTERNALS__ */ + #endif /* __HEAP_INTERNALS_H_INCLUDED */ diff --git a/kernel/lib/heap_toplevel.c b/kernel/lib/heap_toplevel.c index d9f59ff..0e3d8ff 100644 --- a/kernel/lib/heap_toplevel.c +++ b/kernel/lib/heap_toplevel.c @@ -41,6 +41,8 @@ #include #include "heap_internals.h" +#define PHDFLAGS_DELETING 0x80000000 /* deleting the heap */ + /*------------------------ * IMalloc implementation *------------------------ @@ -105,8 +107,11 @@ static UINT32 malloc_Release(IUnknown *pThis) PFNRAWHEAPDATAFREE pfnFree; /* pointer to "free" function */ rc = --(phd->uiRefCount); - if (rc == 0) + if ((rc == 0) && !(phd->uiFlags & PHDFLAGS_DELETING)) { + phd->uiFlags |= PHDFLAGS_DELETING; + ObjHlpFixedCpTeardown(&(phd->fcpMallocSpy)); + ObjHlpFixedCpTeardown(&(phd->fcpSequentialStream)); IUnknown_Release(phd->pChunkAllocator); if (phd->pfnFreeRawHeapData) { @@ -218,12 +223,26 @@ static UINT32 cpc_Release(IUnknown *pThis) static HRESULT cpc_EnumConnectionPoints(IConnectionPointContainer *pThis, IEnumConnectionPoints **ppEnum) { + PHEAPDATA phd = (PHEAPDATA)HeapDataPtr(pThis); /* pointer to heap data */ + return E_NOTIMPL; /* TODO */ } static HRESULT cpc_FindConnectionPoint(IConnectionPointContainer *pThis, REFIID riid, IConnectionPoint **ppCP) { - return E_NOTIMPL; /* TODO */ + PHEAPDATA phd = (PHEAPDATA)HeapDataPtr(pThis); /* pointer to heap data */ + + if (!ppCP) + return E_POINTER; + *ppCP = NULL; + if (IsEqualIID(riid, &IID_IMallocSpy)) + *ppCP = (IConnectionPoint *)(&(phd->fcpMallocSpy)); + else if (IsEqualIID(riid, &IID_ISequentialStream)) + *ppCP = (IConnectionPoint *)(&(phd->fcpSequentialStream)); + else + return CONNECT_E_NOCONNECTION; + IUnknown_AddRef(*ppCP); + return S_OK; } /* The IConnectionPointContainer vtable. */ @@ -272,9 +291,13 @@ HRESULT HeapCreate(PRAWHEAPDATA prhd, PFNRAWHEAPDATAFREE pfnFree, IChunkAllocato phd->mallocInterface.pVTable = &vtblMalloc; phd->cpContainerInterface.pVTable = &vtblConnectionPointContainer; phd->uiRefCount = 1; + phd->uiFlags = 0; phd->pfnFreeRawHeapData = pfnFree; phd->pChunkAllocator = pChunkAllocator; IUnknown_AddRef(phd->pChunkAllocator); + ObjHlpFixedCpSetup(&(phd->fcpMallocSpy), (PUNKNOWN)phd, &IID_IMallocSpy, (IUnknown **)(&(phd->pMallocSpy)), 1, NULL); + ObjHlpFixedCpSetup(&(phd->fcpSequentialStream), (PUNKNOWN)phd, &IID_ISequentialStream, + (IUnknown **)(&(phd->pDebugStream)), 1, NULL); *ppHeap = (IMalloc *)phd; return S_OK; diff --git a/kernel/lib/objhelp.c b/kernel/lib/objhelp.c index 4f60cb5..27f5aa2 100644 --- a/kernel/lib/objhelp.c +++ b/kernel/lib/objhelp.c @@ -94,6 +94,7 @@ HRESULT ObjHlpStandardQueryInterface_ ## iface (IUnknown *pThis, REFIID riid, PP } MAKE_BASE_QI(IConnectionPoint) +MAKE_BASE_QI(IEnumConnections) MAKE_BASE_QI(IMalloc) MAKE_BASE_QI(ISequentialStream) diff --git a/kernel/lib/objhelp_enumconn.c b/kernel/lib/objhelp_enumconn.c new file mode 100644 index 0000000..bb3693e --- /dev/null +++ b/kernel/lib/objhelp_enumconn.c @@ -0,0 +1,319 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include "enumconn.h" + +/*------------------------------------------- + * IEnumConnections interface implementation + *------------------------------------------- + */ + +/* + * Adds a reference to the enumerator object. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumConnections interface pointer). + * + * Returns: + * The new reference count on the object. + */ +static UINT32 enumConn_AddRef(IUnknown *pThis) +{ + return ++(((PENUMCONN)pThis)->uiRefCount); +} + +/* + * Removes a reference from the enumerator object. The object is freed when its reference count reaches 0. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumConnections interface pointer). + * + * Returns: + * The new reference count on the object. + */ +static UINT32 enumConn_Release(IUnknown *pThis) +{ + register PENUMCONN pec = (PENUMCONN)pThis; /* pointer to actual data block */ + register UINT32 rc; /* return from this function */ + IMalloc *pAllocator; /* temporary for allocator */ + PENUMCONNDATA pecd; /* temporary for underlying connections data block */ + + rc = --(pec->uiRefCount); + if (rc == 0) + { /* save off allocator before deallocating */ + pAllocator = pec->pAllocator; + IUnknown_AddRef(pAllocator); + /* save off payload too */ + pecd = pec->pPayload; + /* erase enumerator */ + IUnknown_Release(pec->pAllocator); + IMalloc_Free(pAllocator, pec); + if (--(pecd->uiRefCount) == 0) + { /* we need to erase the data block too */ + _ObjHlpDiscardEnumConnData(pecd); + IMalloc_Free(pAllocator, pecd); + } + IUnknown_Release(pAllocator); /* release temporary reference we added */ + } + return rc; +} + +/* + * Retrieves the next number of connections in the enumeration sequence. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumConnections interface pointer). + * - cConnections = Number of connections to be retrieved. If there are more than this many connections + * in the enumeration sequence, this many are returned. + * - rgcd = Array of enumerated items which will be filled in by this function. Note that the caller is + * responsible for releasing all interface pointers returned as a result of this call. + * - pcFetched = Pointer to a variable which will receive the number of connections retrieved. This value will + * always be less than or equal to cConnections. + * + * Returns: + * - S_OK = All the connections requested were retrieved. *pcFetched is equal to cConnections. + * - S_FALSE = Not all the connections requested could be retrieved. *pcFetched is less than cConnections. + * - Other = An error result. + */ +static HRESULT enumConn_Next(IEnumConnections *pThis, UINT32 cConnections, PCONNECTDATA rgcd, UINT32 *pcFetched) +{ + register PENUMCONN pec = (PENUMCONN)pThis; /* pointer to data block */ + register UINT32 i; /* loop counter */ + + if (cConnections == 0) + { /* nothing to retrieve */ + if (pcFetched) + *pcFetched = 0; + return S_OK; + } + + if (!pcFetched) + return E_POINTER; /* invalid pointer */ + + /* get number of items to fetch */ + *pcFetched = intMin(pec->pPayload->nConnectData - pec->nCurrent, cConnections); + for (i = 0; i < *pcFetched; i++) + { /* fetch the items */ + rgcd[i].pUnk = pec->pPayload->rgConnectData[i + pec->nCurrent].pUnk; + IUnknown_AddRef(rgcd[i].pUnk); + rgcd[i].uiCookie = pec->pPayload->rgConnectData[i + pec->nCurrent].uiCookie; + } + + pec->nCurrent += *pcFetched; /* advance pointer */ + return (*pcFetched == cConnections) ? S_OK : S_FALSE; +} + +/* + * Skips over the next number of connections in the enumeration sequence. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumConnections interface pointer). + * - cConnections = Number of connections to be skipped. If there are fewer than this many connections + * in the enumeration sequence, we skip straight to the end. + * + * Returns: + * - S_OK = We were able to skip over all the specified items. + * - S_FALSE = We were not able to skip over all the specified items. The current position of the enumeration + * is at the end of the sequence. + */ +static HRESULT enumConn_Skip(IEnumConnections *pThis, UINT32 cConnections) +{ + register PENUMCONN pec = (PENUMCONN)pThis; /* pointer to data block */ + register HRESULT rc = S_OK; /* return from this function */ + + pec->nCurrent += cConnections; + if (pec->nCurrent > pec->pPayload->nConnectData) + { /* clamp current pointer and return FALSE */ + pec->nCurrent = pec->pPayload->nConnectData; + rc = S_FALSE; + } + return rc; +} + +/* + * Resets the enumeration sequence to the beginning. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumConnections interface pointer). + * + * Returns: + * S_OK. + */ +static HRESULT enumConn_Reset(IEnumConnections *pThis) +{ + ((PENUMCONN)pThis)->nCurrent = 0; + return S_OK; +} + +/* + * Creates a new enumerator with the same state as the current one. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumConnections interface pointer). + * - ppEnum = Pointer to variable to receive the new enumerator object. The caller is responsible for releasing + * this pointer. + * + * Returns: + * - S_OK = Success. + * - E_INVALIDARG = The pointer argument is not valid. + * - E_OUTOFMEMORY = The memory for a new enumerator could not be allocated. + */ +static HRESULT enumConn_Clone(IEnumConnections *pThis, IEnumConnections **ppEnum) +{ + register PENUMCONN pec = (PENUMCONN)pThis; /* pointer to data block */ + register PENUMCONN pecNew; /* pointer to new enumerator */ + + if (!ppEnum) /* no pointer? */ + return E_INVALIDARG; + *ppEnum = NULL; + pecNew = _ObjHlpAllocateEnumConn(pec->pAllocator, pec->pPayload, pec->nCurrent); + if (!pecNew) /* failed to allocate? */ + return E_OUTOFMEMORY; + IUnknown_QueryInterface((IUnknown *)pecNew, &IID_IEnumConnections, (PPVOID)ppEnum); + return S_OK; +} + +/* The VTable for the IEnumConnections interface. */ +static const SEG_RODATA struct IEnumConnectionsVTable vtblEnumConnections = +{ + .QueryInterface = ObjHlpStandardQueryInterface_IEnumConnections, + .AddRef = enumConn_AddRef, + .Release = enumConn_Release, + .Next = enumConn_Next, + .Skip = enumConn_Skip, + .Reset = enumConn_Reset, + .Clone = enumConn_Clone +}; + +/*----------------------------------- + * IEnumConnections helper functions + *----------------------------------- + */ + +/* + * Allocate the "inner" connection data object for an enumerator. + * + * Parameters: + * - pAllocator = Allocator to use to allocate the memory. + * - nCapacity = Number of slots to allocate for the connection data. + * + * Returns: + * - NULL = The data object could not be allocated. + * - Other = Pointer to the new data object. Its reference count is 0 and it contains no elements. + */ +PENUMCONNDATA _ObjHlpAllocateEnumConnData(IMalloc *pAllocator, UINT32 nCapacity) +{ + register PENUMCONNDATA rc; /* return from this function */ + register SIZE_T cbReturn = sizeof(ENUMCONNDATA) + (nCapacity * sizeof(CONNECTDATA)); /* bytes to allocate */ + + rc = (PENUMCONNDATA)(IMalloc_Alloc(pAllocator, cbReturn)); + if (rc != NULL) + { + StrSetMem(rc, 0, cbReturn); + rc->uiRefCount = 0; + rc->nConnectData = 0; + } + return rc; +} + +/* + * Add an element to the specified "inner" connection data object. Used when building the object. + * + * Parameters: + * - pecd = Pointer to the connection data object. + * - pUnk = IUnknown pointer to add to the "next" slot. A reference is added to this pointer. + * - uiCookie = Cookie value to add to the "next" slot. + * + * Returns: + * Nothing. + */ +void _ObjHlpAddToEnumConnData(PENUMCONNDATA pecd, IUnknown *pUnk, UINT32 uiCookie) +{ + pecd->rgConnectData[pecd->nConnectData].pUnk = pUnk; + IUnknown_AddRef(pecd->rgConnectData[pecd->nConnectData].pUnk); + pecd->rgConnectData[pecd->nConnectData].uiCookie = uiCookie; + pecd->nConnectData++; +} + +/* + * Discards the contents of an "inner" connection data object by releasing all the interface pointers + * it contains. + * + * Parameters: + * - pecd = Pointer to the connection data object. + * + * Returns: + * Nothing. + */ +void _ObjHlpDiscardEnumConnData(PENUMCONNDATA pecd) +{ + register UINT32 i; /* loop counter */ + + for (i = 0; i < pecd->nConnectData; i++) + IUnknown_Release(pecd->rgConnectData[i].pUnk); +} + +/* + * Allocates a new "enumerator" data object. + * + * Parameters: + * - pAllocator = Allocator to use to allocate the memory. + * - pecd = Pointer to the "inner" connection data object to be used. + * - nCurrent = Value to set the "current" element pointer to. + * + * Returns: + * - NULL = The enumerator object could not be allocated. + * - Other = Pointer to the new enumerator object. Its reference count is 0. + */ +PENUMCONN _ObjHlpAllocateEnumConn(IMalloc *pAllocator, PENUMCONNDATA pecd, UINT32 nCurrent) +{ + register PENUMCONN rc; /* return from this function */ + + rc = (PENUMCONN)(IMalloc_Alloc(pAllocator, sizeof(ENUMCONN))); + if (rc) + { /* initialize all the fields */ + rc->enumConnections.pVTable = &vtblEnumConnections; + rc->uiRefCount = 0; + rc->nCurrent = nCurrent; + rc->pPayload = pecd; + pecd->uiRefCount++; + rc->pAllocator = pAllocator; + IUnknown_AddRef(rc->pAllocator); + } + return rc; +} diff --git a/kernel/lib/objhelp_enumgeneric.c b/kernel/lib/objhelp_enumgeneric.c new file mode 100644 index 0000000..f6d5a69 --- /dev/null +++ b/kernel/lib/objhelp_enumgeneric.c @@ -0,0 +1,222 @@ +/* + * This file is part of the COMROGUE Operating System for Raspberry Pi + * + * Copyright (c) 2013, Eric J. Bowersox / Erbosoft Enterprises + * All rights reserved. + * + * This program is free for commercial and non-commercial use as long as the following conditions are + * adhered to. + * + * Copyright in this file remains Eric J. Bowersox and/or Erbosoft, and as such any copyright notices + * in the code are not to be removed. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and + * the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * "Raspberry Pi" is a trademark of the Raspberry Pi Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include "enumgeneric.h" + +/*--------------------------------------- + * IEnumUnknown interface implementation + *--------------------------------------- + */ + +static HRESULT enumGeneric_QueryInterface(IUnknown *pThis, REFIID riid, PPVOID ppvObject) +{ + PENUMGENERIC peg = (PENUMGENERIC)pThis; + + if (!ppvObject) + return E_POINTER; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, peg->riidActual)) + { + *ppvObject = pThis; + IUnknown_AddRef((PUNKNOWN)(*ppvObject)); + return S_OK; + } + + *ppvObject = NULL; + return E_NOINTERFACE; +} + +static UINT32 enumGeneric_AddRef(IUnknown *pThis) +{ + return ++(((PENUMGENERIC)pThis)->uiRefCount); +} + +static UINT32 enumGeneric_Release(IUnknown *pThis) +{ + register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to actual data block */ + register UINT32 rc; /* return from this function */ + IMalloc *pAllocator; /* temporary for allocator */ + PENUMGENERICDATA pegd; /* temporary for underlying objects data block */ + + rc = --(peg->uiRefCount); + if (rc == 0) + { /* save off allocator before deallocating */ + pAllocator = peg->pAllocator; + IUnknown_AddRef(pAllocator); + /* save off payload too */ + pegd = peg->pPayload; + /* erase enumerator */ + IUnknown_Release(peg->pAllocator); + IMalloc_Free(pAllocator, peg); + if (--(pegd->uiRefCount) == 0) + { /* we need to erase the data block too */ + _ObjHlpDiscardEnumGenericData(pegd); + IMalloc_Free(pAllocator, pegd); + } + IUnknown_Release(pAllocator); /* release temporary reference we added */ + } + return rc; +} + +static HRESULT enumGeneric_Next(IEnumUnknown *pThis, UINT32 celt, IUnknown **rgelt, UINT32 *pceltFetched) +{ + register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to data block */ + register UINT32 i; /* loop counter */ + + if (celt == 0) + { /* nothing to retrieve */ + if (pceltFetched) + *pceltFetched = 0; + return S_OK; + } + + if (!pceltFetched) + return E_POINTER; /* invalid pointer */ + + /* get number of items to fetch */ + *pceltFetched = intMin(peg->pPayload->nObjects - peg->nCurrent, celt); + for (i = 0; i < *pceltFetched; i++) + { /* fetch the items */ + rgelt[i] = peg->pPayload->rgObjects[i + peg->nCurrent]; + IUnknown_AddRef(rgelt[i]); + } + + peg->nCurrent += *pceltFetched; /* advance pointer */ + return (*pceltFetched == celt) ? S_OK : S_FALSE; +} + +static HRESULT enumGeneric_Skip(IEnumUnknown *pThis, UINT32 celt) +{ + register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to data block */ + register HRESULT rc = S_OK; /* return from this function */ + + peg->nCurrent += celt; + if (peg->nCurrent > peg->pPayload->nObjects) + { /* clamp current pointer and return FALSE */ + peg->nCurrent = peg->pPayload->nObjects; + rc = S_FALSE; + } + return rc; +} + +static HRESULT enumGeneric_Reset(IEnumUnknown *pThis) +{ + ((PENUMGENERIC)pThis)->nCurrent = 0; + return S_OK; +} + +static HRESULT enumGeneric_Clone(IEnumUnknown *pThis, IEnumUnknown **ppEnum) +{ + register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to data block */ + register PENUMGENERIC pegNew; /* pointer to new enumerator */ + + if (!ppEnum) /* no pointer? */ + return E_INVALIDARG; + *ppEnum = NULL; + pegNew = _ObjHlpAllocateEnumGeneric(peg->pAllocator, peg->riidActual, peg->pPayload, peg->nCurrent); + if (!pegNew) /* failed to allocate? */ + return E_OUTOFMEMORY; + IUnknown_QueryInterface((IUnknown *)pegNew, peg->riidActual, (PPVOID)ppEnum); + return S_OK; +} + +static const SEG_RODATA struct IEnumUnknownVTable vtblEnum = +{ + .QueryInterface = enumGeneric_QueryInterface, + .AddRef = enumGeneric_AddRef, + .Release = enumGeneric_Release, + .Next = enumGeneric_Next, + .Skip = enumGeneric_Skip, + .Reset = enumGeneric_Reset, + .Clone = enumGeneric_Clone +}; + +/*--------------------------------- + * IEnum[Generic] helper functions + *--------------------------------- + */ + +PENUMGENERICDATA _ObjHlpAllocateEnumGenericData(IMalloc *pAllocator, UINT32 nCapacity) +{ + register PENUMGENERICDATA rc; /* return from this function */ + register SIZE_T cbReturn = sizeof(ENUMGENERICDATA) + (nCapacity * sizeof(PUNKNOWN)); /* bytes to allocate */ + + rc = (PENUMGENERICDATA)(IMalloc_Alloc(pAllocator, cbReturn)); + if (rc != NULL) + { + StrSetMem(rc, 0, cbReturn); + rc->uiRefCount = 0; + rc->nObjects = 0; + } + return rc; + +} + +void _ObjHlpAddToEnumGenericData(PENUMGENERICDATA pegd, IUnknown *pUnk) +{ + pegd->rgObjects[pegd->nObjects] = pUnk; + IUnknown_AddRef(pegd->rgObjects[pegd->nObjects]); + pegd->nObjects++; +} + +void _ObjHlpDiscardEnumGenericData(PENUMGENERICDATA pegd) +{ + register UINT32 i; /* loop counter */ + + for (i = 0; i < pegd->nObjects; i++) + IUnknown_Release(pegd->rgObjects[i]); +} + +PENUMGENERIC _ObjHlpAllocateEnumGeneric(IMalloc *pAllocator, REFIID riidActual, PENUMGENERICDATA pegd, + UINT32 nCurrent) +{ + register PENUMGENERIC rc; /* return from this function */ + + rc = (PENUMGENERIC)(IMalloc_Alloc(pAllocator, sizeof(ENUMGENERIC))); + if (rc) + { /* initialize all the fields */ + rc->enumUnknown.pVTable = &vtblEnum; + rc->uiRefCount = 0; + rc->riidActual = riidActual; + rc->nCurrent = nCurrent; + rc->pPayload = pegd; + pegd->uiRefCount++; + rc->pAllocator = pAllocator; + IUnknown_AddRef(rc->pAllocator); + } + return rc; +} diff --git a/kernel/lib/objhelp_fixedcp.c b/kernel/lib/objhelp_fixedcp.c index 231b215..124c8e3 100644 --- a/kernel/lib/objhelp_fixedcp.c +++ b/kernel/lib/objhelp_fixedcp.c @@ -34,22 +34,54 @@ #include #include #include +#include "enumconn.h" + +/* Mask we XOR with the index of the slot plus 1. */ +#define FIXEDCP_MASK 0x4669782A /* "Fix*" */ /*--------------------------------------------- * IConnectionPoint vtable and implementations *--------------------------------------------- */ +/* + * Adds a reference to the connection point object. + * + * Parameters: + * - pThis = Pointer to the connection point object (actually its IConnectionPoint interface pointer). + * + * Returns: + * The new reference count on the object. + */ static UINT32 fixedcp_AddRef(IUnknown *pThis) { return IUnknown_AddRef(((PFIXEDCPDATA)pThis)->punkOuter); } +/* + * Removes a reference from the connection point object. The object is freed when its reference count reaches 0. + * + * Parameters: + * - pThis = Pointer to the connection point object (actually its IConnectionPoint interface pointer). + * + * Returns: + * The new reference count on the object. + */ static UINT32 fixedcp_Release(IUnknown *pThis) { return IUnknown_Release(((PFIXEDCPDATA)pThis)->punkOuter); } +/* + * Retrieves the IID of the outgoing interface managed by this connection point. + * + * Parameters: + * - pThis = Pointer to the connection point object (actually its IConnectionPoint interface pointer). + * - pIID = Pointer to buffer to receive the IID of the outgoing interface managed by this connection point. + * + * Returns: + * Standard HRESULT success/failure indicator. + */ static HRESULT fixedcp_GetConnectionInterface(IConnectionPoint *pThis, IID *pIID) { if (!pIID) @@ -58,7 +90,18 @@ static HRESULT fixedcp_GetConnectionInterface(IConnectionPoint *pThis, IID *pIID return S_OK; } -static HRESULT fixedcp_GetConnectionPointContainer(IConnectionPoint *pThis, IConnectionPointContainer *ppCPC) +/* + * Retrieves the IConnectionPointContainer interface for this connection point's parent connectable object. + * + * Parameters: + * - pThis = Pointer to the connection point object (actually its IConnectionPoint interface pointer). + * - ppCPC = Pointer to variable to receive the IConnectionPointContainer interface. The caller is responsible + * for releasing this interface pointer. + * + * Returns: + * Standard HRESULT success/failure indicator. + */ +static HRESULT fixedcp_GetConnectionPointContainer(IConnectionPoint *pThis, IConnectionPointContainer **ppCPC) { register HRESULT rc; /* return from underlying QI */ @@ -68,19 +111,132 @@ static HRESULT fixedcp_GetConnectionPointContainer(IConnectionPoint *pThis, ICon return rc; } +/* + * Establishes a connection between the connection point and an event sink interface. + * + * Parameters: + * - pThis = Pointer to the connection point object (actually its IConnectionPoint interface pointer). + * - punkSink = Pointer to the event sink interface to attach. + * - puiCookie = Pointer to a variable to receive a "cookie" that can later be used with the Unadvise method + * on this interface to delete the connection. + * + * Returns: + * - S_OK = Connection established; *puiCookie contains the connection cookie. + * - E_POINTER = Either punkSink or puiCookie is invalid. + * - CONNECT_E_ADVISELIMIT = The connection point cannot accept any more connections. + * - CONNECT_E_CANNOTCONNECT = The event sink does not support the correct interface. + */ static HRESULT fixedcp_Advise(IConnectionPoint *pThis, IUnknown *punkSink, UINT32 *puiCookie) { - return E_NOTIMPL; /* TODO */ + register PFIXEDCPDATA pData; /* pointer to actual data block */ + register UINT32 i; /* index of slot to put sink in */ + IUnknown *punkActualSink = NULL; /* actual sink pointer */ + + if (!punkSink || !puiCookie) + return E_POINTER; /* bogus */ + *puiCookie = 0; + + pData = (PFIXEDCPDATA)pThis; + if (pData->ncpSize == pData->ncpCapacity) + return CONNECT_E_ADVISELIMIT; /* too many connections */ + + if (FAILED(IUnknown_QueryInterface(punkSink, pData->riidConnection, (PPVOID)(&punkActualSink)))) + return CONNECT_E_CANNOTCONNECT; /* cannot QI for our interface */ + + for (i = 0; i < pData->ncpCapacity; i++) + { /* search for a slot */ + if (!(pData->ppSlots[i])) + { /* found slot, store sink */ + pData->ppSlots[i] = punkActualSink; + *puiCookie = (UINT32)((i + 1) ^ FIXEDCP_MASK); + pData->ncpSize++; + return S_OK; + } + } + + /* slot not found?!? */ + IUnknown_Release(punkActualSink); + return E_UNEXPECTED; } +/* + * Terminates a previously-established connection between the connection point and an event sink interface. + * + * Parameters: + * - pThis = Pointer to the connection point object (actually its IConnectionPoint interface pointer). + * - uiCookie = Cookie previously returned by the Advise method on this interface. + * + * Returns: + * - S_OK = Connection was terminated successfully. + * - E_POINTER = The cookie value is invalid. + */ static HRESULT fixedcp_Unadvise(IConnectionPoint *pThis, UINT32 uiCookie) { - return E_NOTIMPL; /* TODO */ + register PFIXEDCPDATA pData = (PFIXEDCPDATA)pThis; /* pointer to actual data block */ + register UINT32 i; /* index of slot sink is in */ + + /* Decode the cookie value */ + i = (UINT32)(uiCookie ^ FIXEDCP_MASK) - 1; + if ((i < 0) || (i >= pData->ncpCapacity) || !(pData->ppSlots[i])) + return E_POINTER; + + /* Free up the slot */ + IUnknown_Release(pData->ppSlots[i]); + pData->ppSlots[i] = NULL; + pData->ncpSize--; + return S_OK; } +/* + * Creates an enumerator object to iterate through the current connections on this connection point. + * + * Parameters: + * - pThis = Pointer to the connection point object (actually its IConnectionPoint interface pointer). + * - ppEnum = Pointer to variable to receive the enumerator object interface. The caller is responsible for + * releasing this object when it's no longer needed. + * + * Returns: + * - S_OK = Created the enumerator successfully. + * - E_NOTIMPL = Enumeration is not supported. + * - E_POINTER = ppEnum was not a valid pointer. + * - E_OUTOFMEMORY = Could not allocate the enumerator. + */ static HRESULT fixedcp_EnumConnections(IConnectionPoint *pThis, IEnumConnections **ppEnum) { - return E_NOTIMPL; /* TODO */ + register PFIXEDCPDATA pData = (PFIXEDCPDATA)pThis; /* pointer to actual data block */ + PENUMCONNDATA pecd; /* pointer to enumeration data */ + PENUMCONN pec; /* pointer to enumerator */ + register UINT32 i; /* loop counter */ + + if (!(pData->pAllocator)) + return E_NOTIMPL; /* enumeration not implemented */ + + if (!ppEnum) + return E_POINTER; /* bad return pointer */ + *ppEnum = NULL; + + /* Allocate a data block. */ + pecd = _ObjHlpAllocateEnumConnData(pData->pAllocator, pData->ncpSize); + if (!pecd) + return E_OUTOFMEMORY; + + /* Fill the allocated data block. */ + for (i = 0; i < pData->ncpCapacity; i++) + if (pData->ppSlots[i]) + _ObjHlpAddToEnumConnData(pecd, pData->ppSlots[i], (UINT32)((i + 1) ^ FIXEDCP_MASK)); + + /* Allocate the enumerator. */ + pec = _ObjHlpAllocateEnumConn(pData->pAllocator, pecd, 0); + if (pec) + { /* QI it for our return value */ + IUnknown_QueryInterface((IUnknown *)pec, &IID_IEnumConnections, (PPVOID)ppEnum); + return S_OK; + } + + /* unable to allocate enumerator - bug out */ + _ObjHlpDiscardEnumConnData(pecd); + IMalloc_Free(pData->pAllocator, pecd); + return E_OUTOFMEMORY; } /* VTable for the fixed-size connection point implementation. */ @@ -101,8 +257,23 @@ static const SEG_RODATA struct IConnectionPointVTable vtblFixedCP = *----------------------------------------------- */ +/* + * Sets up a fixed-size connection point object. + * + * Parameters: + * - pData = Pointer to the data block to initialize. + * - punkOuter = Pointer to "outer unknown" for the connection point, which must implement IConnectionPointContainer. + * - riidConnection = Reference to the IID of the outgoing event interface. + * - ppSlots = Pointer to the array of IUnknown "slots" used by this connection point. + * - nSlots = Number of slots to allocate. + * - pAllocator = Pointer to a memory allocator to use to allocate enumerators. This may be NULL if you don't + * want to support enumeration. + * + * Returns: + * Nothing. + */ void ObjHlpFixedCpSetup(PFIXEDCPDATA pData, PUNKNOWN punkOuter, REFIID riidConnection, - IUnknown **ppSlots, INT32 nSlots) + IUnknown **ppSlots, UINT32 nSlots, IMalloc *pAllocator) { pData->connectionPointInterface.pVTable = &vtblFixedCP; pData->punkOuter = punkOuter; @@ -110,15 +281,29 @@ void ObjHlpFixedCpSetup(PFIXEDCPDATA pData, PUNKNOWN punkOuter, REFIID riidConne pData->ppSlots = ppSlots; pData->ncpSize = 0; pData->ncpCapacity = nSlots; + pData->pAllocator = pAllocator; + if (pData->pAllocator) + IUnknown_AddRef(pData->pAllocator); StrSetMem(ppSlots, 0, nSlots * sizeof(IUnknown *)); } +/* + * Tears down a fixed-size connection-point object. + * + * Parameters: + * - pData = Pointer to the data block to destroy. + * + * Returns: + * Nothing. + */ void ObjHlpFixedCpTeardown(PFIXEDCPDATA pData) { - register INT32 i; /* loop counter */ + register UINT32 i; /* loop counter */ for (i = 0; i < pData->ncpCapacity; i++) if (pData->ppSlots[i]) IUnknown_Release(pData->ppSlots[i]); + if (pData->pAllocator) + IUnknown_Release(pData->pAllocator); StrSetMem(pData, 0, sizeof(FIXEDCPDATA)); } diff --git a/kernel/lib/rbtree.c b/kernel/lib/rbtree.c index dfea2db..f693195 100644 --- a/kernel/lib/rbtree.c +++ b/kernel/lib/rbtree.c @@ -82,7 +82,7 @@ INT32 RbtStdCompareByValue(TREEKEY k1, TREEKEY k2) static PRBTREENODE rotate_left(PRBTREENODE ptn) { register PRBTREENODE ptnNewRoot = rbtNodeRight(ptn); - ASSERT(ptnNewRoot); + //ASSERT(ptnNewRoot); rbtSetNodeRight(ptn, ptnNewRoot->ptnLeft); ptnNewRoot->ptnLeft = ptn; rbtSetNodeColor(ptnNewRoot, rbtNodeColor(ptn)); @@ -103,7 +103,7 @@ static PRBTREENODE rotate_left(PRBTREENODE ptn) static PRBTREENODE rotate_right(PRBTREENODE ptn) { register PRBTREENODE ptnNewRoot = ptn->ptnLeft; - ASSERT(ptnNewRoot); + //ASSERT(ptnNewRoot); ptn->ptnLeft = rbtNodeRight(ptnNewRoot); rbtSetNodeRight(ptnNewRoot, ptn); rbtSetNodeColor(ptnNewRoot, rbtNodeColor(ptn)); @@ -172,7 +172,7 @@ static PRBTREENODE insert_under(PRBTREE ptree, PRBTREENODE ptnCurrent, PRBTREENO if (!ptnCurrent) return ptnNew; /* degenerate case */ cmp = (*(ptree->pfnTreeCompare))(ptnNew->treekey, ptnCurrent->treekey); - ASSERT(cmp != 0); + //ASSERT(cmp != 0); if (cmp < 0) ptnCurrent->ptnLeft = insert_under(ptree, ptnCurrent->ptnLeft, ptnNew); else