diff --git a/kernel/lib/enumgeneric.h b/kernel/lib/enumgeneric.h index 4e57928..8026287 100644 --- a/kernel/lib/enumgeneric.h +++ b/kernel/lib/enumgeneric.h @@ -47,6 +47,7 @@ typedef struct tagENUMGENERICDATA { UINT32 uiRefCount; /* reference count */ + REFIID riidObjects; /* IID of underlying objects */ UINT32 nObjects; /* count of IUnknown pointers */ PUNKNOWN rgObjects[0]; /* array of IUnknown pointers */ } ENUMGENERICDATA, *PENUMGENERICDATA; @@ -65,9 +66,9 @@ typedef struct tagENUMGENERIC { *--------------------------------------------------------------------------------------------- */ -extern PENUMGENERICDATA _ObjHlpAllocateEnumGenericData(IMalloc *pAllocator, UINT32 nCapacity); +extern PENUMGENERICDATA _ObjHlpAllocateEnumGenericData(IMalloc *pAllocator, REFIID riidObjects, UINT32 nCapacity); extern void _ObjHlpAddToEnumGenericData(PENUMGENERICDATA pegd, IUnknown *pUnk); -extern void _ObjHlpDiscardEnumGenericData(PENUMGENERICDATA pecd); +extern void _ObjHlpDiscardEnumGenericData(PENUMGENERICDATA pegd); extern PENUMGENERIC _ObjHlpAllocateEnumGeneric(IMalloc *pAllocator, REFIID riidActual, PENUMGENERICDATA pegd, UINT32 nCurrent); diff --git a/kernel/lib/heap_toplevel.c b/kernel/lib/heap_toplevel.c index 0e3d8ff..a4ae160 100644 --- a/kernel/lib/heap_toplevel.c +++ b/kernel/lib/heap_toplevel.c @@ -40,6 +40,7 @@ #include #include #include "heap_internals.h" +#include "enumgeneric.h" #define PHDFLAGS_DELETING 0x80000000 /* deleting the heap */ @@ -221,13 +222,64 @@ static UINT32 cpc_Release(IUnknown *pThis) return malloc_Release((IUnknown *)HeapDataPtr(pThis)); } +/* + * Creates an enumerator object to iterate through all the connection points in this container. + * + * Parameters: + * - pThis = Pointer to the ConnectionPointContainer interface in the heap data object. + * - ppEnum = Pointer to a variable to receive a new reference to IEnumConnectionPoints. + * + * Returns: + * - S_OK = Enumerator created successfully; pointer to it in *ppEnum. + * - E_OUTOFMEMORY = Unable to allocate the enumerator; *ppEnum is NULL. + * - E_POINTER = The ppEnum pointer is not valid. + */ static HRESULT cpc_EnumConnectionPoints(IConnectionPointContainer *pThis, IEnumConnectionPoints **ppEnum) { PHEAPDATA phd = (PHEAPDATA)HeapDataPtr(pThis); /* pointer to heap data */ + PENUMGENERICDATA pegd; /* pointer to data block */ + PENUMGENERIC peg; /* pointer to enumerator */ - return E_NOTIMPL; /* TODO */ + if (!ppEnum) + return E_POINTER; + *ppEnum = NULL; + + /* Allocate the data block. */ + pegd = _ObjHlpAllocateEnumGenericData((IMalloc *)phd, &IID_IConnectionPoint, 2); + if (!pegd) + return E_OUTOFMEMORY; + + /* Build the data block. */ + _ObjHlpAddToEnumGenericData(pegd, (IUnknown *)(&(phd->fcpMallocSpy))); + _ObjHlpAddToEnumGenericData(pegd, (IUnknown *)(&(phd->fcpSequentialStream))); + + /* Allocate the enumerator. */ + peg = _ObjHlpAllocateEnumGeneric((IMalloc *)phd, &IID_IEnumConnectionPoints, pegd, 0); + if (peg) + { + IUnknown_QueryInterface((IUnknown *)peg, &IID_IEnumConnectionPoints, (PPVOID)ppEnum); + return S_OK; + } + + /* Enumerator allocation failed?!? */ + _ObjHlpDiscardEnumGenericData(pegd); + malloc_Free((IMalloc *)phd, pegd); + return E_OUTOFMEMORY; } +/* + * Returns a reference to the IConnectionPoint interface corresponding to a specific outgoing IID. + * + * Parameters: + * - pThis = Pointer to the ConnectionPointContainer interface in the heap data object. + * - riid = IID of the outgoing interface to get the connection point for. + * - ppCP = Pointer to a variable to receive the IConnectionPoint interface pointer. + * + * Returns: + * - S_OK = Found connection point; interface pointer is in *ppCP. + * - E_POINTER = The ppCP pointer is not valid. + * - CONNECT_E_NOCONNECTION = The object does not support the interface indicated by riid. *ppCP is NULL. + */ static HRESULT cpc_FindConnectionPoint(IConnectionPointContainer *pThis, REFIID riid, IConnectionPoint **ppCP) { PHEAPDATA phd = (PHEAPDATA)HeapDataPtr(pThis); /* pointer to heap data */ diff --git a/kernel/lib/objhelp_enumconn.c b/kernel/lib/objhelp_enumconn.c index bb3693e..177a6c6 100644 --- a/kernel/lib/objhelp_enumconn.c +++ b/kernel/lib/objhelp_enumconn.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "enumconn.h" /*------------------------------------------- diff --git a/kernel/lib/objhelp_enumgeneric.c b/kernel/lib/objhelp_enumgeneric.c index f6d5a69..fddfd88 100644 --- a/kernel/lib/objhelp_enumgeneric.c +++ b/kernel/lib/objhelp_enumgeneric.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "enumgeneric.h" /*--------------------------------------- @@ -43,6 +44,22 @@ *--------------------------------------- */ +/* + * Retrieves pointers to the supported interfaces on an object. Any pointer returned by this method + * has AddRef called on it before it returns. + * + * Parameters: + * - pThis = Base interface pointer. + * - riid = The identifier of the interface being requested. + * - ppvObject = Address of a pointer variable that receives the interface pointer requested by riid. + * On return, *ppvObject contains the requested interface pointer, or NULL if the interface + * is not supported. + * + * Returns: + * - S_OK = If the interface is supported. *ppvObject contains the pointer to the interface. + * - E_NOINTERFACE = If the interface is not supported. *ppvObject contains NULL. + * - E_POINTER = If ppvObject is NULL. + */ static HRESULT enumGeneric_QueryInterface(IUnknown *pThis, REFIID riid, PPVOID ppvObject) { PENUMGENERIC peg = (PENUMGENERIC)pThis; @@ -60,11 +77,29 @@ static HRESULT enumGeneric_QueryInterface(IUnknown *pThis, REFIID riid, PPVOID p return E_NOINTERFACE; } +/* + * Adds a reference to the enumerator object. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumUnknown interface pointer). + * + * Returns: + * The new reference count on the object. + */ static UINT32 enumGeneric_AddRef(IUnknown *pThis) { return ++(((PENUMGENERIC)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 IEnumUnknown interface pointer). + * + * Returns: + * The new reference count on the object. + */ static UINT32 enumGeneric_Release(IUnknown *pThis) { register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to actual data block */ @@ -92,6 +127,23 @@ static UINT32 enumGeneric_Release(IUnknown *pThis) return rc; } +/* + * Retrieves the next number of interface pointers in the enumeration sequence. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumUnknown interface pointer). + * - celt = Number of interface pointers to be retrieved. If there are more than this many interface pointers + * in the enumeration sequence, this many are returned. + * - rgelt = 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. + * - pceltFetched = Pointer to a variable which will receive the number of interface pointers retrieved. This + * value will always be less than or equal to celt. + * + * Returns: + * - S_OK = All the interface pointers requested were retrieved. *pceltFetched is equal to celt. + * - S_FALSE = Not all the interface pointers requested could be retrieved. *pceltFetched is less than celt. + * - Other = An error result. + */ static HRESULT enumGeneric_Next(IEnumUnknown *pThis, UINT32 celt, IUnknown **rgelt, UINT32 *pceltFetched) { register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to data block */ @@ -110,15 +162,29 @@ static HRESULT enumGeneric_Next(IEnumUnknown *pThis, UINT32 celt, IUnknown **rge /* 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]); + { /* fetch the items - note we QI for the actual interface we're supposed to be enumerating for */ + if (FAILED(IUnknown_QueryInterface(peg->pPayload->rgObjects[i + peg->nCurrent], peg->pPayload->riidObjects, + (PPVOID)(&(rgelt[i]))))) + return E_UNEXPECTED; } peg->nCurrent += *pceltFetched; /* advance pointer */ return (*pceltFetched == celt) ? S_OK : S_FALSE; } +/* + * Skips over the next number of interface pointers in the enumeration sequence. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumUnknown interface pointer). + * - celt = Number of elements to be skipped. If there are fewer than this many elements + * 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 enumGeneric_Skip(IEnumUnknown *pThis, UINT32 celt) { register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to data block */ @@ -133,12 +199,34 @@ static HRESULT enumGeneric_Skip(IEnumUnknown *pThis, UINT32 celt) return rc; } +/* + * Resets the enumeration sequence to the beginning. + * + * Parameters: + * - pThis = Pointer to the enumerator object (actually its IEnumUnknown interface pointer). + * + * Returns: + * S_OK. + */ static HRESULT enumGeneric_Reset(IEnumUnknown *pThis) { ((PENUMGENERIC)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 IEnumUnknown 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 enumGeneric_Clone(IEnumUnknown *pThis, IEnumUnknown **ppEnum) { register PENUMGENERIC peg = (PENUMGENERIC)pThis; /* pointer to data block */ @@ -154,6 +242,7 @@ static HRESULT enumGeneric_Clone(IEnumUnknown *pThis, IEnumUnknown **ppEnum) return S_OK; } +/* VTable for the IEnumUnknown interface. */ static const SEG_RODATA struct IEnumUnknownVTable vtblEnum = { .QueryInterface = enumGeneric_QueryInterface, @@ -170,7 +259,20 @@ static const SEG_RODATA struct IEnumUnknownVTable vtblEnum = *--------------------------------- */ -PENUMGENERICDATA _ObjHlpAllocateEnumGenericData(IMalloc *pAllocator, UINT32 nCapacity) +/* + * Allocate the "inner" connection data object for an enumerator. + * + * Parameters: + * - pAllocator = Allocator to use to allocate the memory. + * - riidObjects = IID that the objects stored in this block will actually have. NULL is interpreted + * as the IID of IUnknown. + * - nCapacity = Number of slots to allocate for the object pointers. + * + * 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. + */ +PENUMGENERICDATA _ObjHlpAllocateEnumGenericData(IMalloc *pAllocator, REFIID riidObjects, UINT32 nCapacity) { register PENUMGENERICDATA rc; /* return from this function */ register SIZE_T cbReturn = sizeof(ENUMGENERICDATA) + (nCapacity * sizeof(PUNKNOWN)); /* bytes to allocate */ @@ -180,12 +282,22 @@ PENUMGENERICDATA _ObjHlpAllocateEnumGenericData(IMalloc *pAllocator, UINT32 nCap { StrSetMem(rc, 0, cbReturn); rc->uiRefCount = 0; + rc->riidObjects = riidObjects ? riidObjects : &IID_IUnknown; rc->nObjects = 0; } return rc; - } +/* + * Add an element to the specified "inner" object reference data object. Used when building the object. + * + * Parameters: + * - pegd = Pointer to the reference data object. + * - pUnk = IUnknown pointer to add to the "next" slot. A reference is added to this pointer. + * + * Returns: + * Nothing. + */ void _ObjHlpAddToEnumGenericData(PENUMGENERICDATA pegd, IUnknown *pUnk) { pegd->rgObjects[pegd->nObjects] = pUnk; @@ -193,6 +305,16 @@ void _ObjHlpAddToEnumGenericData(PENUMGENERICDATA pegd, IUnknown *pUnk) pegd->nObjects++; } +/* + * Discards the contents of an "inner" object reference data object by releasing all the interface pointers + * it contains. + * + * Parameters: + * - pegd = Pointer to the reference data object. + * + * Returns: + * Nothing. + */ void _ObjHlpDiscardEnumGenericData(PENUMGENERICDATA pegd) { register UINT32 i; /* loop counter */ @@ -201,6 +323,20 @@ void _ObjHlpDiscardEnumGenericData(PENUMGENERICDATA pegd) IUnknown_Release(pegd->rgObjects[i]); } +/* + * Allocates a new "enumerator" data object. + * + * Parameters: + * - pAllocator = Allocator to use to allocate the memory. + * - riidActual = IID that this enumerator will actually support, in addition to IUnknown. NULL is + * interpreted as IID_IEnumUnknown. + * - pegd = Pointer to the "inner" reference 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. + */ PENUMGENERIC _ObjHlpAllocateEnumGeneric(IMalloc *pAllocator, REFIID riidActual, PENUMGENERICDATA pegd, UINT32 nCurrent) { @@ -211,7 +347,7 @@ PENUMGENERIC _ObjHlpAllocateEnumGeneric(IMalloc *pAllocator, REFIID riidActual, { /* initialize all the fields */ rc->enumUnknown.pVTable = &vtblEnum; rc->uiRefCount = 0; - rc->riidActual = riidActual; + rc->riidActual = riidActual ? riidActual : &IID_IEnumUnknown; rc->nCurrent = nCurrent; rc->pPayload = pegd; pegd->uiRefCount++;