mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 11:43:31 +00:00
Implement/document @17,18,19,20,21,22 (Compact list API).
This commit is contained in:
parent
5da88a2cb9
commit
2d990806ec
6 changed files with 897 additions and 78 deletions
|
@ -12,6 +12,7 @@ LDDLLFLAGS = @LDDLLFLAGS@
|
|||
SYMBOLFILE = $(MODULE).tmp.o
|
||||
|
||||
C_SRCS = \
|
||||
clist.c \
|
||||
ordinal.c \
|
||||
path.c \
|
||||
reg.c \
|
||||
|
@ -24,6 +25,7 @@ C_SRCS = \
|
|||
EXTRASUBDIRS = tests
|
||||
|
||||
CTESTS = \
|
||||
tests/clist.c \
|
||||
tests/shreg.c
|
||||
|
||||
@MAKE_DLL_RULES@
|
||||
|
|
434
dlls/shlwapi/clist.c
Normal file
434
dlls/shlwapi/clist.c
Normal file
|
@ -0,0 +1,434 @@
|
|||
/*
|
||||
* SHLWAPI Compact List functions
|
||||
*
|
||||
* Copyright 2002 Jon Griffiths
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "windef.h"
|
||||
#include "winbase.h"
|
||||
#include "winuser.h"
|
||||
#include "wine/obj_base.h"
|
||||
#include "wine/obj_storage.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
||||
|
||||
/* Compact list element (ordinals 17-22) */
|
||||
typedef struct tagSHLWAPI_CLIST
|
||||
{
|
||||
ULONG ulSize; /* Size of this list element and its data */
|
||||
ULONG ulId; /* If -1, The real element follows */
|
||||
/* Item data (or a contained SHLWAPI_CLIST) follows... */
|
||||
} SHLWAPI_CLIST, *LPSHLWAPI_CLIST;
|
||||
|
||||
typedef const SHLWAPI_CLIST* LPCSHLWAPI_CLIST;
|
||||
|
||||
/* ulId for contained SHLWAPI_CLIST items */
|
||||
static const ULONG CLIST_ID_CONTAINER = -1u;
|
||||
|
||||
HRESULT WINAPI SHLWAPI_20(LPSHLWAPI_CLIST*,LPCSHLWAPI_CLIST);
|
||||
|
||||
/*************************************************************************
|
||||
* NextItem
|
||||
*
|
||||
* Internal helper: move a clist pointer to the next item.
|
||||
*/
|
||||
inline static LPSHLWAPI_CLIST NextItem(LPCSHLWAPI_CLIST lpList)
|
||||
{
|
||||
const char* address = (char*)lpList;
|
||||
address += lpList->ulSize;
|
||||
return (LPSHLWAPI_CLIST)address;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.17]
|
||||
*
|
||||
* Write a compact list to a stream.
|
||||
*
|
||||
* PARAMS
|
||||
* lpStream [I] Stream to write the list to
|
||||
* lpList [I] List of items to write
|
||||
*
|
||||
* RETURNS
|
||||
* Success: S_OK
|
||||
* Failure: An HRESULT error code
|
||||
*
|
||||
* NOTES
|
||||
* Ordinals 17,18,19,20,21 and 22 are related and together provide a compact
|
||||
* list structure which may be stored and retrieved from a stream.
|
||||
*
|
||||
* The exposed API consists of:
|
||||
* @17 Write a compact list to a stream
|
||||
* @18 Read and create a list from a stream
|
||||
* @19 Free a list
|
||||
* @20 Insert a new item into a list
|
||||
* @21 Remove an item from a list
|
||||
* @22 Find an item in a list
|
||||
*
|
||||
* The compact list is stored packed into a memory array. Each element has a
|
||||
* size and an associated ID. Elements must be less than 64k if the list is
|
||||
* to be subsequently read from a stream.
|
||||
*
|
||||
* Elements are aligned on DWORD boundaries. If an elements data size is not
|
||||
* a DWORD size multiple, the element is wrapped by inserting a surrounding
|
||||
* element with an Id of -1, and size sufficient to pad to a DWORD boundary.
|
||||
*
|
||||
* These functions are slow for large objects and long lists.
|
||||
*/
|
||||
HRESULT WINAPI SHLWAPI_17(IStream* lpStream, LPSHLWAPI_CLIST lpList)
|
||||
{
|
||||
ULONG ulSize;
|
||||
HRESULT hRet = E_FAIL;
|
||||
|
||||
TRACE("(%p,%p)\n", lpStream, lpList);
|
||||
|
||||
if(lpList)
|
||||
{
|
||||
while (lpList->ulSize)
|
||||
{
|
||||
LPSHLWAPI_CLIST lpItem = lpList;
|
||||
|
||||
if(lpList->ulId == CLIST_ID_CONTAINER)
|
||||
lpItem++;
|
||||
|
||||
hRet = IStream_Write(lpStream,lpItem,lpItem->ulSize,&ulSize);
|
||||
if (FAILED(hRet))
|
||||
return hRet;
|
||||
|
||||
if(lpItem->ulSize != ulSize)
|
||||
return STG_E_MEDIUMFULL;
|
||||
|
||||
lpList = NextItem(lpList);
|
||||
}
|
||||
}
|
||||
|
||||
if(SUCCEEDED(hRet))
|
||||
{
|
||||
ULONG ulDummy;
|
||||
ulSize = 0;
|
||||
|
||||
/* Write a terminating list entry with zero size */
|
||||
hRet = IStream_Write(lpStream, &ulSize,sizeof(ulSize),&ulDummy);
|
||||
}
|
||||
|
||||
return hRet;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.18]
|
||||
*
|
||||
* Read and create a compact list from a stream
|
||||
*
|
||||
* PARAMS
|
||||
* lpStream [I] Stream to read the list from
|
||||
* lppList [0] Pointer to recieve the new List
|
||||
*
|
||||
* RETURNS
|
||||
* Success: S_OK
|
||||
* Failure: An HRESULT error code
|
||||
*
|
||||
* NOTES
|
||||
* When read from a file, list objects are limited in size to 64k.
|
||||
*/
|
||||
HRESULT WINAPI SHLWAPI_18(IStream* lpStream, LPSHLWAPI_CLIST* lppList)
|
||||
{
|
||||
SHLWAPI_CLIST bBuff[128]; /* Temporary storage for new list item */
|
||||
ULONG ulBuffSize = sizeof(bBuff);
|
||||
LPSHLWAPI_CLIST pItem = bBuff;
|
||||
ULONG ulRead, ulSize;
|
||||
HRESULT hRet = S_OK;
|
||||
|
||||
TRACE("(%p,%p)\n", lpStream, lppList);
|
||||
|
||||
if(*lppList)
|
||||
{
|
||||
/* Free any existing list */
|
||||
LocalFree((HLOCAL)*lppList);
|
||||
*lppList = NULL;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* Read the size of the next item */
|
||||
hRet = IStream_Read(lpStream, &ulSize,sizeof(ulSize),&ulRead);
|
||||
|
||||
if(FAILED(hRet) || ulRead != sizeof(ulSize) || !ulSize)
|
||||
break; /* Read failed or read zero size (the end of the list) */
|
||||
|
||||
if(ulSize > 0xFFFF)
|
||||
{
|
||||
LARGE_INTEGER liZero;
|
||||
ULARGE_INTEGER ulPos;
|
||||
|
||||
liZero.QuadPart = 0;
|
||||
|
||||
/* Back the stream up; this object is too big for the list */
|
||||
if(SUCCEEDED(IStream_Seek(lpStream, liZero, STREAM_SEEK_CUR, &ulPos)))
|
||||
{
|
||||
liZero.QuadPart = ulPos.QuadPart - sizeof(ULONG);
|
||||
IStream_Seek(lpStream, liZero, STREAM_SEEK_SET, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
else if (ulSize >= sizeof(SHLWAPI_CLIST))
|
||||
{
|
||||
/* Add this new item to the list */
|
||||
if(ulSize > ulBuffSize)
|
||||
{
|
||||
/* We need more buffer space, allocate it */
|
||||
LPSHLWAPI_CLIST lpTemp;
|
||||
|
||||
if (pItem == bBuff)
|
||||
lpTemp = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT, ulSize);
|
||||
else
|
||||
lpTemp = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)pItem, ulSize,
|
||||
LMEM_ZEROINIT|LMEM_MOVEABLE);
|
||||
|
||||
if(!lpTemp)
|
||||
{
|
||||
hRet = E_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
ulBuffSize = ulSize;
|
||||
pItem = lpTemp;
|
||||
}
|
||||
|
||||
pItem->ulSize = ulSize;
|
||||
ulSize -= sizeof(pItem->ulSize); /* already read this member */
|
||||
|
||||
/* Read the item Id and data */
|
||||
hRet = IStream_Read(lpStream, &pItem->ulId, ulSize, &ulRead);
|
||||
|
||||
if(FAILED(hRet) || ulRead != ulSize)
|
||||
break;
|
||||
|
||||
SHLWAPI_20(lppList, pItem); /* Insert Item */
|
||||
}
|
||||
} while(1);
|
||||
|
||||
/* If we allocated space, free it */
|
||||
if(pItem != bBuff)
|
||||
LocalFree((HLOCAL)pItem);
|
||||
|
||||
return hRet;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.19]
|
||||
*
|
||||
* Free a compact list.
|
||||
*
|
||||
* PARAMS
|
||||
* lpList [I] List to free
|
||||
*
|
||||
* RETURNS
|
||||
* Nothing.
|
||||
*/
|
||||
VOID WINAPI SHLWAPI_19(LPSHLWAPI_CLIST lpList)
|
||||
{
|
||||
TRACE("(%p)\n", lpList);
|
||||
|
||||
if (lpList)
|
||||
LocalFree((HLOCAL)lpList);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.20]
|
||||
*
|
||||
* Insert a new item into a compact list.
|
||||
*
|
||||
* PARAMS
|
||||
* lppList [0] Pointer to the List
|
||||
* lpNewItem [I] The new item to add to the list
|
||||
*
|
||||
* RETURNS
|
||||
* Success: The size of the inserted item.
|
||||
* Failure: An HRESULT error code.
|
||||
*/
|
||||
HRESULT WINAPI SHLWAPI_20(LPSHLWAPI_CLIST* lppList, LPCSHLWAPI_CLIST lpNewItem)
|
||||
{
|
||||
LPSHLWAPI_CLIST lpInsertAt = NULL;
|
||||
ULONG ulSize;
|
||||
|
||||
TRACE("(%p,%p)\n", lppList, lpNewItem);
|
||||
|
||||
if(!lppList || !lpNewItem ||
|
||||
lpNewItem->ulId == CLIST_ID_CONTAINER ||
|
||||
lpNewItem->ulSize < sizeof(SHLWAPI_CLIST))
|
||||
return E_INVALIDARG;
|
||||
|
||||
ulSize = lpNewItem->ulSize;
|
||||
|
||||
if(ulSize & 0x3)
|
||||
{
|
||||
/* Tune size to a ULONG boundary, add space for container element */
|
||||
ulSize = ((ulSize + 0x3) & 0xFFFFFFFC) + sizeof(SHLWAPI_CLIST);
|
||||
TRACE("Creating container item, new size = %ld\n", ulSize);
|
||||
}
|
||||
|
||||
if(!*lppList)
|
||||
{
|
||||
/* An empty list. Allocate space for terminal ulSize also */
|
||||
*lppList = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT,
|
||||
ulSize + sizeof(ULONG));
|
||||
lpInsertAt = *lppList;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Append to the end of the list */
|
||||
ULONG ulTotalSize = 0;
|
||||
LPSHLWAPI_CLIST lpIter = *lppList;
|
||||
|
||||
/* Iterate to the end of the list, calculating the total size */
|
||||
while (lpIter->ulSize)
|
||||
{
|
||||
ulTotalSize += lpIter->ulSize;
|
||||
lpIter = NextItem(lpIter);
|
||||
}
|
||||
|
||||
/* Increase the size of the list */
|
||||
lpIter = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList,
|
||||
ulTotalSize + ulSize+sizeof(ULONG),
|
||||
LMEM_ZEROINIT | LMEM_MOVEABLE);
|
||||
if(lpIter)
|
||||
{
|
||||
*lppList = lpIter;
|
||||
lpInsertAt = (LPSHLWAPI_CLIST)((char*)lpIter + ulTotalSize); /* At end */
|
||||
}
|
||||
}
|
||||
|
||||
if(lpInsertAt)
|
||||
{
|
||||
/* Copy in the new item */
|
||||
LPSHLWAPI_CLIST lpDest = lpInsertAt;
|
||||
|
||||
if(ulSize != lpNewItem->ulSize)
|
||||
{
|
||||
lpInsertAt->ulSize = ulSize;
|
||||
lpInsertAt->ulId = CLIST_ID_CONTAINER;
|
||||
lpDest++;
|
||||
}
|
||||
memcpy(lpDest, lpNewItem, lpNewItem->ulSize);
|
||||
|
||||
/* Terminate the list */
|
||||
lpInsertAt = NextItem(lpInsertAt);
|
||||
lpInsertAt->ulSize = 0;
|
||||
|
||||
return lpNewItem->ulSize;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.21]
|
||||
*
|
||||
* Remove an item from a compact list.
|
||||
*
|
||||
* PARAMS
|
||||
* lppList [O] List to remove the item from
|
||||
* ulId [I] Id of item to remove
|
||||
*
|
||||
* RETURNS
|
||||
* Success: TRUE.
|
||||
* Failure: FALSE, If any parameters are invalid, or the item was not found.
|
||||
*/
|
||||
BOOL WINAPI SHLWAPI_21(LPSHLWAPI_CLIST* lppList, ULONG ulId)
|
||||
{
|
||||
LPSHLWAPI_CLIST lpList = 0;
|
||||
LPSHLWAPI_CLIST lpItem = NULL;
|
||||
LPSHLWAPI_CLIST lpNext;
|
||||
ULONG ulNewSize;
|
||||
|
||||
TRACE("(%p,%ld)\n", lppList, ulId);
|
||||
|
||||
if(lppList && (lpList = *lppList))
|
||||
{
|
||||
/* Search for item in list */
|
||||
while (lpList->ulSize)
|
||||
{
|
||||
if(lpList->ulId == ulId ||
|
||||
(lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId))
|
||||
{
|
||||
lpItem = lpList; /* Found */
|
||||
break;
|
||||
}
|
||||
lpList = NextItem(lpList);
|
||||
}
|
||||
}
|
||||
|
||||
if(!lpItem)
|
||||
return FALSE;
|
||||
|
||||
lpList = lpNext = NextItem(lpItem);
|
||||
|
||||
/* Locate the end of the list */
|
||||
while (lpList->ulSize)
|
||||
lpList = NextItem(lpList);
|
||||
|
||||
/* Resize the list */
|
||||
ulNewSize = LocalSize((HLOCAL)*lppList) - lpItem->ulSize;
|
||||
|
||||
/* Copy following elements over lpItem */
|
||||
memmove(lpItem, lpNext, (char *)lpList - (char *)lpNext + sizeof(ULONG));
|
||||
|
||||
if(ulNewSize <= sizeof(ULONG))
|
||||
{
|
||||
LocalFree((HLOCAL)*lppList);
|
||||
*lppList = NULL; /* Removed the last element */
|
||||
}
|
||||
else
|
||||
{
|
||||
lpList = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList, ulNewSize,
|
||||
LMEM_ZEROINIT|LMEM_MOVEABLE);
|
||||
if(lpList)
|
||||
*lppList = lpList;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.22]
|
||||
*
|
||||
* Find an item in a compact list.
|
||||
*
|
||||
* PARAMS
|
||||
* lpList [I] List to search
|
||||
* ulId [I] ID of item to find
|
||||
*
|
||||
* RETURNS
|
||||
* Success: A pointer to the list item found
|
||||
* Failure: NULL
|
||||
*/
|
||||
LPSHLWAPI_CLIST WINAPI SHLWAPI_22(LPSHLWAPI_CLIST lpList, ULONG ulId)
|
||||
{
|
||||
TRACE("(%p,%ld)\n", lpList, ulId);
|
||||
|
||||
if(lpList)
|
||||
{
|
||||
while(lpList->ulSize)
|
||||
{
|
||||
if(lpList->ulId == ulId)
|
||||
return lpList; /* Matched */
|
||||
else if(lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId)
|
||||
return lpList + 1; /* Contained item matches */
|
||||
|
||||
lpList = NextItem(lpList);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -737,78 +737,6 @@ HRESULT WINAPI SHLWAPI_16 (
|
|||
return 0xabba1252;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.18]
|
||||
*
|
||||
* w is pointer to address of callback routine
|
||||
* x is pointer to LPVOID to receive address of locally allocated
|
||||
* space size 0x14
|
||||
* return is 0 (unless out of memory???)
|
||||
*
|
||||
* related to _19, _21 and _22 below
|
||||
* only seen invoked by SHDOCVW
|
||||
*/
|
||||
LONG WINAPI SHLWAPI_18 (
|
||||
LPVOID *w,
|
||||
LPVOID x)
|
||||
{
|
||||
FIXME("(%p %p)stub\n",w,x);
|
||||
*((LPDWORD)x) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.19]
|
||||
*
|
||||
* w is address of allocated memory from _21
|
||||
* return is 0 (unless out of memory???)
|
||||
*
|
||||
* related to _18, _21 and _22 below
|
||||
* only seen invoked by SHDOCVW
|
||||
*/
|
||||
LONG WINAPI SHLWAPI_19 (
|
||||
LPVOID w)
|
||||
{
|
||||
FIXME("(%p) stub\n",w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.21]
|
||||
*
|
||||
* w points to space allocated via .18 above
|
||||
* LocalSize is done on it (retrieves 18)
|
||||
* LocalReAlloc is done on it to size 8 with LMEM_MOVEABLE & LMEM_ZEROINIT
|
||||
* x values seen 0xa0000005
|
||||
* returns 1
|
||||
*
|
||||
* relates to _18, _19 and _22 above and below
|
||||
* only seen invoked by SHDOCVW
|
||||
*/
|
||||
LONG WINAPI SHLWAPI_21 (
|
||||
LPVOID w,
|
||||
DWORD x)
|
||||
{
|
||||
FIXME("(%p %lx)stub\n",w,x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.22]
|
||||
*
|
||||
* return is 'w' value seen in x is 0xa0000005
|
||||
*
|
||||
* relates to _18, _19 and _21 above
|
||||
* only seen invoked by SHDOCVW
|
||||
*/
|
||||
LPVOID WINAPI SHLWAPI_22 (
|
||||
LPVOID w,
|
||||
DWORD x)
|
||||
{
|
||||
FIXME("(%p %lx)stub\n",w,x);
|
||||
return w;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* @ [SHLWAPI.23]
|
||||
*
|
||||
|
|
|
@ -16,12 +16,12 @@ init SHLWAPI_LibMain
|
|||
14 stdcall @(ptr ptr) SHLWAPI_14
|
||||
15 stdcall @(ptr ptr) SHLWAPI_15
|
||||
16 stdcall @(long long long long) SHLWAPI_16
|
||||
17 stub @
|
||||
18 stdcall @(ptr ptr) SHLWAPI_18
|
||||
19 stdcall @(ptr) SHLWAPI_19
|
||||
20 stub @
|
||||
21 stdcall @(ptr long) SHLWAPI_21
|
||||
22 stdcall @(ptr long) SHLWAPI_22
|
||||
17 stdcall @ (ptr ptr) SHLWAPI_17
|
||||
18 stdcall @ (ptr ptr) SHLWAPI_18
|
||||
19 stdcall @ (ptr) SHLWAPI_19
|
||||
20 stdcall @ (ptr ptr) SHLWAPI_20
|
||||
21 stdcall @ (ptr long) SHLWAPI_21
|
||||
22 stdcall @ (ptr long) SHLWAPI_22
|
||||
23 stdcall @(ptr ptr long) SHLWAPI_23
|
||||
24 stdcall @(ptr ptr long) SHLWAPI_24
|
||||
25 stdcall @(long) SHLWAPI_25
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
clist.ok
|
||||
shlwapi_test.exe.spec.c
|
||||
shreg.ok
|
||||
testlist.c
|
||||
|
|
454
dlls/shlwapi/tests/clist.c
Normal file
454
dlls/shlwapi/tests/clist.c
Normal file
|
@ -0,0 +1,454 @@
|
|||
/* Unit test suite for SHLWAPI Compact List functions
|
||||
*
|
||||
* Copyright 2002 Jon Griffiths
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "wine/test.h"
|
||||
#include "winbase.h"
|
||||
#include "objbase.h"
|
||||
|
||||
typedef struct tagSHLWAPI_CLIST
|
||||
{
|
||||
ULONG ulSize;
|
||||
ULONG ulId;
|
||||
} SHLWAPI_CLIST, *LPSHLWAPI_CLIST;
|
||||
|
||||
typedef const SHLWAPI_CLIST* LPCSHLWAPI_CLIST;
|
||||
|
||||
/* Items to add */
|
||||
static const SHLWAPI_CLIST SHLWAPI_CLIST_items[] =
|
||||
{
|
||||
{4, 1},
|
||||
{8, 3},
|
||||
{12, 2},
|
||||
{16, 8},
|
||||
{20, 9},
|
||||
{3, 11},
|
||||
{9, 82},
|
||||
{33, 16},
|
||||
{32, 55},
|
||||
{24, 100},
|
||||
{39, 116},
|
||||
{ 0, 0}
|
||||
};
|
||||
|
||||
/* Dummy IStream object for testing calls */
|
||||
typedef struct
|
||||
{
|
||||
void* lpVtbl;
|
||||
ULONG ref;
|
||||
int readcalls;
|
||||
BOOL failreadcall;
|
||||
BOOL failreadsize;
|
||||
BOOL readbeyondend;
|
||||
BOOL readreturnlarge;
|
||||
int writecalls;
|
||||
BOOL failwritecall;
|
||||
BOOL failwritesize;
|
||||
int seekcalls;
|
||||
int statcalls;
|
||||
LPCSHLWAPI_CLIST item;
|
||||
} _IDummyStream;
|
||||
|
||||
static
|
||||
HRESULT WINAPI QueryInterface(_IDummyStream *This,REFIID riid, LPVOID *ppvObj)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static ULONG WINAPI AddRef(_IDummyStream *This)
|
||||
{
|
||||
return ++This->ref;
|
||||
}
|
||||
|
||||
static ULONG WINAPI Release(_IDummyStream *This)
|
||||
{
|
||||
return --This->ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI Read(_IDummyStream* This, LPVOID lpMem, ULONG ulSize,
|
||||
LPULONG lpRead)
|
||||
{
|
||||
HRESULT hRet = S_OK;
|
||||
++This->readcalls;
|
||||
|
||||
if (This->failreadcall)
|
||||
{
|
||||
return STG_E_ACCESSDENIED;
|
||||
}
|
||||
else if (This->failreadsize)
|
||||
{
|
||||
*lpRead = ulSize + 8;
|
||||
return S_OK;
|
||||
}
|
||||
else if (This->readreturnlarge)
|
||||
{
|
||||
*((ULONG*)lpMem) = 0xffff01;
|
||||
*lpRead = ulSize;
|
||||
This->readreturnlarge = FALSE;
|
||||
return S_OK;
|
||||
}
|
||||
if (ulSize == sizeof(ULONG))
|
||||
{
|
||||
/* Read size of item */
|
||||
*((ULONG*)lpMem) = This->item->ulSize ? This->item->ulSize + sizeof(SHLWAPI_CLIST) : 0;
|
||||
*lpRead = ulSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int i;
|
||||
char* buff = (char*)lpMem;
|
||||
|
||||
/* Read item data */
|
||||
if (!This->item->ulSize)
|
||||
{
|
||||
This->readbeyondend = TRUE;
|
||||
*lpRead = 0;
|
||||
return E_FAIL; /* Should never happen */
|
||||
}
|
||||
*((ULONG*)lpMem) = This->item->ulId;
|
||||
*lpRead = ulSize;
|
||||
|
||||
for (i = 0; i < This->item->ulSize; i++)
|
||||
buff[4+i] = i*2;
|
||||
|
||||
This->item++;
|
||||
}
|
||||
return hRet;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI Write(_IDummyStream* This, LPVOID lpMem, ULONG ulSize,
|
||||
LPULONG lpWritten)
|
||||
{
|
||||
HRESULT hRet = S_OK;
|
||||
|
||||
++This->writecalls;
|
||||
if (This->failwritecall)
|
||||
{
|
||||
return STG_E_ACCESSDENIED;
|
||||
}
|
||||
else if (This->failwritesize)
|
||||
{
|
||||
*lpWritten = 0;
|
||||
}
|
||||
else
|
||||
*lpWritten = ulSize;
|
||||
return hRet;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI Seek(_IDummyStream* This, LARGE_INTEGER dlibMove,
|
||||
DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
|
||||
{
|
||||
++This->seekcalls;
|
||||
if (plibNewPosition)
|
||||
plibNewPosition->QuadPart = sizeof(ULONG);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI Stat(_IDummyStream* This, STATSTG* pstatstg,
|
||||
DWORD grfStatFlag)
|
||||
{
|
||||
++This->statcalls;
|
||||
if (pstatstg)
|
||||
pstatstg->cbSize.QuadPart = 5000l;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* VTable */
|
||||
static void* iclvt[] =
|
||||
{
|
||||
QueryInterface,
|
||||
AddRef,
|
||||
Release,
|
||||
Read,
|
||||
Write,
|
||||
Seek,
|
||||
NULL, /* SetSize */
|
||||
NULL, /* CopyTo */
|
||||
NULL, /* Commit */
|
||||
NULL, /* Revert */
|
||||
NULL, /* LockRegion */
|
||||
NULL, /* UnlockRegion */
|
||||
Stat,
|
||||
NULL /* Clone */
|
||||
};
|
||||
|
||||
/* Function ptrs for ordinal calls */
|
||||
static HMODULE SHLWAPI_hshlwapi = 0;
|
||||
|
||||
static VOID (WINAPI *pSHLWAPI_19)(LPSHLWAPI_CLIST);
|
||||
static HRESULT (WINAPI *pSHLWAPI_20)(LPSHLWAPI_CLIST*,LPCSHLWAPI_CLIST);
|
||||
static BOOL (WINAPI *pSHLWAPI_21)(LPSHLWAPI_CLIST*,ULONG);
|
||||
static LPSHLWAPI_CLIST (WINAPI *pSHLWAPI_22)(LPSHLWAPI_CLIST,ULONG);
|
||||
static HRESULT (WINAPI *pSHLWAPI_17)(_IDummyStream*,LPSHLWAPI_CLIST);
|
||||
static HRESULT (WINAPI *pSHLWAPI_18)(_IDummyStream*,LPSHLWAPI_CLIST*);
|
||||
|
||||
static void InitFunctionPtrs()
|
||||
{
|
||||
SHLWAPI_hshlwapi = LoadLibraryA("shlwapi.dll");
|
||||
ok(SHLWAPI_hshlwapi != 0, "LoadLibrary failed");
|
||||
if (SHLWAPI_hshlwapi)
|
||||
{
|
||||
pSHLWAPI_17 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)17);
|
||||
ok(pSHLWAPI_17 != 0, "No Ordinal 17");
|
||||
pSHLWAPI_18 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)18);
|
||||
ok(pSHLWAPI_18 != 0, "No Ordinal 18");
|
||||
pSHLWAPI_19 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)19);
|
||||
ok(pSHLWAPI_19 != 0, "No Ordinal 19");
|
||||
pSHLWAPI_20 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)20);
|
||||
ok(pSHLWAPI_20 != 0, "No Ordinal 20");
|
||||
pSHLWAPI_21 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)21);
|
||||
ok(pSHLWAPI_21 != 0, "No Ordinal 21");
|
||||
pSHLWAPI_22 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)22);
|
||||
ok(pSHLWAPI_22 != 0, "No Ordinal 22");
|
||||
}
|
||||
}
|
||||
|
||||
static void InitDummyStream(_IDummyStream* iface)
|
||||
{
|
||||
iface->lpVtbl = (void*)iclvt;
|
||||
iface->ref = 1;
|
||||
iface->readcalls = 0;
|
||||
iface->failreadcall = FALSE;
|
||||
iface->failreadsize = FALSE;
|
||||
iface->readbeyondend = FALSE;
|
||||
iface->readreturnlarge = FALSE;
|
||||
iface->writecalls = 0;
|
||||
iface->failwritecall = FALSE;
|
||||
iface->failwritesize = FALSE;
|
||||
iface->seekcalls = 0;
|
||||
iface->statcalls = 0;
|
||||
iface->item = SHLWAPI_CLIST_items;
|
||||
}
|
||||
|
||||
|
||||
static void test_CList(void)
|
||||
{
|
||||
_IDummyStream streamobj;
|
||||
LPSHLWAPI_CLIST list = NULL;
|
||||
LPCSHLWAPI_CLIST item = SHLWAPI_CLIST_items;
|
||||
HRESULT hRet;
|
||||
LPSHLWAPI_CLIST inserted;
|
||||
char buff[64];
|
||||
unsigned int i;
|
||||
|
||||
if (!pSHLWAPI_17 || !pSHLWAPI_18 || !pSHLWAPI_19 || !pSHLWAPI_20 ||
|
||||
!pSHLWAPI_21 || !pSHLWAPI_22)
|
||||
return;
|
||||
|
||||
/* Populate a list and test the items are added correctly */
|
||||
while (item->ulSize)
|
||||
{
|
||||
/* Create item and fill with data */
|
||||
inserted = (LPSHLWAPI_CLIST)buff;
|
||||
inserted->ulSize = item->ulSize + sizeof(SHLWAPI_CLIST);
|
||||
inserted->ulId = item->ulId;
|
||||
for (i = 0; i < item->ulSize; i++)
|
||||
buff[sizeof(SHLWAPI_CLIST)+i] = i*2;
|
||||
|
||||
/* Add it */
|
||||
hRet = pSHLWAPI_20(&list, inserted);
|
||||
ok(hRet > S_OK, "failed list add");
|
||||
|
||||
if (hRet > S_OK)
|
||||
{
|
||||
ok(list && list->ulSize, "item not added");
|
||||
|
||||
/* Find it */
|
||||
inserted = pSHLWAPI_22(list, item->ulId);
|
||||
ok(inserted != NULL, "lost after adding");
|
||||
|
||||
ok(!inserted || inserted->ulId != -1u, "find returned a container");
|
||||
|
||||
/* Check size */
|
||||
if (inserted && inserted->ulSize & 0x3)
|
||||
{
|
||||
/* Contained */
|
||||
ok(inserted[-1].ulId == -1u, "invalid size is not countained");
|
||||
ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST),
|
||||
"container too small");
|
||||
}
|
||||
else if (inserted)
|
||||
{
|
||||
ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST),
|
||||
"id %ld size wrong (%ld!=%ld)", inserted->ulId, inserted->ulSize,
|
||||
item->ulSize+sizeof(SHLWAPI_CLIST));
|
||||
}
|
||||
if (inserted)
|
||||
{
|
||||
BOOL bDataOK = TRUE;
|
||||
LPBYTE bufftest = (LPBYTE)inserted;
|
||||
|
||||
for (i = 0; i < inserted->ulSize - sizeof(SHLWAPI_CLIST); i++)
|
||||
if (bufftest[sizeof(SHLWAPI_CLIST)+i] != i*2)
|
||||
bDataOK = FALSE;
|
||||
|
||||
ok(bDataOK == TRUE, "data corrupted on insert");
|
||||
}
|
||||
ok(!inserted || inserted->ulId==item->ulId, "find got wrong item");
|
||||
}
|
||||
item++;
|
||||
}
|
||||
|
||||
/* Write the list */
|
||||
InitDummyStream(&streamobj);
|
||||
|
||||
hRet = pSHLWAPI_17(&streamobj, list);
|
||||
ok(hRet == S_OK, "write failed");
|
||||
if (hRet == S_OK)
|
||||
{
|
||||
/* 1 call for each element, + 1 for OK (use our null element for this) */
|
||||
ok(streamobj.writecalls == sizeof(SHLWAPI_CLIST_items)/sizeof(SHLWAPI_CLIST),
|
||||
"wrong call count");
|
||||
ok(streamobj.readcalls == 0,"called Read() in write");
|
||||
ok(streamobj.seekcalls == 0,"called Seek() in write");
|
||||
}
|
||||
|
||||
/* Failure cases for writing */
|
||||
InitDummyStream(&streamobj);
|
||||
streamobj.failwritecall = TRUE;
|
||||
hRet = pSHLWAPI_17(&streamobj, list);
|
||||
ok(hRet == STG_E_ACCESSDENIED, "changed object failure return");
|
||||
ok(streamobj.writecalls == 1, "called object after failure");
|
||||
ok(streamobj.readcalls == 0,"called Read() after failure");
|
||||
ok(streamobj.seekcalls == 0,"called Seek() after failure");
|
||||
|
||||
InitDummyStream(&streamobj);
|
||||
streamobj.failwritesize = TRUE;
|
||||
hRet = pSHLWAPI_17(&streamobj, list);
|
||||
ok(hRet == STG_E_MEDIUMFULL, "changed size failure return");
|
||||
ok(streamobj.writecalls == 1, "called object after size failure");
|
||||
ok(streamobj.readcalls == 0,"called Read() after failure");
|
||||
ok(streamobj.seekcalls == 0,"called Seek() after failure");
|
||||
|
||||
/* Invalid inputs for adding */
|
||||
inserted = (LPSHLWAPI_CLIST)buff;
|
||||
inserted->ulSize = sizeof(SHLWAPI_CLIST) -1;
|
||||
inserted->ulId = 33;
|
||||
hRet = pSHLWAPI_20(&list, inserted);
|
||||
ok(hRet == E_INVALIDARG, "allowed bad element size");
|
||||
|
||||
inserted->ulSize = 44;
|
||||
inserted->ulId = -1;
|
||||
hRet = pSHLWAPI_20(&list, inserted);
|
||||
ok(hRet == E_INVALIDARG, "allowed adding a container");
|
||||
|
||||
item = SHLWAPI_CLIST_items;
|
||||
|
||||
/* Look for non-existing item in populated list */
|
||||
inserted = pSHLWAPI_22(list, 99999999);
|
||||
ok(inserted == NULL, "found a non-existing item");
|
||||
|
||||
while (item->ulSize)
|
||||
{
|
||||
/* Delete items */
|
||||
BOOL bRet = pSHLWAPI_21(&list, item->ulId);
|
||||
ok(bRet == TRUE, "couldn't find item to delete");
|
||||
item++;
|
||||
}
|
||||
|
||||
/* Look for non-existing item in empty list */
|
||||
inserted = pSHLWAPI_22(list, 99999999);
|
||||
ok(inserted == NULL, "found an item in empty list");
|
||||
|
||||
/* Create a list by reading in data */
|
||||
InitDummyStream(&streamobj);
|
||||
|
||||
hRet = pSHLWAPI_18(&streamobj, &list);
|
||||
ok(hRet == S_OK, "failed create from Read()");
|
||||
if (hRet == S_OK)
|
||||
{
|
||||
ok(streamobj.readbeyondend == FALSE, "read beyond end");
|
||||
/* 2 calls per item, but only 1 for the terminator */
|
||||
ok(streamobj.readcalls == sizeof(SHLWAPI_CLIST_items)/sizeof(SHLWAPI_CLIST)*2-1,
|
||||
"wrong call count");
|
||||
ok(streamobj.writecalls == 0, "called Write() from create");
|
||||
ok(streamobj.seekcalls == 0,"called Seek() from create");
|
||||
|
||||
item = SHLWAPI_CLIST_items;
|
||||
|
||||
/* Check the items were added correctly */
|
||||
while (item->ulSize)
|
||||
{
|
||||
inserted = pSHLWAPI_22(list, item->ulId);
|
||||
ok(inserted != NULL, "lost after adding");
|
||||
|
||||
ok(!inserted || inserted->ulId != -1, "find returned a container");
|
||||
|
||||
/* Check size */
|
||||
if (inserted && inserted->ulSize & 0x3)
|
||||
{
|
||||
/* Contained */
|
||||
ok(inserted[-1].ulId == -1, "invalid size is not countained");
|
||||
ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST),
|
||||
"container too small");
|
||||
}
|
||||
else if (inserted)
|
||||
{
|
||||
ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST),
|
||||
"id %ld size wrong (%ld!=%ld)", inserted->ulId, inserted->ulSize,
|
||||
item->ulSize+sizeof(SHLWAPI_CLIST));
|
||||
}
|
||||
ok(!inserted || inserted->ulId==item->ulId, "find got wrong item");
|
||||
if (inserted)
|
||||
{
|
||||
BOOL bDataOK = TRUE;
|
||||
char *bufftest = (char*)inserted;
|
||||
|
||||
for (i = 0; i < inserted->ulSize - sizeof(SHLWAPI_CLIST); i++)
|
||||
if (bufftest[sizeof(SHLWAPI_CLIST)+i] != i*2)
|
||||
bDataOK = FALSE;
|
||||
|
||||
ok(bDataOK == TRUE, "data corrupted on insert");
|
||||
}
|
||||
item++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Failure cases for reading */
|
||||
InitDummyStream(&streamobj);
|
||||
streamobj.failreadcall = TRUE;
|
||||
hRet = pSHLWAPI_18(&streamobj, &list);
|
||||
ok(hRet == STG_E_ACCESSDENIED, "changed object failure return");
|
||||
ok(streamobj.readbeyondend == FALSE, "read beyond end");
|
||||
ok(streamobj.readcalls == 1, "called object after read failure");
|
||||
ok(streamobj.writecalls == 0,"called Write() after read failure");
|
||||
ok(streamobj.seekcalls == 0,"called Seek() after read failure");
|
||||
|
||||
/* Read returns large object */
|
||||
InitDummyStream(&streamobj);
|
||||
streamobj.readreturnlarge = TRUE;
|
||||
hRet = pSHLWAPI_18(&streamobj, &list);
|
||||
ok(hRet == S_OK, "failed create from Read() with large item");
|
||||
ok(streamobj.readbeyondend == FALSE, "read beyond end");
|
||||
ok(streamobj.readcalls == 1,"wrong call count");
|
||||
ok(streamobj.writecalls == 0,"called Write() after read failure");
|
||||
ok(streamobj.seekcalls == 2,"wrong Seek() call count (%d)", streamobj.seekcalls);
|
||||
|
||||
pSHLWAPI_19(list);
|
||||
}
|
||||
|
||||
|
||||
START_TEST(clist)
|
||||
{
|
||||
InitFunctionPtrs();
|
||||
|
||||
test_CList();
|
||||
|
||||
if (SHLWAPI_hshlwapi)
|
||||
FreeLibrary(SHLWAPI_hshlwapi);
|
||||
}
|
Loading…
Reference in a new issue