[COMCTL32] Move DPA/DSA functions out of comctl32undoc.c

Felix Nawothnig felix.nawothnig at t-online.de
Mon Jul 4 12:58:55 CDT 2005


These functions are (mostly) documented for 3 years now and exported by 
name since Win2k (I just move them for now - haven't fix them yet).

ChangeLog:
Move DPA and DSA functions out of comctl32undoc.c as they are documented 
by now.

-------------- next part --------------
Index: Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/Makefile.in,v
retrieving revision 1.39
diff -u -r1.39 Makefile.in
--- Makefile.in	9 May 2005 14:42:36 -0000	1.39
+++ Makefile.in	4 Jul 2005 17:52:51 -0000
@@ -15,7 +15,9 @@
 	comctl32undoc.c \
 	commctrl.c \
 	datetime.c \
+	dpa.c \
 	draglist.c \
+	dsa.c \
 	flatsb.c \
 	header.c \
 	hotkey.c \
Index: comctl32undoc.c
===================================================================
RCS file: /home/wine/wine/dlls/comctl32/comctl32undoc.c,v
retrieving revision 1.99
diff -u -r1.99 comctl32undoc.c
--- comctl32undoc.c	6 May 2005 15:44:32 -0000	1.99
+++ comctl32undoc.c	4 Jul 2005 17:52:53 -0000
@@ -55,314 +55,9 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
 
-struct _DSA
-{
-    INT  nItemCount;
-    LPVOID pData;
-    INT  nMaxCount;
-    INT  nItemSize;
-    INT  nGrow;
-};
-
-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);
-
 static const WCHAR strMRUList[] = { 'M','R','U','L','i','s','t',0 };
 
 /**************************************************************************
- * 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=%lu dwData2=%lu dwItems=%lu\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=%lx\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 %08lx %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;
-}
-
-
-/**************************************************************************
  * Alloc [COMCTL32.71]
  *
  * Allocates memory block from the dll's private heap
@@ -1416,1035 +1111,129 @@
 
 
 /**************************************************************************
- * DSA_Create [COMCTL32.320]
- *
- * Creates a dynamic storage array
- *
- * PARAMS
- *     nSize [I] size of the array elements
- *     nGrow [I] number of elements by which the array grows when it is filled
- *
- * RETURNS
- *     Success: pointer to an array control structure. Use this like a handle.
- *     Failure: NULL
- *
- * NOTES
- *     The DSA_ functions can be used to create and manipulate arrays of
- *     fixed-size memory blocks. These arrays can store any kind of data
- *     (e.g. strings and icons).
+ * Notification functions
  */
-HDSA WINAPI DSA_Create (INT nSize, INT nGrow)
-{
-    HDSA hdsa;
-
-    TRACE("(size=%d grow=%d)\n", nSize, nGrow);
-
-    hdsa = Alloc (sizeof(*hdsa));
-    if (hdsa)
-    {
-	hdsa->nItemCount = 0;
-        hdsa->pData = NULL;
-	hdsa->nMaxCount = 0;
-	hdsa->nItemSize = nSize;
-	hdsa->nGrow = max(1, nGrow);
-    }
-
-    return hdsa;
-}
 
-
-/**************************************************************************
- * DSA_Destroy [COMCTL32.321]
- * 
- * Destroys a dynamic storage array
- *
- * PARAMS
- *     hdsa [I] pointer to the array control structure
- *
- * RETURNS
- *     Success: TRUE
- *     Failure: FALSE
- */
-BOOL WINAPI DSA_Destroy (const HDSA hdsa)
+typedef struct tagNOTIFYDATA
 {
-    TRACE("(%p)\n", hdsa);
-
-    if (!hdsa)
-	return FALSE;
-
-    if (hdsa->pData && (!Free (hdsa->pData)))
-	return FALSE;
-
-    return Free (hdsa);
-}
+    HWND hwndFrom;
+    HWND hwndTo;
+    DWORD  dwParam3;
+    DWORD  dwParam4;
+    DWORD  dwParam5;
+    DWORD  dwParam6;
+} NOTIFYDATA, *LPNOTIFYDATA;
 
 
 /**************************************************************************
- * DSA_GetItem [COMCTL32.322]
- *
- * Copies the specified item into a caller-supplied buffer.
- *
- * PARAMS
- *     hdsa   [I] pointer to the array control structure
- *     nIndex [I] number of the Item to get
- *     pDest  [O] destination buffer. Has to be >= dwElementSize.
- *
- * RETURNS
- *     Success: TRUE
- *     Failure: FALSE
+ * DoNotify [Internal]
  */
-BOOL WINAPI DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
-{
-    LPVOID pSrc;
-
-    TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
 
-    if (!hdsa)
-	return FALSE;
-    if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
-	return FALSE;
-
-    pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
-    memmove (pDest, pSrc, hdsa->nItemSize);
-
-    return TRUE;
-}
-
-
-/**************************************************************************
- * DSA_GetItemPtr [COMCTL32.323]
- *
- * Retrieves a pointer to the specified item.
- *
- * PARAMS
- *     hdsa   [I] pointer to the array control structure
- *     nIndex [I] index of the desired item
- *
- * RETURNS
- *     Success: pointer to an item
- *     Failure: NULL
- */
-LPVOID WINAPI DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
+static LRESULT DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
 {
-    LPVOID pSrc;
-
-    TRACE("(%p %d)\n", hdsa, nIndex);
-
-    if (!hdsa)
-	return NULL;
-    if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
-	return NULL;
-
-    pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
-
-    TRACE("-- ret=%p\n", pSrc);
-
-    return pSrc;
-}
+    NMHDR nmhdr;
+    LPNMHDR lpNmh = NULL;
+    UINT idFrom = 0;
 
+    TRACE("(%p %p %d %p 0x%08lx)\n",
+	   lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
+	   lpNotify->dwParam5);
 
-/**************************************************************************
- * DSA_SetItem [COMCTL32.325]
- *
- * Sets the contents of an item in the array.
- *
- * PARAMS
- *     hdsa   [I] pointer to the array control structure
- *     nIndex [I] index for the item
- *     pSrc   [I] pointer to the new item data
- *
- * RETURNS
- *     Success: TRUE
- *     Failure: FALSE
- */
-BOOL WINAPI DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
-{
-    INT  nSize, nNewItems;
-    LPVOID pDest, lpTemp;
+    if (!lpNotify->hwndTo)
+	return 0;
 
-    TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
+    if (lpNotify->hwndFrom == (HWND)-1) {
+	lpNmh = lpHdr;
+	idFrom = lpHdr->idFrom;
+    }
+    else {
+	if (lpNotify->hwndFrom)
+	    idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
 
-    if ((!hdsa) || nIndex < 0)
-	return FALSE;
+	lpNmh = (lpHdr) ? lpHdr : &nmhdr;
 
-    if (hdsa->nItemCount <= nIndex) {
-	/* within the old array */
-	if (hdsa->nMaxCount > nIndex) {
-	    /* within the allocated space, set a new boundary */
-	    hdsa->nItemCount = nIndex + 1;
-	}
-	else {
-	    /* resize the block of memory */
-	    nNewItems =
-		hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
-	    nSize = hdsa->nItemSize * nNewItems;
-
-	    lpTemp = ReAlloc (hdsa->pData, nSize);
-	    if (!lpTemp)
-		return FALSE;
-
-	    hdsa->nMaxCount = nNewItems;
-	    hdsa->nItemCount = nIndex + 1;
-	    hdsa->pData = lpTemp;
-	}
+	lpNmh->hwndFrom = lpNotify->hwndFrom;
+	lpNmh->idFrom = idFrom;
+	lpNmh->code = uCode;
     }
 
-    /* put the new entry in */
-    pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
-    TRACE("-- move dest=%p src=%p size=%d\n",
-	   pDest, pSrc, hdsa->nItemSize);
-    memmove (pDest, pSrc, hdsa->nItemSize);
-
-    return TRUE;
+    return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
 }
 
 
 /**************************************************************************
- * DSA_InsertItem [COMCTL32.324]
+ * SendNotify [COMCTL32.341]
  *
- * Inserts an item into the array at the specified index.
+ * Sends a WM_NOTIFY message to the specified window.
  *
  * PARAMS
- *     hdsa   [I] pointer to the array control structure
- *     nIndex [I] index for the new item
- *     pSrc   [I] pointer to the element
+ *     hwndTo   [I] Window to receive the message
+ *     hwndFrom [I] Window that the message is from (see notes)
+ *     uCode    [I] Notification code
+ *     lpHdr    [I] The NMHDR and any additional information to send or NULL
  *
  * RETURNS
- *     Success: position of the new item
- *     Failure: -1
+ *     Success: return value from notification
+ *     Failure: 0
+ *
+ * NOTES
+ *     If hwndFrom is -1 then the identifier of the control sending the
+ *     message is taken from the NMHDR structure.
+ *     If hwndFrom is not -1 then lpHdr can be NULL.
  */
-INT WINAPI DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
+LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr)
 {
-    INT   nNewItems, nSize;
-    LPVOID  lpTemp, lpDest;
-
-    TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
-
-    if ((!hdsa) || nIndex < 0)
-	return -1;
-
-    /* when nIndex >= nItemCount then append */
-    if (nIndex >= hdsa->nItemCount)
- 	nIndex = hdsa->nItemCount;
-
-    /* do we need to resize ? */
-    if (hdsa->nItemCount >= hdsa->nMaxCount) {
-	nNewItems = hdsa->nMaxCount + hdsa->nGrow;
-	nSize = hdsa->nItemSize * nNewItems;
-
-	lpTemp = ReAlloc (hdsa->pData, nSize);
-	if (!lpTemp)
-	    return -1;
-
-	hdsa->nMaxCount = nNewItems;
-	hdsa->pData = lpTemp;
-    }
+    NOTIFYDATA notify;
 
-    /* do we need to move elements ? */
-    if (nIndex < hdsa->nItemCount) {
-	lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
-	lpDest = (char *) lpTemp + hdsa->nItemSize;
-	nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
-	TRACE("-- move dest=%p src=%p size=%d\n",
-	       lpDest, lpTemp, nSize);
-	memmove (lpDest, lpTemp, nSize);
-    }
+    TRACE("(%p %p %d %p)\n",
+	   hwndTo, hwndFrom, uCode, lpHdr);
 
-    /* ok, we can put the new Item in */
-    hdsa->nItemCount++;
-    lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
-    TRACE("-- move dest=%p src=%p size=%d\n",
-	   lpDest, pSrc, hdsa->nItemSize);
-    memmove (lpDest, pSrc, hdsa->nItemSize);
+    notify.hwndFrom = hwndFrom;
+    notify.hwndTo   = hwndTo;
+    notify.dwParam5 = 0;
+    notify.dwParam6 = 0;
 
-    return nIndex;
+    return DoNotify (&notify, uCode, lpHdr);
 }
 
 
 /**************************************************************************
- * DSA_DeleteItem [COMCTL32.326]
+ * SendNotifyEx [COMCTL32.342]
  *
- * Deletes the specified item from the array.
+ * Sends a WM_NOTIFY message to the specified window.
  *
  * PARAMS
- *     hdsa   [I] pointer to the array control structure
- *     nIndex [I] index for the element to delete
+ *     hwndFrom [I] Window to receive the message
+ *     hwndTo   [I] Window that the message is from
+ *     uCode    [I] Notification code
+ *     lpHdr    [I] The NMHDR and any additional information to send or NULL
+ *     dwParam5 [I] Unknown
  *
  * RETURNS
- *     Success: number of the deleted element
- *     Failure: -1
+ *     Success: return value from notification
+ *     Failure: 0
+ *
+ * NOTES
+ *     If hwndFrom is -1 then the identifier of the control sending the
+ *     message is taken from the NMHDR structure.
+ *     If hwndFrom is not -1 then lpHdr can be NULL.
  */
-INT WINAPI DSA_DeleteItem (const HDSA hdsa, INT nIndex)
+LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
+                             LPNMHDR lpHdr, DWORD dwParam5)
 {
-    LPVOID lpDest,lpSrc;
-    INT  nSize;
-
-    TRACE("(%p %d)\n", hdsa, nIndex);
+    NOTIFYDATA notify;
+    HWND hwndNotify;
 
-    if (!hdsa)
-	return -1;
-    if (nIndex < 0 || nIndex >= hdsa->nItemCount)
-	return -1;
+    TRACE("(%p %p %d %p 0x%08lx)\n",
+	   hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
 
-    /* do we need to move ? */
-    if (nIndex < hdsa->nItemCount - 1) {
-	lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
-	lpSrc = (char *) lpDest + hdsa->nItemSize;
-	nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
-	TRACE("-- move dest=%p src=%p size=%d\n",
-	       lpDest, lpSrc, nSize);
-	memmove (lpDest, lpSrc, nSize);
-    }
-
-    hdsa->nItemCount--;
-
-    /* free memory ? */
-    if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
-	nSize = hdsa->nItemSize * hdsa->nItemCount;
-
-	lpDest = ReAlloc (hdsa->pData, nSize);
-	if (!lpDest)
-	    return -1;
-
-	hdsa->nMaxCount = hdsa->nItemCount;
-	hdsa->pData = lpDest;
-    }
-
-    return nIndex;
-}
-
-
-/**************************************************************************
- * DSA_DeleteAllItems [COMCTL32.327]
- *
- * Removes all items and reinitializes the array.
- *
- * PARAMS
- *     hdsa [I] pointer to the array control structure
- *
- * RETURNS
- *     Success: TRUE
- *     Failure: FALSE
- */
-BOOL WINAPI DSA_DeleteAllItems (const HDSA hdsa)
-{
-    TRACE("(%p)\n", hdsa);
-
-    if (!hdsa)
-	return FALSE;
-    if (hdsa->pData && (!Free (hdsa->pData)))
-	return FALSE;
-
-    hdsa->nItemCount = 0;
-    hdsa->pData = NULL;
-    hdsa->nMaxCount = 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;
-    if (!hdpa->ptrs) {
-	WARN("no pointer array.\n");
-	return NULL;
-    }
-    if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
-	WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
-	return NULL;
-    }
-
-    TRACE("-- %p\n", hdpa->ptrs[nIndex]);
-
-    return hdpa->ptrs[nIndex];
-}
-
-
-/**************************************************************************
- * DPA_GetPtrIndex [COMCTL32.333]
- *
- * Retrieves the index of the specified pointer
- *
- * PARAMS
- *     hdpa   [I] handle (pointer) to the pointer array
- *     p      [I] pointer
- *
- * RETURNS
- *     Success: index of the specified pointer
- *     Failure: -1
- */
-INT WINAPI DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
-{
-    INT i;
-
-    if (!hdpa || !hdpa->ptrs)
-	return -1;
-
-    for (i = 0; i < hdpa->nItemCount; i++) {
-	if (hdpa->ptrs[i] == p)
-	    return i;
-    }
-
-    return -1;
-}
-
-
-/**************************************************************************
- * DPA_InsertPtr [COMCTL32.334]
- *
- * Inserts a pointer into a dynamic pointer array
- *
- * PARAMS
- *     hdpa [I] handle (pointer) to the array
- *     i    [I] array index
- *     p    [I] pointer to insert
- *
- * RETURNS
- *     Success: index of the inserted pointer
- *     Failure: -1
- */
-INT WINAPI DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
-{
-    TRACE("(%p %d %p)\n", hdpa, i, p);
-
-    if (!hdpa || i < 0) return -1;
-
-    if (i >= 0x7fff)
-	i = hdpa->nItemCount;
-
-    if (i >= hdpa->nItemCount)
-	return DPA_SetPtr(hdpa, i, p) ? i : -1;
-
-    /* create empty spot at the end */
-    if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
-    memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
-    hdpa->ptrs[i] = p;
-    return i;
-}
-
-/**************************************************************************
- * DPA_SetPtr [COMCTL32.335]
- *
- * Sets a pointer in the pointer array
- *
- * PARAMS
- *     hdpa [I] handle (pointer) to the pointer array
- *     i    [I] index of the pointer that will be set
- *     p    [I] pointer to be set
- *
- * RETURNS
- *     Success: TRUE
- *     Failure: FALSE
- */
-BOOL WINAPI DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
-{
-    LPVOID *lpTemp;
-
-    TRACE("(%p %d %p)\n", hdpa, i, p);
-
-    if (!hdpa || i < 0 || i > 0x7fff)
-	return FALSE;
-
-    if (hdpa->nItemCount <= i) {
-	/* within the old array */
-	if (hdpa->nMaxCount <= i) {
-	    /* resize the block of memory */
-	    INT nNewItems =
-		hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
-	    INT nSize = nNewItems * sizeof(LPVOID);
-
-	    if (hdpa->ptrs)
-	        lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
-	    else
-		lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
-	    
-	    if (!lpTemp)
-		return FALSE;
-
-	    hdpa->nMaxCount = nNewItems;
-	    hdpa->ptrs = lpTemp;
-	}
-        hdpa->nItemCount = i+1;
-    }
-
-    /* put the new entry in */
-    hdpa->ptrs[i] = p;
-
-    return TRUE;
-}
-
-
-/**************************************************************************
- * DPA_DeletePtr [COMCTL32.336]
- *
- * Removes a pointer from the pointer array.
- *
- * PARAMS
- *     hdpa [I] handle (pointer) to the pointer array
- *     i    [I] index of the pointer that will be deleted
- *
- * RETURNS
- *     Success: deleted pointer
- *     Failure: NULL
- */
-LPVOID WINAPI DPA_DeletePtr (const HDPA hdpa, INT i)
-{
-    LPVOID *lpDest, *lpSrc, lpTemp = NULL;
-    INT  nSize;
-
-    TRACE("(%p %d)\n", hdpa, i);
-
-    if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
-	return NULL;
-
-    lpTemp = hdpa->ptrs[i];
-
-    /* do we need to move ?*/
-    if (i < hdpa->nItemCount - 1) {
-	lpDest = hdpa->ptrs + i;
-	lpSrc = lpDest + 1;
-	nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
-	TRACE("-- move dest=%p src=%p size=%x\n",
-	       lpDest, lpSrc, nSize);
-	memmove (lpDest, lpSrc, nSize);
-    }
-
-    hdpa->nItemCount --;
-
-    /* free memory ?*/
-    if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
-	INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
-	nSize = nNewItems * sizeof(LPVOID);
-	lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
-				      hdpa->ptrs, nSize);
-	if (!lpDest)
-	    return NULL;
-
-	hdpa->nMaxCount = nNewItems;
-	hdpa->ptrs = (LPVOID*)lpDest;
-    }
-
-    return lpTemp;
-}
-
-
-/**************************************************************************
- * DPA_DeleteAllPtrs [COMCTL32.337]
- *
- * Removes all pointers and reinitializes the array.
- *
- * PARAMS
- *     hdpa [I] handle (pointer) to the pointer array
- *
- * RETURNS
- *     Success: TRUE
- *     Failure: FALSE
- */
-BOOL WINAPI DPA_DeleteAllPtrs (const HDPA hdpa)
-{
-    TRACE("(%p)\n", hdpa);
-
-    if (!hdpa)
-	return FALSE;
-
-    if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
-	return FALSE;
-
-    hdpa->nItemCount = 0;
-    hdpa->nMaxCount = hdpa->nGrow * 2;
-    hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
-				     hdpa->nMaxCount * sizeof(LPVOID));
-
-    return TRUE;
-}
-
-
-/**************************************************************************
- * DPA_QuickSort [Internal]
- *
- * Ordinary quicksort (used by DPA_Sort).
- *
- * PARAMS
- *     lpPtrs     [I] pointer to the pointer array
- *     l          [I] index of the "left border" of the partition
- *     r          [I] index of the "right border" of the partition
- *     pfnCompare [I] pointer to the compare function
- *     lParam     [I] user defined value (3rd parameter in compare function)
- *
- * RETURNS
- *     NONE
- */
-static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
-                           PFNDPACOMPARE pfnCompare, LPARAM lParam)
-{
-    INT m;
-    LPVOID t;
-
-    TRACE("l=%i r=%i\n", l, r);
-
-    if (l==r)    /* one element is always sorted */
-        return;
-    if (r<l)     /* oops, got it in the wrong order */
-	{
-        DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
-        return;
-	}
-    m = (l+r)/2; /* divide by two */
-    DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
-    DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
-
-    /* join the two sides */
-    while( (l<=m) && (m<r) )
-    {
-        if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
-        {
-            t = lpPtrs[m+1];
-            memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l]));
-            lpPtrs[l] = t;
-
-            m++;
-        }
-        l++;
-    }
-}
-
-
-/**************************************************************************
- * DPA_Sort [COMCTL32.338]
- *
- * Sorts a pointer array using a user defined compare function
- *
- * PARAMS
- *     hdpa       [I] handle (pointer) to the pointer array
- *     pfnCompare [I] pointer to the compare function
- *     lParam     [I] user defined value (3rd parameter of compare function)
- *
- * RETURNS
- *     Success: TRUE
- *     Failure: FALSE
- */
-BOOL WINAPI DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
-{
-    if (!hdpa || !pfnCompare)
-	return FALSE;
-
-    TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
-
-    if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
-	DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
-		       pfnCompare, lParam);
-
-    return TRUE;
-}
-
-
-/**************************************************************************
- * DPA_Search [COMCTL32.339]
- *
- * Searches a pointer array for a specified pointer
- *
- * PARAMS
- *     hdpa       [I] handle (pointer) to the pointer array
- *     pFind      [I] pointer to search for
- *     nStart     [I] start index
- *     pfnCompare [I] pointer to the compare function
- *     lParam     [I] user defined value (3rd parameter of compare function)
- *     uOptions   [I] search options
- *
- * RETURNS
- *     Success: index of the pointer in the array.
- *     Failure: -1
- *
- * NOTES
- *     Binary search taken from R.Sedgewick "Algorithms in C"!
- *     Function is NOT tested!
- *     If something goes wrong, blame HIM not ME! (Eric Kohl)
- */
-INT WINAPI DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
-                       PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
-{
-    if (!hdpa || !pfnCompare || !pFind)
-	return -1;
-
-    TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
-	   hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
-
-    if (uOptions & DPAS_SORTED) {
-	/* array is sorted --> use binary search */
-	INT l, r, x, n;
-	LPVOID *lpPtr;
-
-	TRACE("binary search\n");
-
-	l = (nStart == -1) ? 0 : nStart;
-	r = hdpa->nItemCount - 1;
-	lpPtr = hdpa->ptrs;
-	while (r >= l) {
-	    x = (l + r) / 2;
-	    n = (pfnCompare)(pFind, lpPtr[x], lParam);
-	    if (n < 0)
-		r = x - 1;
-	    else
-		l = x + 1;
-	    if (n == 0) {
-		TRACE("-- ret=%d\n", n);
-		return n;
-	    }
-	}
-
-	if (uOptions & DPAS_INSERTBEFORE) {
-	    if (r == -1) r = 0;
-	    TRACE("-- ret=%d\n", r);
-	    return r;
-	}
-
-	if (uOptions & DPAS_INSERTAFTER) {
-	    TRACE("-- ret=%d\n", l);
-	    return l;
-	}
-    }
-    else {
-	/* array is not sorted --> use linear search */
-	LPVOID *lpPtr;
-	INT  nIndex;
-
-	TRACE("linear search\n");
-
-	nIndex = (nStart == -1)? 0 : nStart;
-	lpPtr = hdpa->ptrs;
-	for (; nIndex < hdpa->nItemCount; nIndex++) {
-	    if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
-		TRACE("-- ret=%d\n", nIndex);
-		return nIndex;
-	    }
-	}
-    }
-
-    TRACE("-- not found: ret=-1\n");
-    return -1;
-}
-
-
-/**************************************************************************
- * DPA_CreateEx [COMCTL32.340]
- *
- * Creates a dynamic pointer array using the specified size and heap.
- *
- * PARAMS
- *     nGrow [I] number of items by which the array grows when it is filled
- *     hHeap [I] handle to the heap where the array is stored
- *
- * RETURNS
- *     Success: handle (pointer) to the pointer array.
- *     Failure: NULL
- *
- * NOTES
- *     The DPA_ functions can be used to create and manipulate arrays of
- *     pointers.
- */
-HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap)
-{
-    HDPA hdpa;
-
-    TRACE("(%d %p)\n", nGrow, hHeap);
-
-    if (hHeap)
-	hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa));
-    else
-	hdpa = Alloc (sizeof(*hdpa));
-
-    if (hdpa) {
-	hdpa->nGrow = max(8, nGrow);
-	hdpa->hHeap = hHeap ? hHeap : GetProcessHeap();
-	hdpa->nMaxCount = hdpa->nGrow * 2;
-	hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
-				hdpa->nMaxCount * sizeof(LPVOID));
-    }
-
-    TRACE("-- %p\n", hdpa);
-
-    return hdpa;
-}
-
-
-/**************************************************************************
- * DPA_Create [COMCTL32.328]
- *
- * Creates a dynamic pointer array.
- *
- * PARAMS
- *     nGrow [I] number of items by which the array grows when it is filled
- *
- * RETURNS
- *     Success: handle (pointer) to the pointer array.
- *     Failure: NULL
- *
- * NOTES
- *     The DPA_ functions can be used to create and manipulate arrays of
- *     pointers.
- */
-HDPA WINAPI DPA_Create (INT nGrow)
-{
-    return DPA_CreateEx( nGrow, 0 );
-}
-
-
-/**************************************************************************
- * Notification functions
- */
-
-typedef struct tagNOTIFYDATA
-{
-    HWND hwndFrom;
-    HWND hwndTo;
-    DWORD  dwParam3;
-    DWORD  dwParam4;
-    DWORD  dwParam5;
-    DWORD  dwParam6;
-} NOTIFYDATA, *LPNOTIFYDATA;
-
-
-/**************************************************************************
- * DoNotify [Internal]
- */
-
-static LRESULT DoNotify (LPNOTIFYDATA lpNotify, UINT uCode, LPNMHDR lpHdr)
-{
-    NMHDR nmhdr;
-    LPNMHDR lpNmh = NULL;
-    UINT idFrom = 0;
-
-    TRACE("(%p %p %d %p 0x%08lx)\n",
-	   lpNotify->hwndFrom, lpNotify->hwndTo, uCode, lpHdr,
-	   lpNotify->dwParam5);
-
-    if (!lpNotify->hwndTo)
-	return 0;
-
-    if (lpNotify->hwndFrom == (HWND)-1) {
-	lpNmh = lpHdr;
-	idFrom = lpHdr->idFrom;
-    }
-    else {
-	if (lpNotify->hwndFrom)
-	    idFrom = GetDlgCtrlID (lpNotify->hwndFrom);
-
-	lpNmh = (lpHdr) ? lpHdr : &nmhdr;
-
-	lpNmh->hwndFrom = lpNotify->hwndFrom;
-	lpNmh->idFrom = idFrom;
-	lpNmh->code = uCode;
-    }
-
-    return SendMessageW (lpNotify->hwndTo, WM_NOTIFY, idFrom, (LPARAM)lpNmh);
-}
-
-
-/**************************************************************************
- * SendNotify [COMCTL32.341]
- *
- * Sends a WM_NOTIFY message to the specified window.
- *
- * PARAMS
- *     hwndTo   [I] Window to receive the message
- *     hwndFrom [I] Window that the message is from (see notes)
- *     uCode    [I] Notification code
- *     lpHdr    [I] The NMHDR and any additional information to send or NULL
- *
- * RETURNS
- *     Success: return value from notification
- *     Failure: 0
- *
- * NOTES
- *     If hwndFrom is -1 then the identifier of the control sending the
- *     message is taken from the NMHDR structure.
- *     If hwndFrom is not -1 then lpHdr can be NULL.
- */
-LRESULT WINAPI SendNotify (HWND hwndTo, HWND hwndFrom, UINT uCode, LPNMHDR lpHdr)
-{
-    NOTIFYDATA notify;
-
-    TRACE("(%p %p %d %p)\n",
-	   hwndTo, hwndFrom, uCode, lpHdr);
-
-    notify.hwndFrom = hwndFrom;
-    notify.hwndTo   = hwndTo;
-    notify.dwParam5 = 0;
-    notify.dwParam6 = 0;
-
-    return DoNotify (&notify, uCode, lpHdr);
-}
-
-
-/**************************************************************************
- * SendNotifyEx [COMCTL32.342]
- *
- * Sends a WM_NOTIFY message to the specified window.
- *
- * PARAMS
- *     hwndFrom [I] Window to receive the message
- *     hwndTo   [I] Window that the message is from
- *     uCode    [I] Notification code
- *     lpHdr    [I] The NMHDR and any additional information to send or NULL
- *     dwParam5 [I] Unknown
- *
- * RETURNS
- *     Success: return value from notification
- *     Failure: 0
- *
- * NOTES
- *     If hwndFrom is -1 then the identifier of the control sending the
- *     message is taken from the NMHDR structure.
- *     If hwndFrom is not -1 then lpHdr can be NULL.
- */
-LRESULT WINAPI SendNotifyEx (HWND hwndTo, HWND hwndFrom, UINT uCode,
-                             LPNMHDR lpHdr, DWORD dwParam5)
-{
-    NOTIFYDATA notify;
-    HWND hwndNotify;
-
-    TRACE("(%p %p %d %p 0x%08lx)\n",
-	   hwndFrom, hwndTo, uCode, lpHdr, dwParam5);
-
-    hwndNotify = hwndTo;
-    if (!hwndTo) {
-	if (IsWindow (hwndFrom)) {
-	    hwndNotify = GetParent (hwndFrom);
-	    if (!hwndNotify)
-		return 0;
-	}
+    hwndNotify = hwndTo;
+    if (!hwndTo) {
+	if (IsWindow (hwndFrom)) {
+	    hwndNotify = GetParent (hwndFrom);
+	    if (!hwndNotify)
+		return 0;
+	}
     }
 
     notify.hwndFrom = hwndFrom;
@@ -2454,120 +1243,3 @@
 
     return DoNotify (&notify, uCode, lpHdr);
 }
-
-
-
-
-/**************************************************************************
- * DPA_EnumCallback [COMCTL32.385]
- *
- * Enumerates all items in a dynamic pointer array.
- *
- * PARAMS
- *     hdpa     [I] handle to the dynamic pointer array
- *     enumProc [I]
- *     lParam   [I]
- *
- * RETURNS
- *     none
- */
-VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
-                              LPVOID lParam)
-{
-    INT i;
-
-    TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
-
-    if (!hdpa)
-	return;
-    if (hdpa->nItemCount <= 0)
-	return;
-
-    for (i = 0; i < hdpa->nItemCount; i++) {
-	if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
-	    return;
-    }
-
-    return;
-}
-
-
-/**************************************************************************
- * DPA_DestroyCallback [COMCTL32.386]
- *
- * Enumerates all items in a dynamic pointer array and destroys it.
- *
- * PARAMS
- *     hdpa     [I] handle to the dynamic pointer array
- *     enumProc [I]
- *     lParam   [I]
- *
- * RETURNS
- *     none
- */
-void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
-                                 LPVOID lParam)
-{
-    TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
-
-    DPA_EnumCallback (hdpa, enumProc, lParam);
-    DPA_Destroy (hdpa);
-}
-
-
-/**************************************************************************
- * DSA_EnumCallback [COMCTL32.387]
- *
- * Enumerates all items in a dynamic storage array.
- *
- * PARAMS
- *     hdsa     [I] handle to the dynamic storage array
- *     enumProc [I]
- *     lParam   [I]
- *
- * RETURNS
- *     none
- */
-VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
-                              LPVOID lParam)
-{
-    INT i;
-
-    TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
-
-    if (!hdsa)
-	return;
-    if (hdsa->nItemCount <= 0)
-	return;
-
-    for (i = 0; i < hdsa->nItemCount; i++) {
-	LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
-	if ((enumProc)(lpItem, lParam) == 0)
-	    return;
-    }
-
-    return;
-}
-
-
-/**************************************************************************
- * DSA_DestroyCallback [COMCTL32.388]
- *
- * Enumerates all items in a dynamic storage array and destroys it.
- *
- * PARAMS
- *     hdsa     [I] handle to the dynamic storage array
- *     enumProc [I]
- *     lParam   [I]
- *
- * RETURNS
- *     none
- */
-void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
-                                 LPVOID lParam)
-{
-    TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
-
-    DSA_EnumCallback (hdsa, enumProc, lParam);
-    DSA_Destroy (hdsa);
-}
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ dpa.c	2005-07-04 19:42:13.000000000 +0200
@@ -0,0 +1,978 @@
+/*
+ * Dynamic pointer array (DPA) implementation
+ *
+ * Copyright 1998 Eric Kohl
+ *           1998 Juergen Schmied <j.schmied at 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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=%lu dwData2=%lu dwItems=%lu\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=%lx\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 %08lx %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;
+    if (!hdpa->ptrs) {
+        WARN("no pointer array.\n");
+        return NULL;
+    }
+    if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
+        WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
+        return NULL;
+    }
+
+    TRACE("-- %p\n", hdpa->ptrs[nIndex]);
+
+    return hdpa->ptrs[nIndex];
+}
+
+
+/**************************************************************************
+ * DPA_GetPtrIndex [COMCTL32.333]
+ *
+ * Retrieves the index of the specified pointer
+ *
+ * PARAMS
+ *     hdpa   [I] handle (pointer) to the pointer array
+ *     p      [I] pointer
+ *
+ * RETURNS
+ *     Success: index of the specified pointer
+ *     Failure: -1
+ */
+INT WINAPI DPA_GetPtrIndex (const HDPA hdpa, LPVOID p)
+{
+    INT i;
+
+    if (!hdpa || !hdpa->ptrs)
+        return -1;
+
+    for (i = 0; i < hdpa->nItemCount; i++) {
+        if (hdpa->ptrs[i] == p)
+            return i;
+    }
+
+    return -1;
+}
+
+
+/**************************************************************************
+ * DPA_InsertPtr [COMCTL32.334]
+ *
+ * Inserts a pointer into a dynamic pointer array
+ *
+ * PARAMS
+ *     hdpa [I] handle (pointer) to the array
+ *     i    [I] array index
+ *     p    [I] pointer to insert
+ *
+ * RETURNS
+ *     Success: index of the inserted pointer
+ *     Failure: -1
+ */
+INT WINAPI DPA_InsertPtr (const HDPA hdpa, INT i, LPVOID p)
+{
+    TRACE("(%p %d %p)\n", hdpa, i, p);
+
+    if (!hdpa || i < 0) return -1;
+
+    if (i >= 0x7fff)
+        i = hdpa->nItemCount;
+
+    if (i >= hdpa->nItemCount)
+        return DPA_SetPtr(hdpa, i, p) ? i : -1;
+
+    /* create empty spot at the end */
+    if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
+    memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i, (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
+    hdpa->ptrs[i] = p;
+    return i;
+}
+
+
+/**************************************************************************
+ * DPA_SetPtr [COMCTL32.335]
+ *
+ * Sets a pointer in the pointer array
+ *
+ * PARAMS
+ *     hdpa [I] handle (pointer) to the pointer array
+ *     i    [I] index of the pointer that will be set
+ *     p    [I] pointer to be set
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DPA_SetPtr (const HDPA hdpa, INT i, LPVOID p)
+{
+    LPVOID *lpTemp;
+
+    TRACE("(%p %d %p)\n", hdpa, i, p);
+
+    if (!hdpa || i < 0 || i > 0x7fff)
+        return FALSE;
+
+    if (hdpa->nItemCount <= i) {
+        /* within the old array */
+        if (hdpa->nMaxCount <= i) {
+            /* resize the block of memory */
+            INT nNewItems =
+                hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
+            INT nSize = nNewItems * sizeof(LPVOID);
+
+            if (hdpa->ptrs)
+                lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
+            else
+                lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
+            
+            if (!lpTemp)
+                return FALSE;
+
+            hdpa->nMaxCount = nNewItems;
+            hdpa->ptrs = lpTemp;
+        }
+        hdpa->nItemCount = i+1;
+    }
+
+    /* put the new entry in */
+    hdpa->ptrs[i] = p;
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * DPA_DeletePtr [COMCTL32.336]
+ *
+ * Removes a pointer from the pointer array.
+ *
+ * PARAMS
+ *     hdpa [I] handle (pointer) to the pointer array
+ *     i    [I] index of the pointer that will be deleted
+ *
+ * RETURNS
+ *     Success: deleted pointer
+ *     Failure: NULL
+ */
+LPVOID WINAPI DPA_DeletePtr (const HDPA hdpa, INT i)
+{
+    LPVOID *lpDest, *lpSrc, lpTemp = NULL;
+    INT  nSize;
+
+    TRACE("(%p %d)\n", hdpa, i);
+
+    if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
+        return NULL;
+
+    lpTemp = hdpa->ptrs[i];
+
+    /* do we need to move ?*/
+    if (i < hdpa->nItemCount - 1) {
+        lpDest = hdpa->ptrs + i;
+        lpSrc = lpDest + 1;
+        nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
+        TRACE("-- move dest=%p src=%p size=%x\n",
+               lpDest, lpSrc, nSize);
+        memmove (lpDest, lpSrc, nSize);
+    }
+
+    hdpa->nItemCount --;
+
+    /* free memory ?*/
+    if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
+        INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
+        nSize = nNewItems * sizeof(LPVOID);
+        lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
+                                      hdpa->ptrs, nSize);
+        if (!lpDest)
+            return NULL;
+
+        hdpa->nMaxCount = nNewItems;
+        hdpa->ptrs = (LPVOID*)lpDest;
+    }
+
+    return lpTemp;
+}
+
+
+/**************************************************************************
+ * DPA_DeleteAllPtrs [COMCTL32.337]
+ *
+ * Removes all pointers and reinitializes the array.
+ *
+ * PARAMS
+ *     hdpa [I] handle (pointer) to the pointer array
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DPA_DeleteAllPtrs (const HDPA hdpa)
+{
+    TRACE("(%p)\n", hdpa);
+
+    if (!hdpa)
+        return FALSE;
+
+    if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
+        return FALSE;
+
+    hdpa->nItemCount = 0;
+    hdpa->nMaxCount = hdpa->nGrow * 2;
+    hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
+                                     hdpa->nMaxCount * sizeof(LPVOID));
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * DPA_QuickSort [Internal]
+ *
+ * Ordinary quicksort (used by DPA_Sort).
+ *
+ * PARAMS
+ *     lpPtrs     [I] pointer to the pointer array
+ *     l          [I] index of the "left border" of the partition
+ *     r          [I] index of the "right border" of the partition
+ *     pfnCompare [I] pointer to the compare function
+ *     lParam     [I] user defined value (3rd parameter in compare function)
+ *
+ * RETURNS
+ *     NONE
+ */
+static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
+                           PFNDPACOMPARE pfnCompare, LPARAM lParam)
+{
+    INT m;
+    LPVOID t;
+
+    TRACE("l=%i r=%i\n", l, r);
+
+    if (l==r)    /* one element is always sorted */
+        return;
+    if (r<l)     /* oops, got it in the wrong order */
+        {
+        DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
+        return;
+        }
+    m = (l+r)/2; /* divide by two */
+    DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
+    DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
+
+    /* join the two sides */
+    while( (l<=m) && (m<r) )
+    {
+        if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
+        {
+            t = lpPtrs[m+1];
+            memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l]));
+            lpPtrs[l] = t;
+
+            m++;
+        }
+        l++;
+    }
+}
+
+
+/**************************************************************************
+ * DPA_Sort [COMCTL32.338]
+ *
+ * Sorts a pointer array using a user defined compare function
+ *
+ * PARAMS
+ *     hdpa       [I] handle (pointer) to the pointer array
+ *     pfnCompare [I] pointer to the compare function
+ *     lParam     [I] user defined value (3rd parameter of compare function)
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DPA_Sort (const HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
+{
+    if (!hdpa || !pfnCompare)
+        return FALSE;
+
+    TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
+
+    if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
+        DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
+                       pfnCompare, lParam);
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * DPA_Search [COMCTL32.339]
+ *
+ * Searches a pointer array for a specified pointer
+ *
+ * PARAMS
+ *     hdpa       [I] handle (pointer) to the pointer array
+ *     pFind      [I] pointer to search for
+ *     nStart     [I] start index
+ *     pfnCompare [I] pointer to the compare function
+ *     lParam     [I] user defined value (3rd parameter of compare function)
+ *     uOptions   [I] search options
+ *
+ * RETURNS
+ *     Success: index of the pointer in the array.
+ *     Failure: -1
+ *
+ * NOTES
+ *     Binary search taken from R.Sedgewick "Algorithms in C"!
+ *     Function is NOT tested!
+ *     If something goes wrong, blame HIM not ME! (Eric Kohl)
+ */
+INT WINAPI DPA_Search (const HDPA hdpa, LPVOID pFind, INT nStart,
+                       PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
+{
+    if (!hdpa || !pfnCompare || !pFind)
+        return -1;
+
+    TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
+           hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
+
+    if (uOptions & DPAS_SORTED) {
+        /* array is sorted --> use binary search */
+        INT l, r, x, n;
+        LPVOID *lpPtr;
+
+        TRACE("binary search\n");
+
+        l = (nStart == -1) ? 0 : nStart;
+        r = hdpa->nItemCount - 1;
+        lpPtr = hdpa->ptrs;
+        while (r >= l) {
+            x = (l + r) / 2;
+            n = (pfnCompare)(pFind, lpPtr[x], lParam);
+            if (n < 0)
+                r = x - 1;
+            else
+                l = x + 1;
+            if (n == 0) {
+                TRACE("-- ret=%d\n", n);
+                return n;
+            }
+        }
+
+        if (uOptions & DPAS_INSERTBEFORE) {
+            if (r == -1) r = 0;
+            TRACE("-- ret=%d\n", r);
+            return r;
+        }
+
+        if (uOptions & DPAS_INSERTAFTER) {
+            TRACE("-- ret=%d\n", l);
+            return l;
+        }
+    }
+    else {
+        /* array is not sorted --> use linear search */
+        LPVOID *lpPtr;
+        INT  nIndex;
+
+        TRACE("linear search\n");
+
+        nIndex = (nStart == -1)? 0 : nStart;
+        lpPtr = hdpa->ptrs;
+        for (; nIndex < hdpa->nItemCount; nIndex++) {
+            if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0) {
+                TRACE("-- ret=%d\n", nIndex);
+                return nIndex;
+            }
+        }
+    }
+
+    TRACE("-- not found: ret=-1\n");
+    return -1;
+}
+
+
+/**************************************************************************
+ * DPA_CreateEx [COMCTL32.340]
+ *
+ * Creates a dynamic pointer array using the specified size and heap.
+ *
+ * PARAMS
+ *     nGrow [I] number of items by which the array grows when it is filled
+ *     hHeap [I] handle to the heap where the array is stored
+ *
+ * RETURNS
+ *     Success: handle (pointer) to the pointer array.
+ *     Failure: NULL
+ *
+ * NOTES
+ *     The DPA_ functions can be used to create and manipulate arrays of
+ *     pointers.
+ */
+HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap)
+{
+    HDPA hdpa;
+
+    TRACE("(%d %p)\n", nGrow, hHeap);
+
+    if (hHeap)
+        hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa));
+    else
+        hdpa = Alloc (sizeof(*hdpa));
+
+    if (hdpa) {
+        hdpa->nGrow = max(8, nGrow);
+        hdpa->hHeap = hHeap ? hHeap : GetProcessHeap();
+        hdpa->nMaxCount = hdpa->nGrow * 2;
+        hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
+                                hdpa->nMaxCount * sizeof(LPVOID));
+    }
+
+    TRACE("-- %p\n", hdpa);
+
+    return hdpa;
+}
+
+
+/**************************************************************************
+ * DPA_Create [COMCTL32.328]
+ *
+ * Creates a dynamic pointer array.
+ *
+ * PARAMS
+ *     nGrow [I] number of items by which the array grows when it is filled
+ *
+ * RETURNS
+ *     Success: handle (pointer) to the pointer array.
+ *     Failure: NULL
+ *
+ * NOTES
+ *     The DPA_ functions can be used to create and manipulate arrays of
+ *     pointers.
+ */
+HDPA WINAPI DPA_Create (INT nGrow)
+{
+    return DPA_CreateEx( nGrow, 0 );
+}
+
+
+/**************************************************************************
+ * DPA_EnumCallback [COMCTL32.385]
+ *
+ * Enumerates all items in a dynamic pointer array.
+ *
+ * PARAMS
+ *     hdpa     [I] handle to the dynamic pointer array
+ *     enumProc [I]
+ *     lParam   [I]
+ *
+ * RETURNS
+ *     none
+ */
+VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
+                              LPVOID lParam)
+{
+    INT i;
+
+    TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
+
+    if (!hdpa)
+	return;
+    if (hdpa->nItemCount <= 0)
+	return;
+
+    for (i = 0; i < hdpa->nItemCount; i++) {
+	if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
+	    return;
+    }
+
+    return;
+}
+
+
+/**************************************************************************
+ * DPA_DestroyCallback [COMCTL32.386]
+ *
+ * Enumerates all items in a dynamic pointer array and destroys it.
+ *
+ * PARAMS
+ *     hdpa     [I] handle to the dynamic pointer array
+ *     enumProc [I]
+ *     lParam   [I]
+ *
+ * RETURNS
+ *     none
+ */
+void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
+                                 LPVOID lParam)
+{
+    TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
+
+    DPA_EnumCallback (hdpa, enumProc, lParam);
+    DPA_Destroy (hdpa);
+}
--- /dev/null	1970-01-01 01:00:00.000000000 +0100
+++ dsa.c	2005-07-04 19:46:53.000000000 +0200
@@ -0,0 +1,436 @@
+/*
+ * Dynamic structure array (DSA) implementation
+ *
+ * Copyright 1998 Eric Kohl
+ *           1998 Juergen Schmied <j.schmied at 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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  
+ */
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "commctrl.h"
+
+#include "comctl32.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dsa);
+
+struct _DSA
+{
+    INT  nItemCount;
+    LPVOID pData;
+    INT  nMaxCount;
+    INT  nItemSize;
+    INT  nGrow;
+};
+
+/**************************************************************************
+ * DSA_Create [COMCTL32.320]
+ *
+ * Creates a dynamic storage array
+ *
+ * PARAMS
+ *     nSize [I] size of the array elements
+ *     nGrow [I] number of elements by which the array grows when it is filled
+ *
+ * RETURNS
+ *     Success: pointer to an array control structure. Use this like a handle.
+ *     Failure: NULL
+ *
+ * NOTES
+ *     The DSA_ functions can be used to create and manipulate arrays of
+ *     fixed-size memory blocks. These arrays can store any kind of data
+ *     (e.g. strings and icons).
+ */
+HDSA WINAPI DSA_Create (INT nSize, INT nGrow)
+{
+    HDSA hdsa;
+
+    TRACE("(size=%d grow=%d)\n", nSize, nGrow);
+
+    hdsa = Alloc (sizeof(*hdsa));
+    if (hdsa)
+    {
+        hdsa->nItemCount = 0;
+        hdsa->pData = NULL;
+        hdsa->nMaxCount = 0;
+        hdsa->nItemSize = nSize;
+        hdsa->nGrow = max(1, nGrow);
+    }
+
+    return hdsa;
+}
+
+
+/**************************************************************************
+ * DSA_Destroy [COMCTL32.321]
+ * 
+ * Destroys a dynamic storage array
+ *
+ * PARAMS
+ *     hdsa [I] pointer to the array control structure
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DSA_Destroy (const HDSA hdsa)
+{
+    TRACE("(%p)\n", hdsa);
+
+    if (!hdsa)
+        return FALSE;
+
+    if (hdsa->pData && (!Free (hdsa->pData)))
+        return FALSE;
+
+    return Free (hdsa);
+}
+
+
+/**************************************************************************
+ * DSA_GetItem [COMCTL32.322]
+ *
+ * Copies the specified item into a caller-supplied buffer.
+ *
+ * PARAMS
+ *     hdsa   [I] pointer to the array control structure
+ *     nIndex [I] number of the Item to get
+ *     pDest  [O] destination buffer. Has to be >= dwElementSize.
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DSA_GetItem (const HDSA hdsa, INT nIndex, LPVOID pDest)
+{
+    LPVOID pSrc;
+
+    TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
+
+    if (!hdsa)
+        return FALSE;
+    if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
+        return FALSE;
+
+    pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
+    memmove (pDest, pSrc, hdsa->nItemSize);
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * DSA_GetItemPtr [COMCTL32.323]
+ *
+ * Retrieves a pointer to the specified item.
+ *
+ * PARAMS
+ *     hdsa   [I] pointer to the array control structure
+ *     nIndex [I] index of the desired item
+ *
+ * RETURNS
+ *     Success: pointer to an item
+ *     Failure: NULL
+ */
+LPVOID WINAPI DSA_GetItemPtr (const HDSA hdsa, INT nIndex)
+{
+    LPVOID pSrc;
+
+    TRACE("(%p %d)\n", hdsa, nIndex);
+
+    if (!hdsa)
+        return NULL;
+    if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
+        return NULL;
+
+    pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
+
+    TRACE("-- ret=%p\n", pSrc);
+
+    return pSrc;
+}
+
+
+/**************************************************************************
+ * DSA_SetItem [COMCTL32.325]
+ *
+ * Sets the contents of an item in the array.
+ *
+ * PARAMS
+ *     hdsa   [I] pointer to the array control structure
+ *     nIndex [I] index for the item
+ *     pSrc   [I] pointer to the new item data
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DSA_SetItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
+{
+    INT  nSize, nNewItems;
+    LPVOID pDest, lpTemp;
+
+    TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
+
+    if ((!hdsa) || nIndex < 0)
+        return FALSE;
+
+    if (hdsa->nItemCount <= nIndex) {
+        /* within the old array */
+        if (hdsa->nMaxCount > nIndex) {
+            /* within the allocated space, set a new boundary */
+            hdsa->nItemCount = nIndex + 1;
+        }
+        else {
+            /* resize the block of memory */
+            nNewItems =
+                hdsa->nGrow * ((INT)(((nIndex + 1) - 1) / hdsa->nGrow) + 1);
+            nSize = hdsa->nItemSize * nNewItems;
+
+            lpTemp = ReAlloc (hdsa->pData, nSize);
+            if (!lpTemp)
+                return FALSE;
+
+            hdsa->nMaxCount = nNewItems;
+            hdsa->nItemCount = nIndex + 1;
+            hdsa->pData = lpTemp;
+        }
+    }
+
+    /* put the new entry in */
+    pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
+    TRACE("-- move dest=%p src=%p size=%d\n",
+           pDest, pSrc, hdsa->nItemSize);
+    memmove (pDest, pSrc, hdsa->nItemSize);
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * DSA_InsertItem [COMCTL32.324]
+ *
+ * Inserts an item into the array at the specified index.
+ *
+ * PARAMS
+ *     hdsa   [I] pointer to the array control structure
+ *     nIndex [I] index for the new item
+ *     pSrc   [I] pointer to the element
+ *
+ * RETURNS
+ *     Success: position of the new item
+ *     Failure: -1
+ */
+INT WINAPI DSA_InsertItem (const HDSA hdsa, INT nIndex, LPVOID pSrc)
+{
+    INT   nNewItems, nSize;
+    LPVOID  lpTemp, lpDest;
+
+    TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
+
+    if ((!hdsa) || nIndex < 0)
+        return -1;
+
+    /* when nIndex >= nItemCount then append */
+    if (nIndex >= hdsa->nItemCount)
+         nIndex = hdsa->nItemCount;
+
+    /* do we need to resize ? */
+    if (hdsa->nItemCount >= hdsa->nMaxCount) {
+        nNewItems = hdsa->nMaxCount + hdsa->nGrow;
+        nSize = hdsa->nItemSize * nNewItems;
+
+        lpTemp = ReAlloc (hdsa->pData, nSize);
+        if (!lpTemp)
+            return -1;
+
+        hdsa->nMaxCount = nNewItems;
+        hdsa->pData = lpTemp;
+    }
+
+    /* do we need to move elements ? */
+    if (nIndex < hdsa->nItemCount) {
+        lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
+        lpDest = (char *) lpTemp + hdsa->nItemSize;
+        nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
+        TRACE("-- move dest=%p src=%p size=%d\n",
+               lpDest, lpTemp, nSize);
+        memmove (lpDest, lpTemp, nSize);
+    }
+
+    /* ok, we can put the new Item in */
+    hdsa->nItemCount++;
+    lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
+    TRACE("-- move dest=%p src=%p size=%d\n",
+           lpDest, pSrc, hdsa->nItemSize);
+    memmove (lpDest, pSrc, hdsa->nItemSize);
+
+    return nIndex;
+}
+
+
+/**************************************************************************
+ * DSA_DeleteItem [COMCTL32.326]
+ *
+ * Deletes the specified item from the array.
+ *
+ * PARAMS
+ *     hdsa   [I] pointer to the array control structure
+ *     nIndex [I] index for the element to delete
+ *
+ * RETURNS
+ *     Success: number of the deleted element
+ *     Failure: -1
+ */
+INT WINAPI DSA_DeleteItem (const HDSA hdsa, INT nIndex)
+{
+    LPVOID lpDest,lpSrc;
+    INT  nSize;
+
+    TRACE("(%p %d)\n", hdsa, nIndex);
+
+    if (!hdsa)
+        return -1;
+    if (nIndex < 0 || nIndex >= hdsa->nItemCount)
+        return -1;
+
+    /* do we need to move ? */
+    if (nIndex < hdsa->nItemCount - 1) {
+        lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
+        lpSrc = (char *) lpDest + hdsa->nItemSize;
+        nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
+        TRACE("-- move dest=%p src=%p size=%d\n",
+               lpDest, lpSrc, nSize);
+        memmove (lpDest, lpSrc, nSize);
+    }
+
+    hdsa->nItemCount--;
+
+    /* free memory ? */
+    if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
+        nSize = hdsa->nItemSize * hdsa->nItemCount;
+
+        lpDest = ReAlloc (hdsa->pData, nSize);
+        if (!lpDest)
+            return -1;
+
+        hdsa->nMaxCount = hdsa->nItemCount;
+        hdsa->pData = lpDest;
+    }
+
+    return nIndex;
+}
+
+
+/**************************************************************************
+ * DSA_DeleteAllItems [COMCTL32.327]
+ *
+ * Removes all items and reinitializes the array.
+ *
+ * PARAMS
+ *     hdsa [I] pointer to the array control structure
+ *
+ * RETURNS
+ *     Success: TRUE
+ *     Failure: FALSE
+ */
+BOOL WINAPI DSA_DeleteAllItems (const HDSA hdsa)
+{
+    TRACE("(%p)\n", hdsa);
+
+    if (!hdsa)
+        return FALSE;
+    if (hdsa->pData && (!Free (hdsa->pData)))
+        return FALSE;
+
+    hdsa->nItemCount = 0;
+    hdsa->pData = NULL;
+    hdsa->nMaxCount = 0;
+
+    return TRUE;
+}
+
+
+/**************************************************************************
+ * DSA_EnumCallback [COMCTL32.387]
+ *
+ * Enumerates all items in a dynamic storage array.
+ *
+ * PARAMS
+ *     hdsa     [I] handle to the dynamic storage array
+ *     enumProc [I]
+ *     lParam   [I]
+ *
+ * RETURNS
+ *     none
+ */
+VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
+                              LPVOID lParam)
+{
+    INT i;
+
+    TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
+
+    if (!hdsa)
+        return;
+    if (hdsa->nItemCount <= 0)
+        return;
+
+    for (i = 0; i < hdsa->nItemCount; i++) {
+        LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
+        if ((enumProc)(lpItem, lParam) == 0)
+            return;
+    }
+
+    return;
+}
+
+
+/**************************************************************************
+ * DSA_DestroyCallback [COMCTL32.388]
+ *
+ * Enumerates all items in a dynamic storage array and destroys it.
+ *
+ * PARAMS
+ *     hdsa     [I] handle to the dynamic storage array
+ *     enumProc [I]
+ *     lParam   [I]
+ *
+ * RETURNS
+ *     none
+ */
+void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
+                                 LPVOID lParam)
+{
+    TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
+
+    DSA_EnumCallback (hdsa, enumProc, lParam);
+    DSA_Destroy (hdsa);
+}


More information about the wine-patches mailing list