📄 dpa.c
字号:
/*
* Dynamic pointer array (DPA) implementation
*
* Copyright 1998 Eric Kohl
* 1998 Juergen Schmied <j.schmied@metronet.de>
* 2000 Eric Kohl for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
* NOTES
* These functions were involuntarily documented by Microsoft in 2002 as
* the outcome of an anti-trust suit brought by various U.S. governments.
* As a result the specifications on MSDN are inaccurate, incomplete
* and misleading. A much more complete (unofficial) documentation is
* available at:
*
* http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl32
*/
#define COBJMACROS
#include <stdarg.h>
#include <limits.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "commctrl.h"
#include "objbase.h"
#include "comctl32.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(dpa);
struct _DPA
{
INT nItemCount;
LPVOID *ptrs;
HANDLE hHeap;
INT nGrow;
INT nMaxCount;
};
typedef struct _STREAMDATA
{
DWORD dwSize;
DWORD dwData2;
DWORD dwItems;
} STREAMDATA, *PSTREAMDATA;
typedef struct _LOADDATA
{
INT nCount;
PVOID ptr;
} LOADDATA, *LPLOADDATA;
typedef HRESULT (CALLBACK *DPALOADPROC)(LPLOADDATA,IStream*,LPARAM);
/**************************************************************************
* DPA_LoadStream [COMCTL32.9]
*
* Loads a dynamic pointer array from a stream
*
* PARAMS
* phDpa [O] pointer to a handle to a dynamic pointer array
* loadProc [I] pointer to a callback function
* pStream [I] pointer to a stream
* lParam [I] application specific value
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*
* NOTES
* No more information available yet!
*/
HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc,
IStream *pStream, LPARAM lParam)
{
HRESULT errCode;
LARGE_INTEGER position;
ULARGE_INTEGER newPosition;
STREAMDATA streamData;
LOADDATA loadData;
ULONG ulRead;
HDPA hDpa;
PVOID *ptr;
FIXME ("phDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
phDpa, loadProc, pStream, lParam);
if (!phDpa || !loadProc || !pStream)
return E_INVALIDARG;
*phDpa = (HDPA)NULL;
position.QuadPart = 0;
/*
* Zero out our streamData
*/
memset(&streamData,0,sizeof(STREAMDATA));
errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition);
if (errCode != S_OK)
return errCode;
errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
if (errCode != S_OK)
return errCode;
FIXME ("dwSize=%u dwData2=%u dwItems=%u\n",
streamData.dwSize, streamData.dwData2, streamData.dwItems);
if ( ulRead < sizeof(STREAMDATA) ||
lParam < sizeof(STREAMDATA) ||
streamData.dwSize < sizeof(STREAMDATA) ||
streamData.dwData2 < 1) {
errCode = E_FAIL;
}
if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */
return E_OUTOFMEMORY;
/* create the dpa */
hDpa = DPA_Create (streamData.dwItems);
if (!hDpa)
return E_OUTOFMEMORY;
if (!DPA_Grow (hDpa, streamData.dwItems))
return E_OUTOFMEMORY;
/* load data from the stream into the dpa */
ptr = hDpa->ptrs;
for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) {
errCode = (loadProc)(&loadData, pStream, lParam);
if (errCode != S_OK) {
errCode = S_FALSE;
break;
}
*ptr = loadData.ptr;
ptr++;
}
/* set the number of items */
hDpa->nItemCount = loadData.nCount;
/* store the handle to the dpa */
*phDpa = hDpa;
FIXME ("new hDpa=%p, errorcode=%x\n", hDpa, errCode);
return errCode;
}
/**************************************************************************
* DPA_SaveStream [COMCTL32.10]
*
* Saves a dynamic pointer array to a stream
*
* PARAMS
* hDpa [I] handle to a dynamic pointer array
* loadProc [I] pointer to a callback function
* pStream [I] pointer to a stream
* lParam [I] application specific value
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*
* NOTES
* No more information available yet!
*/
HRESULT WINAPI DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc,
IStream *pStream, LPARAM lParam)
{
FIXME ("hDpa=%p loadProc=%p pStream=%p lParam=%lx\n",
hDpa, loadProc, pStream, lParam);
return E_FAIL;
}
/**************************************************************************
* DPA_Merge [COMCTL32.11]
*
* Merge two dynamic pointers arrays.
*
* PARAMS
* hdpa1 [I] handle to a dynamic pointer array
* hdpa2 [I] handle to a dynamic pointer array
* dwFlags [I] flags
* pfnCompare [I] pointer to sort function
* pfnMerge [I] pointer to merge function
* lParam [I] application specific value
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*
* NOTES
* No more information available yet!
*/
BOOL WINAPI DPA_Merge (const HDPA hdpa1, const HDPA hdpa2, DWORD dwFlags,
PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge,
LPARAM lParam)
{
INT nCount;
LPVOID *pWork1, *pWork2;
INT nResult, i;
INT nIndex;
TRACE("%p %p %08x %p %p %08lx)\n",
hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
if (IsBadWritePtr (hdpa1, sizeof(*hdpa1)))
return FALSE;
if (IsBadWritePtr (hdpa2, sizeof(*hdpa2)))
return FALSE;
if (IsBadCodePtr ((FARPROC)pfnCompare))
return FALSE;
if (IsBadCodePtr ((FARPROC)pfnMerge))
return FALSE;
if (!(dwFlags & DPAM_NOSORT)) {
TRACE("sorting dpa's!\n");
if (hdpa1->nItemCount > 0)
DPA_Sort (hdpa1, pfnCompare, lParam);
TRACE ("dpa 1 sorted!\n");
if (hdpa2->nItemCount > 0)
DPA_Sort (hdpa2, pfnCompare, lParam);
TRACE ("dpa 2 sorted!\n");
}
if (hdpa2->nItemCount < 1)
return TRUE;
TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
hdpa1->nItemCount, hdpa2->nItemCount);
/* working but untrusted implementation */
pWork1 = &(hdpa1->ptrs[hdpa1->nItemCount - 1]);
pWork2 = &(hdpa2->ptrs[hdpa2->nItemCount - 1]);
nIndex = hdpa1->nItemCount - 1;
nCount = hdpa2->nItemCount - 1;
do
{
if (nIndex < 0) {
if ((nCount >= 0) && (dwFlags & DPAM_INSERT)) {
/* Now insert the remaining new items into DPA 1 */
TRACE("%d items to be inserted at start of DPA 1\n",
nCount+1);
for (i=nCount; i>=0; i--) {
PVOID ptr;
ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
if (!ptr)
return FALSE;
DPA_InsertPtr (hdpa1, 0, ptr);
pWork2--;
}
}
break;
}
nResult = (pfnCompare)(*pWork1, *pWork2, lParam);
TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n",
nResult, nIndex, nCount);
if (nResult == 0)
{
PVOID ptr;
ptr = (pfnMerge)(1, *pWork1, *pWork2, lParam);
if (!ptr)
return FALSE;
nCount--;
pWork2--;
*pWork1 = ptr;
nIndex--;
pWork1--;
}
else if (nResult > 0)
{
/* item in DPA 1 missing from DPA 2 */
if (dwFlags & DPAM_DELETE)
{
/* Now delete the extra item in DPA1 */
PVOID ptr;
ptr = DPA_DeletePtr (hdpa1, hdpa1->nItemCount - 1);
(pfnMerge)(2, ptr, NULL, lParam);
}
nIndex--;
pWork1--;
}
else
{
/* new item in DPA 2 */
if (dwFlags & DPAM_INSERT)
{
/* Now insert the new item in DPA 1 */
PVOID ptr;
ptr = (pfnMerge)(3, *pWork2, NULL, lParam);
if (!ptr)
return FALSE;
DPA_InsertPtr (hdpa1, nIndex+1, ptr);
}
nCount--;
pWork2--;
}
}
while (nCount >= 0);
return TRUE;
}
/**************************************************************************
* DPA_Destroy [COMCTL32.329]
*
* Destroys a dynamic pointer array
*
* PARAMS
* hdpa [I] handle (pointer) to the pointer array
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI DPA_Destroy (const HDPA hdpa)
{
TRACE("(%p)\n", hdpa);
if (!hdpa)
return FALSE;
if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
return FALSE;
return HeapFree (hdpa->hHeap, 0, hdpa);
}
/**************************************************************************
* DPA_Grow [COMCTL32.330]
*
* Sets the growth amount.
*
* PARAMS
* hdpa [I] handle (pointer) to the existing (source) pointer array
* nGrow [I] number of items by which the array grows when it's too small
*
* RETURNS
* Success: TRUE
* Failure: FALSE
*/
BOOL WINAPI DPA_Grow (const HDPA hdpa, INT nGrow)
{
TRACE("(%p %d)\n", hdpa, nGrow);
if (!hdpa)
return FALSE;
hdpa->nGrow = max(8, nGrow);
return TRUE;
}
/**************************************************************************
* DPA_Clone [COMCTL32.331]
*
* Copies a pointer array to an other one or creates a copy
*
* PARAMS
* hdpa [I] handle (pointer) to the existing (source) pointer array
* hdpaNew [O] handle (pointer) to the destination pointer array
*
* RETURNS
* Success: pointer to the destination pointer array.
* Failure: NULL
*
* NOTES
* - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
* array will be created and it's handle (pointer) is returned.
* - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
* this implementation just returns NULL.
*/
HDPA WINAPI DPA_Clone (const HDPA hdpa, const HDPA hdpaNew)
{
INT nNewItems, nSize;
HDPA hdpaTemp;
if (!hdpa)
return NULL;
TRACE("(%p %p)\n", hdpa, hdpaNew);
if (!hdpaNew) {
/* create a new DPA */
hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
sizeof(*hdpaTemp));
hdpaTemp->hHeap = hdpa->hHeap;
hdpaTemp->nGrow = hdpa->nGrow;
}
else
hdpaTemp = hdpaNew;
if (hdpaTemp->ptrs) {
/* remove old pointer array */
HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
hdpaTemp->ptrs = NULL;
hdpaTemp->nItemCount = 0;
hdpaTemp->nMaxCount = 0;
}
/* create a new pointer array */
nNewItems = hdpaTemp->nGrow *
((INT)((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
nSize = nNewItems * sizeof(LPVOID);
hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
hdpaTemp->nMaxCount = nNewItems;
/* clone the pointer array */
hdpaTemp->nItemCount = hdpa->nItemCount;
memmove (hdpaTemp->ptrs, hdpa->ptrs,
hdpaTemp->nItemCount * sizeof(LPVOID));
return hdpaTemp;
}
/**************************************************************************
* DPA_GetPtr [COMCTL32.332]
*
* Retrieves a pointer from a dynamic pointer array
*
* PARAMS
* hdpa [I] handle (pointer) to the pointer array
* nIndex [I] array index of the desired pointer
*
* RETURNS
* Success: pointer
* Failure: NULL
*/
LPVOID WINAPI DPA_GetPtr (const HDPA hdpa, INT nIndex)
{
TRACE("(%p %d)\n", hdpa, nIndex);
if (!hdpa)
return NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -