From d8de9b24fbb7c68adb0708d6cb6a96bb241d7498 Mon Sep 17 00:00:00 2001 From: Steven Edwards Date: Sat, 6 Aug 2005 23:58:36 +0000 Subject: [PATCH] add some of the shlwapi tests svn path=/trunk/; revision=17126 --- reactos/regtests/winetests/shlwapi/.cvsignore | 9 + reactos/regtests/winetests/shlwapi/clist.c | 643 ++++++++++++++ reactos/regtests/winetests/shlwapi/clsid.c | 171 ++++ .../regtests/winetests/shlwapi/generated.c | 186 ++++ reactos/regtests/winetests/shlwapi/ordinal.c | 248 ++++++ reactos/regtests/winetests/shlwapi/path.c | 833 ++++++++++++++++++ .../winetests/shlwapi/shlwapi_test.xml | 13 + reactos/regtests/winetests/shlwapi/shreg.c | 385 ++++++++ reactos/regtests/winetests/shlwapi/string.c | 760 ++++++++++++++++ reactos/regtests/winetests/shlwapi/testlist.c | 32 + 10 files changed, 3280 insertions(+) create mode 100755 reactos/regtests/winetests/shlwapi/.cvsignore create mode 100755 reactos/regtests/winetests/shlwapi/clist.c create mode 100755 reactos/regtests/winetests/shlwapi/clsid.c create mode 100755 reactos/regtests/winetests/shlwapi/generated.c create mode 100755 reactos/regtests/winetests/shlwapi/ordinal.c create mode 100755 reactos/regtests/winetests/shlwapi/path.c create mode 100755 reactos/regtests/winetests/shlwapi/shlwapi_test.xml create mode 100755 reactos/regtests/winetests/shlwapi/shreg.c create mode 100755 reactos/regtests/winetests/shlwapi/string.c create mode 100755 reactos/regtests/winetests/shlwapi/testlist.c diff --git a/reactos/regtests/winetests/shlwapi/.cvsignore b/reactos/regtests/winetests/shlwapi/.cvsignore new file mode 100755 index 00000000000..7bbf4176ebb --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/.cvsignore @@ -0,0 +1,9 @@ +Makefile +clist.ok +clsid.ok +generated.ok +ordinal.ok +path.ok +shreg.ok +string.ok +testlist.c diff --git a/reactos/regtests/winetests/shlwapi/clist.c b/reactos/regtests/winetests/shlwapi/clist.c new file mode 100755 index 00000000000..6abe85a9efa --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/clist.c @@ -0,0 +1,643 @@ +/* Unit test suite for SHLWAPI Compact List and IStream ordinal 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 + +#include "wine/test.h" +#include "windef.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; + LONG ref; + int readcalls; + BOOL failreadcall; + BOOL failreadsize; + BOOL readbeyondend; + BOOL readreturnlarge; + int writecalls; + BOOL failwritecall; + BOOL failwritesize; + int seekcalls; + int statcalls; + BOOL failstatcall; + LPCSHLWAPI_CLIST item; + ULARGE_INTEGER pos; +} _IDummyStream; + +static +HRESULT WINAPI QueryInterface(_IDummyStream *This,REFIID riid, LPVOID *ppvObj) +{ + return S_OK; +} + +static ULONG WINAPI AddRef(_IDummyStream *This) +{ + return InterlockedIncrement(&This->ref); +} + +static ULONG WINAPI Release(_IDummyStream *This) +{ + return InterlockedDecrement(&This->ref); +} + +static HRESULT WINAPI Read(_IDummyStream* This, LPVOID lpMem, ULONG ulSize, + PULONG 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, + PULONG 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; + This->pos.QuadPart = dlibMove.QuadPart; + if (plibNewPosition) + plibNewPosition->QuadPart = dlibMove.QuadPart; + return S_OK; +} + +static HRESULT WINAPI Stat(_IDummyStream* This, STATSTG* pstatstg, + DWORD grfStatFlag) +{ + ++This->statcalls; + if (This->failstatcall) + return E_FAIL; + if (pstatstg) + pstatstg->cbSize.QuadPart = This->pos.QuadPart; + 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 BOOL (WINAPI *pSHLWAPI_166)(_IDummyStream*); +static HRESULT (WINAPI *pSHLWAPI_184)(_IDummyStream*,LPVOID,ULONG); +static HRESULT (WINAPI *pSHLWAPI_212)(_IDummyStream*,LPCVOID,ULONG); +static HRESULT (WINAPI *pSHLWAPI_213)(_IDummyStream*); +static HRESULT (WINAPI *pSHLWAPI_214)(_IDummyStream*,ULARGE_INTEGER*); + + +static void InitFunctionPtrs(void) +{ + SHLWAPI_hshlwapi = LoadLibraryA("shlwapi.dll"); + ok(SHLWAPI_hshlwapi != 0, "LoadLibrary failed\n"); + if (SHLWAPI_hshlwapi) + { + pSHLWAPI_17 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)17); + ok(pSHLWAPI_17 != 0, "No Ordinal 17\n"); + pSHLWAPI_18 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)18); + ok(pSHLWAPI_18 != 0, "No Ordinal 18\n"); + pSHLWAPI_19 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)19); + ok(pSHLWAPI_19 != 0, "No Ordinal 19\n"); + pSHLWAPI_20 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)20); + ok(pSHLWAPI_20 != 0, "No Ordinal 20\n"); + pSHLWAPI_21 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)21); + ok(pSHLWAPI_21 != 0, "No Ordinal 21\n"); + pSHLWAPI_22 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)22); + ok(pSHLWAPI_22 != 0, "No Ordinal 22\n"); + pSHLWAPI_166 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)166); + ok(pSHLWAPI_166 != 0, "No Ordinal 166\n"); + pSHLWAPI_184 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)184); + ok(pSHLWAPI_184 != 0, "No Ordinal 184\n"); + pSHLWAPI_212 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)212); + ok(pSHLWAPI_212 != 0, "No Ordinal 212\n"); + pSHLWAPI_213 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)213); + ok(pSHLWAPI_213 != 0, "No Ordinal 213\n"); + pSHLWAPI_214 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)214); + ok(pSHLWAPI_214 != 0, "No Ordinal 214\n"); + } +} + +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->failstatcall = FALSE; + iface->item = SHLWAPI_CLIST_items; + iface->pos.QuadPart = 0; +} + + +static void test_CList(void) +{ + _IDummyStream streamobj; + LPSHLWAPI_CLIST list = NULL; + LPCSHLWAPI_CLIST item = SHLWAPI_CLIST_items; + HRESULT hRet; + LPSHLWAPI_CLIST inserted; + BYTE 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\n"); + + if (hRet > S_OK) + { + ok(list && list->ulSize, "item not added\n"); + + /* Find it */ + inserted = pSHLWAPI_22(list, item->ulId); + ok(inserted != NULL, "lost after adding\n"); + + ok(!inserted || inserted->ulId != ~0UL, "find returned a container\n"); + + /* Check size */ + if (inserted && inserted->ulSize & 0x3) + { + /* Contained */ + ok(inserted[-1].ulId == ~0UL, "invalid size is not countained\n"); + ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST), + "container too small\n"); + } + else if (inserted) + { + ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST), + "id %ld size wrong (%ld!=%ld)\n", 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\n"); + } + ok(!inserted || inserted->ulId==item->ulId, "find got wrong item\n"); + } + item++; + } + + /* Write the list */ + InitDummyStream(&streamobj); + + hRet = pSHLWAPI_17(&streamobj, list); + ok(hRet == S_OK, "write failed\n"); + 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\n"); + ok(streamobj.readcalls == 0,"called Read() in write\n"); + ok(streamobj.seekcalls == 0,"called Seek() in write\n"); + } + + /* Failure cases for writing */ + InitDummyStream(&streamobj); + streamobj.failwritecall = TRUE; + hRet = pSHLWAPI_17(&streamobj, list); + ok(hRet == STG_E_ACCESSDENIED, "changed object failure return\n"); + ok(streamobj.writecalls == 1, "called object after failure\n"); + ok(streamobj.readcalls == 0,"called Read() after failure\n"); + ok(streamobj.seekcalls == 0,"called Seek() after failure\n"); + + InitDummyStream(&streamobj); + streamobj.failwritesize = TRUE; + hRet = pSHLWAPI_17(&streamobj, list); + ok(hRet == STG_E_MEDIUMFULL, "changed size failure return\n"); + ok(streamobj.writecalls == 1, "called object after size failure\n"); + ok(streamobj.readcalls == 0,"called Read() after failure\n"); + ok(streamobj.seekcalls == 0,"called Seek() after failure\n"); + + /* Invalid inputs for adding */ + inserted = (LPSHLWAPI_CLIST)buff; + inserted->ulSize = sizeof(SHLWAPI_CLIST) -1; + inserted->ulId = 33; + hRet = pSHLWAPI_20(&list, inserted); + /* The call succeeds but the item is not inserted, except on some early + * versions which return failure. Wine behaves like later versions. + */ +#if 0 + ok(hRet == S_OK, "failed bad element size\n"); +#endif + inserted = pSHLWAPI_22(list, 33); + ok(inserted == NULL, "inserted bad element size\n"); + + inserted = (LPSHLWAPI_CLIST)buff; + inserted->ulSize = 44; + inserted->ulId = ~0UL; + hRet = pSHLWAPI_20(&list, inserted); + /* See comment above, some early versions fail this call */ +#if 0 + ok(hRet == S_OK, "failed adding a container\n"); +#endif + item = SHLWAPI_CLIST_items; + + /* Look for nonexistent item in populated list */ + inserted = pSHLWAPI_22(list, 99999999); + ok(inserted == NULL, "found a nonexistent item\n"); + + while (item->ulSize) + { + /* Delete items */ + BOOL bRet = pSHLWAPI_21(&list, item->ulId); + ok(bRet == TRUE, "couldn't find item to delete\n"); + item++; + } + + /* Look for nonexistent item in empty list */ + inserted = pSHLWAPI_22(list, 99999999); + ok(inserted == NULL, "found an item in empty list\n"); + + /* Create a list by reading in data */ + InitDummyStream(&streamobj); + + hRet = pSHLWAPI_18(&streamobj, &list); + ok(hRet == S_OK, "failed create from Read()\n"); + if (hRet == S_OK) + { + ok(streamobj.readbeyondend == FALSE, "read beyond end\n"); + /* 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\n"); + ok(streamobj.writecalls == 0, "called Write() from create\n"); + ok(streamobj.seekcalls == 0,"called Seek() from create\n"); + + 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\n"); + + ok(!inserted || inserted->ulId != ~0UL, "find returned a container\n"); + + /* Check size */ + if (inserted && inserted->ulSize & 0x3) + { + /* Contained */ + ok(inserted[-1].ulId == ~0UL, "invalid size is not countained\n"); + ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST), + "container too small\n"); + } + else if (inserted) + { + ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST), + "id %ld size wrong (%ld!=%ld)\n", inserted->ulId, inserted->ulSize, + item->ulSize+sizeof(SHLWAPI_CLIST)); + } + ok(!inserted || inserted->ulId==item->ulId, "find got wrong item\n"); + 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\n"); + } + item++; + } + } + + /* Failure cases for reading */ + InitDummyStream(&streamobj); + streamobj.failreadcall = TRUE; + hRet = pSHLWAPI_18(&streamobj, &list); + ok(hRet == STG_E_ACCESSDENIED, "changed object failure return\n"); + ok(streamobj.readbeyondend == FALSE, "read beyond end\n"); + ok(streamobj.readcalls == 1, "called object after read failure\n"); + ok(streamobj.writecalls == 0,"called Write() after read failure\n"); + ok(streamobj.seekcalls == 0,"called Seek() after read failure\n"); + + /* 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\n"); + ok(streamobj.readbeyondend == FALSE, "read beyond end\n"); + ok(streamobj.readcalls == 1,"wrong call count\n"); + ok(streamobj.writecalls == 0,"called Write() after read failure\n"); + ok(streamobj.seekcalls == 2,"wrong Seek() call count (%d)\n", streamobj.seekcalls); + + pSHLWAPI_19(list); +} + +static BOOL test_SHLWAPI_166(void) +{ + _IDummyStream streamobj; + BOOL bRet; + + if (!pSHLWAPI_166) + return FALSE; + + InitDummyStream(&streamobj); + bRet = pSHLWAPI_166(&streamobj); + + if (bRet != TRUE) + return FALSE; /* This version doesn't support stream ops on clists */ + + ok(streamobj.readcalls == 0, "called Read()\n"); + ok(streamobj.writecalls == 0, "called Write()\n"); + ok(streamobj.seekcalls == 0, "called Seek()\n"); + ok(streamobj.statcalls == 1, "wrong call count\n"); + + streamobj.statcalls = 0; + streamobj.pos.QuadPart = 50001; + + bRet = pSHLWAPI_166(&streamobj); + + ok(bRet == FALSE, "failed after seek adjusted\n"); + ok(streamobj.readcalls == 0, "called Read()\n"); + ok(streamobj.writecalls == 0, "called Write()\n"); + ok(streamobj.seekcalls == 0, "called Seek()\n"); + ok(streamobj.statcalls == 1, "wrong call count\n"); + + /* Failure cases */ + InitDummyStream(&streamobj); + streamobj.pos.QuadPart = 50001; + streamobj.failstatcall = TRUE; /* 1: Stat() Bad, Read() OK */ + bRet = pSHLWAPI_166(&streamobj); + ok(bRet == FALSE, "should be FALSE after read is OK\n"); + ok(streamobj.readcalls == 1, "wrong call count\n"); + ok(streamobj.writecalls == 0, "called Write()\n"); + ok(streamobj.seekcalls == 1, "wrong call count\n"); + ok(streamobj.statcalls == 1, "wrong call count\n"); + ok(streamobj.pos.QuadPart == 0, "Didn't seek to start\n"); + + InitDummyStream(&streamobj); + streamobj.pos.QuadPart = 50001; + streamobj.failstatcall = TRUE; + streamobj.failreadcall = TRUE; /* 2: Stat() Bad, Read() Bad Also */ + bRet = pSHLWAPI_166(&streamobj); + ok(bRet == TRUE, "Should be true after read fails\n"); + ok(streamobj.readcalls == 1, "wrong call count\n"); + ok(streamobj.writecalls == 0, "called Write()\n"); + ok(streamobj.seekcalls == 0, "Called Seek()\n"); + ok(streamobj.statcalls == 1, "wrong call count\n"); + ok(streamobj.pos.QuadPart == 50001, "called Seek() after read failed\n"); + return TRUE; +} + +static void test_SHLWAPI_184(void) +{ + _IDummyStream streamobj; + char buff[256]; + HRESULT hRet; + + if (!pSHLWAPI_184) + return; + + InitDummyStream(&streamobj); + hRet = pSHLWAPI_184(&streamobj, buff, sizeof(buff)); + + ok(hRet == S_OK, "failed Read()\n"); + ok(streamobj.readcalls == 1, "wrong call count\n"); + ok(streamobj.writecalls == 0, "called Write()\n"); + ok(streamobj.seekcalls == 0, "called Seek()\n"); +} + +static void test_SHLWAPI_212(void) +{ + _IDummyStream streamobj; + char buff[256]; + HRESULT hRet; + + if (!pSHLWAPI_212) + return; + + InitDummyStream(&streamobj); + hRet = pSHLWAPI_212(&streamobj, buff, sizeof(buff)); + + ok(hRet == S_OK, "failed Write()\n"); + ok(streamobj.readcalls == 0, "called Read()\n"); + ok(streamobj.writecalls == 1, "wrong call count\n"); + ok(streamobj.seekcalls == 0, "called Seek()\n"); +} + +static void test_SHLWAPI_213(void) +{ + _IDummyStream streamobj; + ULARGE_INTEGER ul; + LARGE_INTEGER ll; + HRESULT hRet; + + if (!pSHLWAPI_213 || !pSHLWAPI_214) + return; + + InitDummyStream(&streamobj); + ll.QuadPart = 5000l; + Seek(&streamobj, ll, 0, NULL); /* Seek to 5000l */ + + streamobj.seekcalls = 0; + pSHLWAPI_213(&streamobj); /* Should rewind */ + ok(streamobj.statcalls == 0, "called Stat()\n"); + ok(streamobj.readcalls == 0, "called Read()\n"); + ok(streamobj.writecalls == 0, "called Write()\n"); + ok(streamobj.seekcalls == 1, "wrong call count\n"); + + ul.QuadPart = 50001; + hRet = pSHLWAPI_214(&streamobj, &ul); + ok(hRet == S_OK, "failed Stat()\n"); + ok(ul.QuadPart == 0, "213 didn't rewind stream\n"); +} + +static void test_SHLWAPI_214(void) +{ + _IDummyStream streamobj; + ULARGE_INTEGER ul; + LARGE_INTEGER ll; + HRESULT hRet; + + if (!pSHLWAPI_214) + return; + + InitDummyStream(&streamobj); + ll.QuadPart = 5000l; + Seek(&streamobj, ll, 0, NULL); + ul.QuadPart = 0; + streamobj.seekcalls = 0; + hRet = pSHLWAPI_214(&streamobj, &ul); + + ok(hRet == S_OK, "failed Stat()\n"); + ok(streamobj.statcalls == 1, "wrong call count\n"); + ok(streamobj.readcalls == 0, "called Read()\n"); + ok(streamobj.writecalls == 0, "called Write()\n"); + ok(streamobj.seekcalls == 0, "called Seek()\n"); + ok(ul.QuadPart == 5000l, "Stat gave wrong size\n"); +} + +START_TEST(clist) +{ + InitFunctionPtrs(); + + test_CList(); + + /* Test streaming if this version supports it */ + if (test_SHLWAPI_166()) + { + test_SHLWAPI_184(); + test_SHLWAPI_212(); + test_SHLWAPI_213(); + test_SHLWAPI_214(); + } + + if (SHLWAPI_hshlwapi) + FreeLibrary(SHLWAPI_hshlwapi); +} diff --git a/reactos/regtests/winetests/shlwapi/clsid.c b/reactos/regtests/winetests/shlwapi/clsid.c new file mode 100755 index 00000000000..ce496531f3e --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/clsid.c @@ -0,0 +1,171 @@ +/* Unit test suite for SHLWAPI Class ID functions + * + * Copyright 2003 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 + +#define INITGUID +#include "wine/test.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#include "winuser.h" +#include "shlguid.h" +#include "wine/shobjidl.h" + +/* Function ptrs for ordinal calls */ +static HMODULE hShlwapi = 0; +static BOOL (WINAPI *pSHLWAPI_269)(LPCSTR, CLSID *) = 0; +static DWORD (WINAPI *pSHLWAPI_23)(REFGUID, LPSTR, INT) = 0; + +/* GUIDs to test */ +const GUID * TEST_guids[] = { + &CLSID_ShellDesktop, + &CLSID_ShellLink, + &CATID_BrowsableShellExt, + &CATID_BrowseInPlace, + &CATID_DeskBand, + &CATID_InfoBand, + &CATID_CommBand, + &FMTID_Intshcut, + &FMTID_InternetSite, + &CGID_Explorer, + &CGID_ShellDocView, + &CGID_ShellServiceObject, + &CGID_ExplorerBarDoc, + &IID_INewShortcutHookA, + &IID_IShellIcon, + &IID_IShellFolder, + &IID_IShellExtInit, + &IID_IShellPropSheetExt, + &IID_IPersistFolder, + &IID_IExtractIconA, + &IID_IShellDetails, + &IID_IDelayedRelease, + &IID_IShellLinkA, + &IID_IShellCopyHookA, + &IID_IFileViewerA, + &IID_ICommDlgBrowser, + &IID_IEnumIDList, + &IID_IFileViewerSite, + &IID_IContextMenu2, + &IID_IShellExecuteHookA, + &IID_IPropSheetPage, + &IID_INewShortcutHookW, + &IID_IFileViewerW, + &IID_IShellLinkW, + &IID_IExtractIconW, + &IID_IShellExecuteHookW, + &IID_IShellCopyHookW, + &IID_IRemoteComputer, + &IID_IQueryInfo, + &IID_IDockingWindow, + &IID_IDockingWindowSite, + &CLSID_NetworkPlaces, + &CLSID_NetworkDomain, + &CLSID_NetworkServer, + &CLSID_NetworkShare, + &CLSID_MyComputer, + &CLSID_Internet, + &CLSID_ShellFSFolder, + &CLSID_RecycleBin, + &CLSID_ControlPanel, + &CLSID_Printers, + &CLSID_MyDocuments, + NULL +}; + +DEFINE_GUID(IID_Endianess, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F, 0x0A); + +static void test_ClassIDs(void) +{ + const GUID **guids = TEST_guids; + char szBuff[256]; + GUID guid; + DWORD dwLen; + BOOL bRet; + int i = 0; + + if (!pSHLWAPI_269 || !pSHLWAPI_23) + return; + + while (*guids) + { + dwLen = pSHLWAPI_23(*guids, szBuff, 256); + ok(dwLen == 39, "wrong size for id %d\n", i); + + bRet = pSHLWAPI_269(szBuff, &guid); + ok(bRet != FALSE, "created invalid string '%s'\n", szBuff); + + if (bRet) + ok(IsEqualGUID(*guids, &guid), "GUID created wrong %d\n", i); + + guids++; + i++; + } + + /* Test endianess */ + dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 256); + ok(dwLen == 39, "wrong size for IID_Endianess\n"); + + ok(!strcmp(szBuff, "{01020304-0506-0708-090A-0B0C0D0E0F0A}"), + "Endianess Broken, got '%s'\n", szBuff); + + /* test lengths */ + szBuff[0] = ':'; + dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 0); + ok(dwLen == 0, "accepted bad length\n"); + ok(szBuff[0] == ':', "wrote to buffer with no length\n"); + + szBuff[0] = ':'; + dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 38); + ok(dwLen == 0, "accepted bad length\n"); + ok(szBuff[0] == ':', "wrote to buffer with no length\n"); + + szBuff[0] = ':'; + dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39); + ok(dwLen == 39, "rejected ok length\n"); + ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n"); + + /* Test string */ + strcpy(szBuff, "{xxx-"); + bRet = pSHLWAPI_269(szBuff, &guid); + ok(bRet == FALSE, "accepted invalid string\n"); + + dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39); + ok(dwLen == 39, "rejected ok length\n"); + ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n"); +} + + +START_TEST(clsid) +{ + hShlwapi = LoadLibraryA("shlwapi.dll"); + ok(hShlwapi != 0, "LoadLibraryA failed\n"); + if (hShlwapi) + { + pSHLWAPI_269 = (void*)GetProcAddress(hShlwapi, (LPSTR)269); + pSHLWAPI_23 = (void*)GetProcAddress(hShlwapi, (LPSTR)23); + } + + test_ClassIDs(); + + if (hShlwapi) + FreeLibrary(hShlwapi); +} diff --git a/reactos/regtests/winetests/shlwapi/generated.c b/reactos/regtests/winetests/shlwapi/generated.c new file mode 100755 index 00000000000..b1f618b87b8 --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/generated.c @@ -0,0 +1,186 @@ +/* File generated automatically from tools/winapi/test.dat; do not edit! */ +/* This file can be copied, modified and distributed without restriction. */ + +/* + * Unit tests for data structure packing + */ + +#define WINVER 0x0501 +#define _WIN32_IE 0x0501 +#define _WIN32_WINNT 0x0501 + +#define WINE_NOWINSOCK + +#include +#include "windef.h" +#include "winbase.h" +#include "wtypes.h" +#include "winreg.h" +#include "shlwapi.h" + +#include "wine/test.h" + +/*********************************************************************** + * Compability macros + */ + +#define DWORD_PTR UINT_PTR +#define LONG_PTR INT_PTR +#define ULONG_PTR UINT_PTR + +/*********************************************************************** + * Windows API extension + */ + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) +# define FIELD_ALIGNMENT(type, field) __alignof(((type*)0)->field) +#elif defined(__GNUC__) +# define FIELD_ALIGNMENT(type, field) __alignof__(((type*)0)->field) +#else +/* FIXME: Not sure if is possible to do without compiler extension */ +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1300) && defined(__cplusplus) +# define _TYPE_ALIGNMENT(type) __alignof(type) +#elif defined(__GNUC__) +# define _TYPE_ALIGNMENT(type) __alignof__(type) +#else +/* + * FIXME: Not sure if is possible to do without compiler extension + * (if type is not just a name that is, if so the normal) + * TYPE_ALIGNMENT can be used) + */ +#endif + +#if defined(TYPE_ALIGNMENT) && defined(_MSC_VER) && _MSC_VER >= 800 && !defined(__cplusplus) +#pragma warning(disable:4116) +#endif + +#if !defined(TYPE_ALIGNMENT) && defined(_TYPE_ALIGNMENT) +# define TYPE_ALIGNMENT _TYPE_ALIGNMENT +#endif + +/*********************************************************************** + * Test helper macros + */ + +#ifdef FIELD_ALIGNMENT +# define TEST_FIELD_ALIGNMENT(type, field, align) \ + ok(FIELD_ALIGNMENT(type, field) == align, \ + "FIELD_ALIGNMENT(" #type ", " #field ") == %d (expected " #align ")\n", \ + (int)FIELD_ALIGNMENT(type, field)) +#else +# define TEST_FIELD_ALIGNMENT(type, field, align) do { } while (0) +#endif + +#define TEST_FIELD_OFFSET(type, field, offset) \ + ok(FIELD_OFFSET(type, field) == offset, \ + "FIELD_OFFSET(" #type ", " #field ") == %ld (expected " #offset ")\n", \ + (long int)FIELD_OFFSET(type, field)) + +#ifdef _TYPE_ALIGNMENT +#define TEST__TYPE_ALIGNMENT(type, align) \ + ok(_TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)_TYPE_ALIGNMENT(type)) +#else +# define TEST__TYPE_ALIGNMENT(type, align) do { } while (0) +#endif + +#ifdef TYPE_ALIGNMENT +#define TEST_TYPE_ALIGNMENT(type, align) \ + ok(TYPE_ALIGNMENT(type) == align, "TYPE_ALIGNMENT(" #type ") == %d (expected " #align ")\n", (int)TYPE_ALIGNMENT(type)) +#else +# define TEST_TYPE_ALIGNMENT(type, align) do { } while (0) +#endif + +#define TEST_TYPE_SIZE(type, size) \ + ok(sizeof(type) == size, "sizeof(" #type ") == %d (expected " #size ")\n", ((int) sizeof(type))) + +/*********************************************************************** + * Test macros + */ + +#define TEST_FIELD(type, field_type, field_name, field_offset, field_size, field_align) \ + TEST_TYPE_SIZE(field_type, field_size); \ + TEST_FIELD_ALIGNMENT(type, field_name, field_align); \ + TEST_FIELD_OFFSET(type, field_name, field_offset); \ + +#define TEST_TYPE(type, size, align) \ + TEST_TYPE_ALIGNMENT(type, align); \ + TEST_TYPE_SIZE(type, size) + +#define TEST_TYPE_POINTER(type, size, align) \ + TEST__TYPE_ALIGNMENT(*(type)0, align); \ + TEST_TYPE_SIZE(*(type)0, size) + +#define TEST_TYPE_SIGNED(type) \ + ok((type) -1 < 0, "(" #type ") -1 < 0\n"); + +#define TEST_TYPE_UNSIGNED(type) \ + ok((type) -1 > 0, "(" #type ") -1 > 0\n"); + +static void test_pack_ASSOCF(void) +{ + /* ASSOCF */ + TEST_TYPE(ASSOCF, 4, 4); + TEST_TYPE_UNSIGNED(ASSOCF); +} + +static void test_pack_DLLGETVERSIONPROC(void) +{ + /* DLLGETVERSIONPROC */ + TEST_TYPE(DLLGETVERSIONPROC, 4, 4); +} + +static void test_pack_DLLVERSIONINFO(void) +{ + /* DLLVERSIONINFO (pack 8) */ + TEST_TYPE(DLLVERSIONINFO, 20, 4); + TEST_FIELD(DLLVERSIONINFO, DWORD, cbSize, 0, 4, 4); + TEST_FIELD(DLLVERSIONINFO, DWORD, dwMajorVersion, 4, 4, 4); + TEST_FIELD(DLLVERSIONINFO, DWORD, dwMinorVersion, 8, 4, 4); + TEST_FIELD(DLLVERSIONINFO, DWORD, dwBuildNumber, 12, 4, 4); + TEST_FIELD(DLLVERSIONINFO, DWORD, dwPlatformID, 16, 4, 4); +} + +static void test_pack_DLLVERSIONINFO2(void) +{ + /* DLLVERSIONINFO2 (pack 8) */ + TEST_TYPE(DLLVERSIONINFO2, 32, 8); + TEST_FIELD(DLLVERSIONINFO2, DLLVERSIONINFO, info1, 0, 20, 4); + TEST_FIELD(DLLVERSIONINFO2, DWORD, dwFlags, 20, 4, 4); + TEST_FIELD(DLLVERSIONINFO2, ULONGLONG, ullVersion, 24, 8, 8); +} + +static void test_pack_HUSKEY(void) +{ + /* HUSKEY */ + TEST_TYPE(HUSKEY, 4, 4); +} + +static void test_pack_IQueryAssociations(void) +{ + /* IQueryAssociations */ +} + +static void test_pack_PHUSKEY(void) +{ + /* PHUSKEY */ + TEST_TYPE(PHUSKEY, 4, 4); + TEST_TYPE_POINTER(PHUSKEY, 4, 4); +} + +static void test_pack(void) +{ + test_pack_ASSOCF(); + test_pack_DLLGETVERSIONPROC(); + test_pack_DLLVERSIONINFO(); + test_pack_DLLVERSIONINFO2(); + test_pack_HUSKEY(); + test_pack_IQueryAssociations(); + test_pack_PHUSKEY(); +} + +START_TEST(generated) +{ + test_pack(); +} diff --git a/reactos/regtests/winetests/shlwapi/ordinal.c b/reactos/regtests/winetests/shlwapi/ordinal.c new file mode 100755 index 00000000000..20798c72c9a --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/ordinal.c @@ -0,0 +1,248 @@ +/* Unit test suite for SHLWAPI ordinal functions + * + * Copyright 2004 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 + +#include "wine/test.h" +#include "winbase.h" +#include "winerror.h" +#include "winuser.h" + +/* Function ptrs for ordinal calls */ +static HMODULE hShlwapi; +static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int); +static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD); + +static HANDLE (WINAPI *pSHAllocShared)(LPCVOID,DWORD,DWORD); +static LPVOID (WINAPI *pSHLockShared)(HANDLE,DWORD); +static BOOL (WINAPI *pSHUnlockShared)(LPVOID); +static BOOL (WINAPI *pSHFreeShared)(HANDLE,DWORD); + +static void test_GetAcceptLanguagesA(void) +{ HRESULT retval; + DWORD buffersize, buffersize2, exactsize; + char buffer[100]; + + if (!pGetAcceptLanguagesA) + return; + + buffersize = sizeof(buffer); + memset(buffer, 0, sizeof(buffer)); + SetLastError(ERROR_SUCCESS); + retval = pGetAcceptLanguagesA( buffer, &buffersize); + trace("GetAcceptLanguagesA: retval %08lx, size %08lx, buffer (%s)," + " last error %ld\n", retval, buffersize, buffer, GetLastError()); + if(retval != S_OK) { + trace("GetAcceptLanguagesA: skipping tests\n"); + return; + } + ok( (ERROR_NO_IMPERSONATION_TOKEN == GetLastError()) || + (ERROR_CLASS_DOES_NOT_EXIST == GetLastError()) || + (ERROR_PROC_NOT_FOUND == GetLastError()) || + (ERROR_CALL_NOT_IMPLEMENTED == GetLastError()) || + (ERROR_SUCCESS == GetLastError()), "last error set to %ld\n", GetLastError()); + exactsize = strlen(buffer); + + SetLastError(ERROR_SUCCESS); + retval = pGetAcceptLanguagesA( NULL, NULL); + ok(retval == E_FAIL, + "function result wrong: got %08lx; expected E_FAIL\n", retval); + ok(ERROR_SUCCESS == GetLastError(), "last error set to %ld\n", GetLastError()); + + buffersize = sizeof(buffer); + SetLastError(ERROR_SUCCESS); + retval = pGetAcceptLanguagesA( NULL, &buffersize); + ok(retval == E_FAIL, + "function result wrong: got %08lx; expected E_FAIL\n", retval); + ok(buffersize == sizeof(buffer), + "buffersize was changed (2nd parameter; not on Win2k)\n"); + ok(ERROR_SUCCESS == GetLastError(), "last error set to %ld\n", GetLastError()); + + SetLastError(ERROR_SUCCESS); + retval = pGetAcceptLanguagesA( buffer, NULL); + ok(retval == E_FAIL, + "function result wrong: got %08lx; expected E_FAIL\n", retval); + ok(ERROR_SUCCESS == GetLastError(), "last error set to %ld\n", GetLastError()); + + buffersize = 0; + memset(buffer, 0, sizeof(buffer)); + SetLastError(ERROR_SUCCESS); + retval = pGetAcceptLanguagesA( buffer, &buffersize); + ok(retval == E_FAIL, + "function result wrong: got %08lx; expected E_FAIL\n", retval); + ok(buffersize == 0, + "buffersize wrong(changed) got %08lx; expected 0 (2nd parameter; not on Win2k)\n", buffersize); + ok(ERROR_SUCCESS == GetLastError(), "last error set to %ld\n", GetLastError()); + + buffersize = buffersize2 = 1; + memset(buffer, 0, sizeof(buffer)); + SetLastError(ERROR_SUCCESS); + retval = pGetAcceptLanguagesA( buffer, &buffersize); + switch(retval) { + case 0L: + if(buffersize == exactsize) { + ok( (ERROR_SUCCESS == GetLastError()) || (ERROR_CALL_NOT_IMPLEMENTED == GetLastError()) || + (ERROR_PROC_NOT_FOUND == GetLastError()) || (ERROR_NO_IMPERSONATION_TOKEN == GetLastError()), + "last error wrong: got %08lx; expected ERROR_SUCCESS(NT4)/ERROR_CALL_NOT_IMPLEMENTED(98/ME)/" + "ERROR_PROC_NOT_FOUND(NT4)/ERROR_NO_IMPERSONATION_TOKEN(XP)\n", GetLastError()); + ok(exactsize == strlen(buffer), + "buffer content (length) wrong: got %08x, expected %08lx \n", strlen(buffer), exactsize); + } else if((buffersize +1) == buffersize2) { + ok(ERROR_SUCCESS == GetLastError(), + "last error wrong: got %08lx; expected ERROR_SUCCESS\n", GetLastError()); + ok(buffersize == strlen(buffer), + "buffer content (length) wrong: got %08x, expected %08lx \n", strlen(buffer), buffersize); + } else + ok( 0, "retval %08lx, size %08lx, buffer (%s), last error %ld\n", + retval, buffersize, buffer, GetLastError()); + break; + case E_INVALIDARG: + ok(buffersize == 0, + "buffersize wrong: got %08lx, expected 0 (2nd parameter;Win2k)\n", buffersize); + ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), + "last error wrong: got %08lx; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError()); + ok(buffersize2 == strlen(buffer), + "buffer content (length) wrong: got %08x, expected %08lx \n", strlen(buffer), buffersize2); + break; + default: + ok( 0, "retval %08lx, size %08lx, buffer (%s), last error %ld\n", + retval, buffersize, buffer, GetLastError()); + break; + } + + buffersize = buffersize2 = exactsize; + memset(buffer, 0, sizeof(buffer)); + SetLastError(ERROR_SUCCESS); + retval = pGetAcceptLanguagesA( buffer, &buffersize); + switch(retval) { + case 0L: + ok(ERROR_SUCCESS == GetLastError(), + "last error wrong: got %08lx; expected ERROR_SUCCESS\n", GetLastError()); + if((buffersize == exactsize) /* XP */ || + ((buffersize +1)== exactsize) /* 98 */) + ok(buffersize == strlen(buffer), + "buffer content (length) wrong: got %08x, expected %08lx \n", strlen(buffer), buffersize); + else + ok( 0, "retval %08lx, size %08lx, buffer (%s), last error %ld\n", + retval, buffersize, buffer, GetLastError()); + break; + case E_INVALIDARG: + ok(buffersize == 0, + "buffersize wrong: got %08lx, expected 0 (2nd parameter;Win2k)\n", buffersize); + ok(ERROR_INSUFFICIENT_BUFFER == GetLastError(), + "last error wrong: got %08lx; expected ERROR_INSUFFICIENT_BUFFER\n", GetLastError()); + ok(buffersize2 == strlen(buffer), + "buffer content (length) wrong: got %08x, expected %08lx \n", strlen(buffer), buffersize2); + break; + default: + ok( 0, "retval %08lx, size %08lx, buffer (%s), last error %ld\n", + retval, buffersize, buffer, GetLastError()); + break; + } +} + +static void test_SHSearchMapInt(void) +{ + int keys[8], values[8]; + int i = 0; + + if (!pSHSearchMapInt) + return; + + memset(keys, 0, sizeof(keys)); + memset(values, 0, sizeof(values)); + keys[0] = 99; values[0] = 101; + + /* NULL key/value lists crash native, so skip testing them */ + + /* 1 element */ + i = pSHSearchMapInt(keys, values, 1, keys[0]); + ok(i == values[0], "Len 1, expected %d, got %d\n", values[0], i); + + /* Key doesn't exist */ + i = pSHSearchMapInt(keys, values, 1, 100); + ok(i == -1, "Len 1 - bad key, expected -1, got %d\n", i); + + /* Len = 0 => not found */ + i = pSHSearchMapInt(keys, values, 0, keys[0]); + ok(i == -1, "Len 1 - passed len 0, expected -1, got %d\n", i); + + /* 2 elements, len = 1 */ + keys[1] = 98; values[1] = 102; + i = pSHSearchMapInt(keys, values, 1, keys[1]); + ok(i == -1, "Len 1 - array len 2, expected -1, got %d\n", i); + + /* 2 elements, len = 2 */ + i = pSHSearchMapInt(keys, values, 2, keys[1]); + ok(i == values[1], "Len 2, expected %d, got %d\n", values[1], i); + + /* Searches forward */ + keys[2] = 99; values[2] = 103; + i = pSHSearchMapInt(keys, values, 3, keys[0]); + ok(i == values[0], "Len 3, expected %d, got %d\n", values[0], i); +} + +static void test_alloc_shared(void) +{ + DWORD procid; + HANDLE hmem; + int val; + int* p; + BOOL ret; + + procid=GetCurrentProcessId(); + hmem=pSHAllocShared(NULL,10,procid); + ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %ld\n", GetLastError()); + ret = pSHFreeShared(hmem, procid); + ok( ret, "SHFreeShared failed: %ld\n", GetLastError()); + + val=0x12345678; + hmem=pSHAllocShared(&val,4,procid); + ok(hmem!=NULL,"SHAllocShared(NULL...) failed: %ld\n", GetLastError()); + + p=(int*)pSHLockShared(hmem,procid); + ok(p!=NULL,"SHLockShared failed: %ld\n", GetLastError()); + if (p!=NULL) + ok(*p==val,"Wrong value in shared memory: %d instead of %d\n",*p,val); + ret = pSHUnlockShared(p); + ok( ret, "SHUnlockShared failed: %ld\n", GetLastError()); + + ret = pSHFreeShared(hmem, procid); + ok( ret, "SHFreeShared failed: %ld\n", GetLastError()); +} + +START_TEST(ordinal) +{ + hShlwapi = LoadLibraryA("shlwapi.dll"); + ok(hShlwapi != 0, "LoadLibraryA failed\n"); + if (!hShlwapi) + return; + + pGetAcceptLanguagesA = (void*)GetProcAddress(hShlwapi, (LPSTR)14); + pSHSearchMapInt = (void*)GetProcAddress(hShlwapi, (LPSTR)198); + pSHAllocShared=(void*)GetProcAddress(hShlwapi,(char*)7); + pSHLockShared=(void*)GetProcAddress(hShlwapi,(char*)8); + pSHUnlockShared=(void*)GetProcAddress(hShlwapi,(char*)9); + pSHFreeShared=(void*)GetProcAddress(hShlwapi,(char*)10); + + test_GetAcceptLanguagesA(); + test_SHSearchMapInt(); + test_alloc_shared(); + FreeLibrary(hShlwapi); +} diff --git a/reactos/regtests/winetests/shlwapi/path.c b/reactos/regtests/winetests/shlwapi/path.c new file mode 100755 index 00000000000..9812e083098 --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/path.c @@ -0,0 +1,833 @@ +/* Unit test suite for Path functions + * + * Copyright 2002 Matthew Mastracci + * + * 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 +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "wine/unicode.h" +#include "winreg.h" +#include "shlwapi.h" +#include "wininet.h" + +static HMODULE hShlwapi; +static HRESULT (WINAPI *pPathIsValidCharA)(char,DWORD); +static HRESULT (WINAPI *pPathIsValidCharW)(WCHAR,DWORD); + +const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923"; +const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923"; +const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y"; + +typedef struct _TEST_URL_CANONICALIZE { + const char *url; + DWORD flags; + HRESULT expectret; + const char *expecturl; +} TEST_URL_CANONICALIZE; + +const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = { + /*FIXME {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/"},*/ + {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests"}, + {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"}, + {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests"}, + {"http://www.winehq.org/tests\r", 0, S_OK, "http://www.winehq.org/tests"}, + {"http://www.winehq.org/tests\r", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests"}, + {"http://www.winehq.org/tests/../tests/", 0, S_OK, "http://www.winehq.org/tests/"}, + {"http://www.winehq.org/tests/../tests/..", 0, S_OK, "http://www.winehq.org/"}, + {"http://www.winehq.org/tests/../tests/../", 0, S_OK, "http://www.winehq.org/"}, + {"http://www.winehq.org/tests/..", 0, S_OK, "http://www.winehq.org/"}, + {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/"}, + {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"}, + {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y"}, + {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example"}, + {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example"}, + {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example"}, + {"http://www.winehq.org/tests/foo bar", URL_ESCAPE_SPACES_ONLY| URL_DONT_ESCAPE_EXTRA_INFO , S_OK, "http://www.winehq.org/tests/foo%20bar"}, + {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar"}, + {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar"}, +}; + +typedef struct _TEST_URL_ESCAPE { + const char *url; + DWORD flags; + DWORD expectescaped; + HRESULT expectret; + const char *expecturl; +} TEST_URL_ESCAPE; + +const TEST_URL_ESCAPE TEST_ESCAPE[] = { + {"http://www.winehq.org/tests0", 0, 0, S_OK, "http://www.winehq.org/tests0"}, + {"http://www.winehq.org/tests1\n", 0, 0, S_OK, "http://www.winehq.org/tests1%0A"}, + {"http://www.winehq.org/tests2\r", 0, 0, S_OK, "http://www.winehq.org/tests2%0D"}, + {"http://www.winehq.org/tests3\r", URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, 0, S_OK, "http://www.winehq.org/tests3\r"}, + {"http://www.winehq.org/tests4\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests4\r"}, + {"http://www.winehq.org/tests5\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY, 0, S_OK, "http://www.winehq.org/tests5\r"}, + {"/direct/swhelp/series6/6.2i_latestservicepack.dat\r", URL_ESCAPE_SPACES_ONLY, 0, S_OK, "/direct/swhelp/series6/6.2i_latestservicepack.dat\r"}, + + {"file://////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"}, + {"file://///foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"}, + {"file:////foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"}, + {"file:///localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"}, + {"file:///foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"}, + {"file://loCalHost/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"}, + {"file://foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"}, + {"file:/localhost/foo/bar\\baz", 0, 0, S_OK, "file:///localhost/foo/bar/baz"}, + {"file:/foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"}, + {"file:foo/bar\\baz", 0, 0, S_OK, "file:foo/bar/baz"}, + {"file:\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"}, + {"file:\\\\foo/bar\\baz", 0, 0, S_OK, "file://foo/bar/baz"}, + {"file:\\\\\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"}, + {"file:\\\\localhost\\foo/bar\\baz", 0, 0, S_OK, "file:///foo/bar/baz"}, + {"file:///f oo/b?a r\\baz", 0, 0, S_OK, "file:///f%20oo/b?a r\\baz"}, + {"file:///foo/b#a r\\baz", 0, 0, S_OK, "file:///foo/b%23a%20r/baz"}, + {"file:///f o^&`{}|][\"<>\\%o/b#a r\\baz", 0, 0, S_OK, "file:///f%20o%5E%26%60%7B%7D%7C%5D%5B%22%3C%3E/%o/b%23a%20r/baz"}, + {"file:///f o%o/b?a r\\b%az", URL_ESCAPE_PERCENT, 0, S_OK, "file:///f%20o%25o/b?a r\\b%az"}, + {"file:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "file:%2Ffoo%2Fbar%5Cbaz"}, + + {"foo/b%ar\\ba?z\\", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%ar%5Cba%3Fz%5C"}, + {"foo/b%ar\\ba?z\\", URL_ESCAPE_PERCENT | URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "foo%2Fb%25ar%5Cba%3Fz%5C"}, + {"foo/bar\\ba?z\\", 0, 0, S_OK, "foo/bar%5Cba?z\\"}, + {"/foo/bar\\ba?z\\", 0, 0, S_OK, "/foo/bar%5Cba?z\\"}, + {"/foo/bar\\ba#z\\", 0, 0, S_OK, "/foo/bar%5Cba#z\\"}, + {"/foo/%5C", 0, 0, S_OK, "/foo/%5C"}, + {"/foo/%5C", URL_ESCAPE_PERCENT, 0, S_OK, "/foo/%255C"}, + + {"http://////foo/bar\\baz", 0, 0, S_OK, "http://////foo/bar/baz"}, + {"http://///foo/bar\\baz", 0, 0, S_OK, "http://///foo/bar/baz"}, + {"http:////foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"}, + {"http:///foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"}, + {"http://localhost/foo/bar\\baz", 0, 0, S_OK, "http://localhost/foo/bar/baz"}, + {"http://foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"}, + {"http:/foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"}, + {"http:foo/bar\\ba?z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba?z\\"}, + {"http:foo/bar\\ba#z\\", 0, 0, S_OK, "http:foo%2Fbar%2Fba#z\\"}, + {"http:\\foo/bar\\baz", 0, 0, S_OK, "http:/foo/bar/baz"}, + {"http:\\\\foo/bar\\baz", 0, 0, S_OK, "http://foo/bar/baz"}, + {"http:\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:///foo/bar/baz"}, + {"http:\\\\\\\\foo/bar\\baz", 0, 0, S_OK, "http:////foo/bar/baz"}, + {"http:/fo ?o/b ar\\baz", 0, 0, S_OK, "http:/fo%20?o/b ar\\baz"}, + {"http:fo ?o/b ar\\baz", 0, 0, S_OK, "http:fo%20?o/b ar\\baz"}, + {"http:/foo/bar\\baz", URL_ESCAPE_SEGMENT_ONLY, 0, S_OK, "http:%2Ffoo%2Fbar%5Cbaz"}, + + {"https://foo/bar\\baz", 0, 0, S_OK, "https://foo/bar/baz"}, + {"https:/foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"}, + {"https:\\foo/bar\\baz", 0, 0, S_OK, "https:/foo/bar/baz"}, + + {"foo:////foo/bar\\baz", 0, 0, S_OK, "foo:////foo/bar%5Cbaz"}, + {"foo:///foo/bar\\baz", 0, 0, S_OK, "foo:///foo/bar%5Cbaz"}, + {"foo://localhost/foo/bar\\baz", 0, 0, S_OK, "foo://localhost/foo/bar%5Cbaz"}, + {"foo://foo/bar\\baz", 0, 0, S_OK, "foo://foo/bar%5Cbaz"}, + {"foo:/foo/bar\\baz", 0, 0, S_OK, "foo:/foo/bar%5Cbaz"}, + {"foo:foo/bar\\baz", 0, 0, S_OK, "foo:foo%2Fbar%5Cbaz"}, + {"foo:\\foo/bar\\baz", 0, 0, S_OK, "foo:%5Cfoo%2Fbar%5Cbaz"}, + {"foo:/foo/bar\\ba?\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba?\\z"}, + {"foo:/foo/bar\\ba#\\z", 0, 0, S_OK, "foo:/foo/bar%5Cba#\\z"}, + + {"mailto:/fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:%2Ffo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"}, + {"mailto:fo/o@b\\%a?\\r.b#\\az", 0, 0, S_OK, "mailto:fo%2Fo@b%5C%a%3F%5Cr.b%23%5Caz"}, + {"mailto:fo/o@b\\%a?\\r.b#\\az", URL_ESCAPE_PERCENT, 0, S_OK, "mailto:fo%2Fo@b%5C%25a%3F%5Cr.b%23%5Caz"}, + + {"ftp:fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:fo%2Fo@bar.baz%2Ffoo%2Fbar"}, + {"ftp:/fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:/fo/o@bar.baz/foo/bar"}, + {"ftp://fo/o@bar.baz/fo?o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo?o\\bar"}, + {"ftp://fo/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://fo/o@bar.baz/fo#o\\bar"}, + {"ftp://localhost/o@bar.baz/fo#o\\bar", 0, 0, S_OK, "ftp://localhost/o@bar.baz/fo#o\\bar"}, + {"ftp:///fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:///fo/o@bar.baz/foo/bar"}, + {"ftp:////fo/o@bar.baz/foo/bar", 0, 0, S_OK, "ftp:////fo/o@bar.baz/foo/bar"} +}; + +typedef struct _TEST_URL_COMBINE { + const char *url1; + const char *url2; + DWORD flags; + HRESULT expectret; + const char *expecturl; +} TEST_URL_COMBINE; + +const TEST_URL_COMBINE TEST_COMBINE[] = { + {"http://www.winehq.org/tests", "tests1", 0, S_OK, "http://www.winehq.org/tests1"}, + /*FIXME {"http://www.winehq.org/tests", "../tests2", 0, S_OK, "http://www.winehq.org/tests2"},*/ + {"http://www.winehq.org/tests/", "../tests3", 0, S_OK, "http://www.winehq.org/tests3"}, + {"http://www.winehq.org/tests/../tests", "tests4", 0, S_OK, "http://www.winehq.org/tests4"}, + {"http://www.winehq.org/tests/../tests/", "tests5", 0, S_OK, "http://www.winehq.org/tests/tests5"}, + {"http://www.winehq.org/tests/../tests/", "/tests6/..", 0, S_OK, "http://www.winehq.org/"}, + {"http://www.winehq.org/tests/../tests/..", "tests7/..", 0, S_OK, "http://www.winehq.org/"}, + {"http://www.winehq.org/tests/?query=x&return=y", "tests8", 0, S_OK, "http://www.winehq.org/tests/tests8"}, + {"http://www.winehq.org/tests/#example", "tests9", 0, S_OK, "http://www.winehq.org/tests/tests9"}, + {"http://www.winehq.org/tests/../tests/", "/tests10/..", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests10/.."}, + {"http://www.winehq.org/tests/../", "tests11", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../tests11"}, +}; + +struct { + const char *path; + const char *url; + DWORD ret; +} TEST_URLFROMPATH [] = { + {"foo", "file:foo", S_OK}, + {"foo\\bar", "file:foo/bar", S_OK}, + {"\\foo\\bar", "file:///foo/bar", S_OK}, + {"c:\\foo\\bar", "file:///c:/foo/bar", S_OK}, + {"c:foo\\bar", "file:///c:foo/bar", S_OK}, + {"c:\\foo/b a%r", "file:///c:/foo/b%20a%25r", S_OK}, + {"c:\\foo\\foo bar", "file:///c:/foo/foo%20bar", S_OK}, +#if 0 + /* The following test fails on native shlwapi as distributed with Win95/98. + * Wine matches the behaviour of later versions. + */ + {"xx:c:\\foo\\bar", "xx:c:\\foo\\bar", S_FALSE} +#endif +}; + +struct { + const char *url; + const char *path; + DWORD ret; +} TEST_PATHFROMURL[] = { + {"file:///c:/foo/ba%5Cr", "c:\\foo\\ba\\r", S_OK}, + {"file:///c:/foo/../ba%5Cr", "c:\\foo\\..\\ba\\r", S_OK}, + {"file:///host/c:/foo/bar", "\\host\\c:\\foo\\bar", S_OK}, + {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK}, + {"file://host/c:/foo/bar", "\\\\hostc:\\foo\\bar", S_OK}, + {"file:\\\\host\\c:\\foo\\bar", "\\\\hostc:\\foo\\bar", S_OK}, + {"file:\\\\host\\ca\\foo\\bar", "\\\\host\\ca\\foo\\bar", S_OK}, + {"file:\\\\host\\c|\\foo\\bar", "\\\\hostc|\\foo\\bar", S_OK}, + {"file:\\%5Chost\\c:\\foo\\bar", "\\\\host\\c:\\foo\\bar", S_OK}, + {"file:\\\\host\\cx:\\foo\\bar", "\\\\host\\cx:\\foo\\bar", S_OK}, + {"file://c:/foo/bar", "c:\\foo\\bar", S_OK}, + {"file://c:/d:/foo/bar", "c:\\d:\\foo\\bar", S_OK}, + {"file://c|/d|/foo/bar", "c:\\d|\\foo\\bar", S_OK}, + {"file://host/foo/bar", "\\\\host\\foo\\bar", S_OK}, + {"file:/foo/bar", "\\foo\\bar", S_OK}, + {"file:/foo/bar/", "\\foo\\bar\\", S_OK}, + {"file:foo/bar", "foo\\bar", S_OK}, + {"file:c:/foo/bar", "c:\\foo\\bar", S_OK}, + {"file:c|/foo/bar", "c:\\foo\\bar", S_OK}, + {"file:cx|/foo/bar", "cx|\\foo\\bar", S_OK}, + {"file:////c:/foo/bar", "c:\\foo\\bar", S_OK}, +/* {"file:////c:/foo/foo%20bar", "c:\\foo\\foo%20bar", S_OK},*/ + + {"c:\\foo\\bar", NULL, E_INVALIDARG}, + {"foo/bar", NULL, E_INVALIDARG}, + {"http://foo/bar", NULL, E_INVALIDARG}, + +}; + +struct { + char url[30]; + const char *expect; +} TEST_URL_UNESCAPE[] = { + {"file://foo/bar", "file://foo/bar"}, + {"file://fo%20o%5Ca/bar", "file://fo o\\a/bar"} +}; + + +struct { + const char *path; + BOOL expect; +} TEST_PATH_IS_URL[] = { + {"http://foo/bar", TRUE}, + {"c:\\foo\\bar", FALSE}, + {"foo://foo/bar", TRUE}, + {"foo\\bar", FALSE}, + {"foo.bar", FALSE}, + {"bogusscheme:", TRUE}, + {"http:partial", TRUE} +}; + +struct { + const char *url; + BOOL expectOpaque; + BOOL expectFile; +} TEST_URLIS_ATTRIBS[] = { + { "ftp:", FALSE, FALSE }, + { "http:", FALSE, FALSE }, + { "gopher:", FALSE, FALSE }, + { "mailto:", TRUE, FALSE }, + { "news:", FALSE, FALSE }, + { "nntp:", FALSE, FALSE }, + { "telnet:", FALSE, FALSE }, + { "wais:", FALSE, FALSE }, + { "file:", FALSE, TRUE }, + { "mk:", FALSE, FALSE }, + { "https:", FALSE, FALSE }, + { "shell:", TRUE, FALSE }, + { "https:", FALSE, FALSE }, + { "snews:", FALSE, FALSE }, + { "local:", FALSE, FALSE }, + { "javascript:", TRUE, FALSE }, + { "vbscript:", TRUE, FALSE }, + { "about:", TRUE, FALSE }, + { "res:", FALSE, FALSE }, + { "bogusscheme:", FALSE, FALSE }, + { "file:\\\\e:\\b\\c", FALSE, TRUE }, + { "file://e:/b/c", FALSE, TRUE }, + { "http:partial", FALSE, FALSE }, + { "mailto://www.winehq.org/test.html", TRUE, FALSE }, + { "file:partial", FALSE, TRUE } +}; + + +static LPWSTR GetWideString(const char* szString) +{ + LPWSTR wszString = HeapAlloc(GetProcessHeap(), 0, (2*INTERNET_MAX_URL_LENGTH) * sizeof(WCHAR)); + + MultiByteToWideChar(0, 0, szString, -1, wszString, INTERNET_MAX_URL_LENGTH); + + return wszString; +} + +static void FreeWideString(LPWSTR wszString) +{ + HeapFree(GetProcessHeap(), 0, wszString); +} + +static void hash_url(const char* szUrl) +{ + LPCSTR szTestUrl = szUrl; + LPWSTR wszTestUrl = GetWideString(szTestUrl); + + DWORD cbSize = sizeof(DWORD); + DWORD dwHash1, dwHash2; + ok(UrlHashA(szTestUrl, (LPBYTE)&dwHash1, cbSize) == S_OK, "UrlHashA didn't return S_OK\n"); + ok(UrlHashW(wszTestUrl, (LPBYTE)&dwHash2, cbSize) == S_OK, "UrlHashW didn't return S_OK\n"); + + FreeWideString(wszTestUrl); + + ok(dwHash1 == dwHash2, "Hashes didn't compare\n"); +} + +static void test_UrlHash(void) +{ + hash_url(TEST_URL_1); + hash_url(TEST_URL_2); + hash_url(TEST_URL_3); +} + +static void test_url_part(const char* szUrl, DWORD dwPart, DWORD dwFlags, const char* szExpected) +{ + CHAR szPart[INTERNET_MAX_URL_LENGTH]; + WCHAR wszPart[INTERNET_MAX_URL_LENGTH]; + LPWSTR wszUrl = GetWideString(szUrl); + LPWSTR wszConvertedPart; + + DWORD dwSize; + + dwSize = INTERNET_MAX_URL_LENGTH; + ok( UrlGetPartA(szUrl, szPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartA for \"%s\" part 0x%08lx didn't return S_OK but \"%s\"\n", szUrl, dwPart, szPart); + dwSize = INTERNET_MAX_URL_LENGTH; + ok( UrlGetPartW(wszUrl, wszPart, &dwSize, dwPart, dwFlags) == S_OK, "UrlGetPartW didn't return S_OK\n" ); + + wszConvertedPart = GetWideString(szPart); + + ok(strcmpW(wszPart,wszConvertedPart)==0, "Strings didn't match between ascii and unicode UrlGetPart!\n"); + + FreeWideString(wszUrl); + FreeWideString(wszConvertedPart); + + /* Note that v6.0 and later don't return '?' with the query */ + ok(strcmp(szPart,szExpected)==0 || + (*szExpected=='?' && !strcmp(szPart,szExpected+1)), + "Expected %s, but got %s\n", szExpected, szPart); +} + +static void test_UrlGetPart(void) +{ + test_url_part(TEST_URL_3, URL_PART_HOSTNAME, 0, "localhost"); + test_url_part(TEST_URL_3, URL_PART_PORT, 0, "21"); + test_url_part(TEST_URL_3, URL_PART_USERNAME, 0, "foo"); + test_url_part(TEST_URL_3, URL_PART_PASSWORD, 0, "bar"); + test_url_part(TEST_URL_3, URL_PART_SCHEME, 0, "http"); + test_url_part(TEST_URL_3, URL_PART_QUERY, 0, "?query=x&return=y"); +} + +static void test_url_escape(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl) +{ + CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH]; + DWORD dwEscaped; + WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH]; + WCHAR *urlW, *expected_urlW; + dwEscaped=INTERNET_MAX_URL_LENGTH; + + ok(UrlEscapeA(szUrl, szReturnUrl, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl); + ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", szExpectUrl, szReturnUrl, szUrl); + + dwEscaped = INTERNET_MAX_URL_LENGTH; + urlW = GetWideString(szUrl); + expected_urlW = GetWideString(szExpectUrl); + ok(UrlEscapeW(urlW, ret_urlW, &dwEscaped, dwFlags) == dwExpectReturn, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", dwExpectReturn, szUrl); + WideCharToMultiByte(CP_ACP,0,ret_urlW,-1,szReturnUrl,INTERNET_MAX_URL_LENGTH,0,0); + ok(strcmpW(ret_urlW, expected_urlW)==0, "Expected \"%s\", but got \"%s\" from \"%s\" flags %08lx\n", szExpectUrl, szReturnUrl, szUrl, dwFlags); + FreeWideString(urlW); + FreeWideString(expected_urlW); + +} + +static void test_url_canonicalize(const char *szUrl, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl) +{ + CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH]; + WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH]; + LPWSTR wszUrl = GetWideString(szUrl); + LPWSTR wszExpectUrl = GetWideString(szExpectUrl); + LPWSTR wszConvertedUrl; + + DWORD dwSize; + + dwSize = INTERNET_MAX_URL_LENGTH; + ok(UrlCanonicalizeA(szUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n"); + ok(UrlCanonicalizeA(szUrl, szReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeA didn't return 0x%08lx\n", dwExpectReturn); + ok(strcmp(szReturnUrl,szExpectUrl)==0, "UrlCanonicalizeA dwFlags 0x%08lx Expected %s, but got %s\n", dwFlags, szExpectUrl, szReturnUrl); + + dwSize = INTERNET_MAX_URL_LENGTH; + ok(UrlCanonicalizeW(wszUrl, NULL, &dwSize, dwFlags) != dwExpectReturn, "Unexpected return for NULL buffer\n"); + ok(UrlCanonicalizeW(wszUrl, wszReturnUrl, &dwSize, dwFlags) == dwExpectReturn, "UrlCanonicalizeW didn't return 0x%08lx\n", dwExpectReturn); + wszConvertedUrl = GetWideString(szReturnUrl); + ok(strcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCanonicalize!\n"); + FreeWideString(wszConvertedUrl); + + + FreeWideString(wszUrl); + FreeWideString(wszExpectUrl); +} + + +static void test_UrlEscape(void) +{ + unsigned int i; + for(i=0; i + . + + ntdll + shlwapi + ole32 + oleaut32 + clist.c + ordinal.c + shreg.c + string.c + testlist.c + diff --git a/reactos/regtests/winetests/shlwapi/shreg.c b/reactos/regtests/winetests/shlwapi/shreg.c new file mode 100755 index 00000000000..d8d4d923200 --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/shreg.c @@ -0,0 +1,385 @@ +/* Unit test suite for SHReg* functions + * + * Copyright 2002 Juergen Schmied + * + * 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 +#include +#include + +#include "wine/test.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" +#include "winuser.h" +#include "shlwapi.h" + +/* Keys used for testing */ +#define REG_TEST_KEY "Software\\Wine\\Test" +#define REG_CURRENT_VERSION "Software\\Microsoft\\Windows\\CurrentVersion" + +static HMODULE hshlwapi; +typedef DWORD (WINAPI *SHCopyKeyA_func)(HKEY,LPCSTR,HKEY,DWORD); +static SHCopyKeyA_func pSHCopyKeyA; +typedef DWORD (WINAPI *SHRegGetPathA_func)(HKEY,LPCSTR,LPCSTR,LPSTR,DWORD); +static SHRegGetPathA_func pSHRegGetPathA; + +static const char * sTestpath1 = "%LONGSYSTEMVAR%\\subdir1"; +static const char * sTestpath2 = "%FOO%\\subdir1"; + +static const char * sEnvvar1 = "bar"; +static const char * sEnvvar2 = "ImARatherLongButIndeedNeededString"; + +static char sExpTestpath1[MAX_PATH]; +static char sExpTestpath2[MAX_PATH]; +static unsigned sExpLen1; +static unsigned sExpLen2; + +static const char * sEmptyBuffer ="0123456789"; + +/* delete key and all its subkeys */ +static DWORD delete_key( HKEY hkey, LPSTR parent, LPSTR keyname ) +{ + HKEY parentKey; + DWORD ret; + + RegCloseKey(hkey); + + /* open the parent of the key to close */ + ret = RegOpenKeyExA( HKEY_CURRENT_USER, parent, 0, KEY_ALL_ACCESS, &parentKey); + if (ret != ERROR_SUCCESS) + return ret; + + ret = SHDeleteKeyA( parentKey, keyname ); + RegCloseKey(parentKey); + + return ret; +} + +static HKEY create_test_entries(void) +{ + HKEY hKey; + DWORD ret; + + SetEnvironmentVariableA("LONGSYSTEMVAR", sEnvvar1); + SetEnvironmentVariableA("FOO", sEnvvar2); + + ret = RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEY, &hKey); + ok( ERROR_SUCCESS == ret, "RegCreateKeyA failed, ret=%lu\n", ret); + + if (hKey) + { + ok(!RegSetValueExA(hKey,"Test1",0,REG_EXPAND_SZ, (LPBYTE) sTestpath1, strlen(sTestpath1)+1), "RegSetValueExA failed\n"); + ok(!RegSetValueExA(hKey,"Test2",0,REG_SZ, (LPBYTE) sTestpath1, strlen(sTestpath1)+1), "RegSetValueExA failed\n"); + ok(!RegSetValueExA(hKey,"Test3",0,REG_EXPAND_SZ, (LPBYTE) sTestpath2, strlen(sTestpath2)+1), "RegSetValueExA failed\n"); + } + + sExpLen1 = ExpandEnvironmentStringsA(sTestpath1, sExpTestpath1, sizeof(sExpTestpath1)); + sExpLen2 = ExpandEnvironmentStringsA(sTestpath2, sExpTestpath2, sizeof(sExpTestpath2)); + + ok(sExpLen1 > 0, "Couldn't expand %s\n", sTestpath1); + trace("sExplen1 = (%d)\n", sExpLen1); + ok(sExpLen2 > 0, "Couldn't expand %s\n", sTestpath2); + trace("sExplen2 = (%d)\n", sExpLen2); + + return hKey; +} + +static void test_SHGetValue(void) +{ + DWORD dwSize; + DWORD dwType; + DWORD dwRet; + char buf[MAX_PATH]; + + strcpy(buf, sEmptyBuffer); + dwSize = MAX_PATH; + dwType = -1; + dwRet = SHGetValueA(HKEY_CURRENT_USER, REG_TEST_KEY, "Test1", &dwType, buf, &dwSize); + ok( ERROR_SUCCESS == dwRet, "SHGetValueA failed, ret=%lu\n", dwRet); + ok( 0 == strcmp(sExpTestpath1, buf), "Comparing of (%s) with (%s) failed\n", buf, sExpTestpath1); + ok( REG_SZ == dwType, "Expected REG_SZ, got (%lu)\n", dwType); + + strcpy(buf, sEmptyBuffer); + dwSize = MAX_PATH; + dwType = -1; + dwRet = SHGetValueA(HKEY_CURRENT_USER, REG_TEST_KEY, "Test2", &dwType, buf, &dwSize); + ok( ERROR_SUCCESS == dwRet, "SHGetValueA failed, ret=%lu\n", dwRet); + ok( 0 == strcmp(sTestpath1, buf) , "Comparing of (%s) with (%s) failed\n", buf, sTestpath1); + ok( REG_SZ == dwType , "Expected REG_SZ, got (%lu)\n", dwType); +} + +static void test_SHGetRegPath(void) +{ + char buf[MAX_PATH]; + DWORD dwRet; + + if (!pSHRegGetPathA) + return; + + strcpy(buf, sEmptyBuffer); + dwRet = (*pSHRegGetPathA)(HKEY_CURRENT_USER, REG_TEST_KEY, "Test1", buf, 0); + ok( ERROR_SUCCESS == dwRet, "SHRegGetPathA failed, ret=%lu\n", dwRet); + ok( 0 == strcmp(sExpTestpath1, buf) , "Comparing (%s) with (%s) failed\n", buf, sExpTestpath1); +} + +static void test_SHQUeryValueEx(void) +{ + HKEY hKey; + DWORD dwSize; + DWORD dwType; + char buf[MAX_PATH]; + DWORD dwRet; + const char * sTestedFunction = ""; + DWORD nUsedBuffer1,nUsedBuffer2; + + sTestedFunction = "RegOpenKeyExA"; + dwRet = RegOpenKeyExA(HKEY_CURRENT_USER, REG_TEST_KEY, 0, KEY_QUERY_VALUE, &hKey); + ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%lu\n", sTestedFunction, dwRet); + + /****** SHQueryValueExA ******/ + + sTestedFunction = "SHQueryValueExA"; + nUsedBuffer1 = max(strlen(sExpTestpath1)+1, strlen(sTestpath1)+1); + nUsedBuffer2 = max(strlen(sExpTestpath2)+1, strlen(sTestpath2)+1); + /* + * Case 1.1 All arguments are NULL + */ + dwRet = SHQueryValueExA( hKey, "Test1", NULL, NULL, NULL, NULL); + ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%lu\n", sTestedFunction, dwRet); + + /* + * Case 1.2 dwType is set + */ + dwType = -1; + dwRet = SHQueryValueExA( hKey, "Test1", NULL, &dwType, NULL, NULL); + ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%lu\n", sTestedFunction, dwRet); + ok( REG_SZ == dwType , "Expected REG_SZ, got (%lu)\n", dwType); + + /* + * dwSize is set + * dwExpanded < dwUnExpanded + */ + dwSize = 6; + dwRet = SHQueryValueExA( hKey, "Test1", NULL, NULL, NULL, &dwSize); + ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%lu\n", sTestedFunction, dwRet); + ok( dwSize == nUsedBuffer1, "Buffer sizes (%lu) and (%lu) are not equal\n", dwSize, nUsedBuffer1); + + /* + * dwExpanded > dwUnExpanded + */ + dwSize = 6; + dwRet = SHQueryValueExA( hKey, "Test3", NULL, NULL, NULL, &dwSize); + ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%lu\n", sTestedFunction, dwRet); + ok( dwSize >= nUsedBuffer2, "Buffer size (%lu) should be >= (%lu)\n", dwSize, nUsedBuffer2); + + /* + * Case 1 string shrinks during expanding + */ + strcpy(buf, sEmptyBuffer); + dwSize = 6; + dwType = -1; + dwRet = SHQueryValueExA( hKey, "Test1", NULL, &dwType, buf, &dwSize); + ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%lu)\n", dwRet); + ok( 0 == strcmp(sEmptyBuffer, buf) , "Comparing (%s) with (%s) failed\n", buf, sEmptyBuffer); + ok( dwSize == nUsedBuffer1, "Buffer sizes (%lu) and (%lu) are not equal\n", dwSize, nUsedBuffer1); + ok( REG_SZ == dwType , "Expected REG_SZ, got (%lu)\n", dwType); + + /* + * string grows during expanding + * dwSize is smaller then the size of the unexpanded string + */ + strcpy(buf, sEmptyBuffer); + dwSize = 6; + dwType = -1; + dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, buf, &dwSize); + ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%lu)\n", dwRet); + ok( 0 == strcmp(sEmptyBuffer, buf) , "Comparing (%s) with (%s) failed\n", buf, sEmptyBuffer); + ok( dwSize >= nUsedBuffer2, "Buffer size (%lu) should be >= (%lu)\n", dwSize, nUsedBuffer2); + ok( REG_SZ == dwType , "Expected REG_SZ, got (%lu)\n", dwType); + + /* + * string grows during expanding + * dwSize is larger then the size of the unexpanded string but smaller than the part before the backslash + * if the unexpanded string fits into the buffer it can get cut when expanded + */ + strcpy(buf, sEmptyBuffer); + dwSize = strlen(sEnvvar2) - 2; + dwType = -1; + dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, buf, &dwSize); + ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%lu)\n", dwRet); + + todo_wine + { + ok( (0 == strcmp("", buf)) | (0 == strcmp(sTestpath2, buf)), + "Expected empty or unexpanded string (win98), got (%s)\n", buf); + } + + ok( dwSize >= nUsedBuffer2, "Buffer size (%lu) should be >= (%lu)\n", dwSize, nUsedBuffer2); + ok( REG_SZ == dwType , "Expected REG_SZ, got (%lu)\n", dwType); + + /* + * string grows during expanding + * dwSize is larger then the size of the part before the backslash but smaller then the expanded string + * if the unexpanded string fits into the buffer it can get cut when expanded + */ + strcpy(buf, sEmptyBuffer); + dwSize = sExpLen2 - 4; + dwType = -1; + dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, buf, &dwSize); + ok( ERROR_MORE_DATA == dwRet, "Expected ERROR_MORE_DATA, got (%lu)\n", dwRet); + + todo_wine + { + ok( (0 == strcmp("", buf)) | (0 == strcmp(sEnvvar2, buf)), + "Expected empty or first part of the string \"%s\", got \"%s\"\n", sEnvvar2, buf); + } + + ok( dwSize >= nUsedBuffer2, "Buffer size (%lu) should be >= (%lu)\n", dwSize, nUsedBuffer2); + ok( REG_SZ == dwType , "Expected REG_SZ, got (%lu)\n", dwType); + + /* + * The buffer is NULL but the size is set + */ + strcpy(buf, sEmptyBuffer); + dwSize = 6; + dwType = -1; + dwRet = SHQueryValueExA( hKey, "Test3", NULL, &dwType, NULL, &dwSize); + ok( ERROR_SUCCESS == dwRet, "%s failed, ret=%lu\n", sTestedFunction, dwRet); + ok( dwSize >= nUsedBuffer2, "Buffer size (%lu) should be >= (%lu)\n", dwSize, nUsedBuffer2); + ok( REG_SZ == dwType , "Expected REG_SZ, got (%lu)\n", dwType); + + RegCloseKey(hKey); +} + +static void test_SHCopyKey(void) +{ + HKEY hKeySrc, hKeyDst; + DWORD dwRet; + + /* Delete existing destination sub keys */ + hKeyDst = NULL; + if (!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination", &hKeyDst) && hKeyDst) + { + SHDeleteKeyA(hKeyDst, NULL); + RegCloseKey(hKeyDst); + } + + hKeyDst = NULL; + dwRet = RegCreateKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination", &hKeyDst); + if (dwRet || !hKeyDst) + { + ok( 0, "Destination couldn't be created, RegCreateKeyA returned (%lu)\n", dwRet); + return; + } + + hKeySrc = NULL; + dwRet = RegOpenKeyA(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, &hKeySrc); + if (dwRet || !hKeySrc) + { + ok( 0, "Source couldn't be opened, RegOpenKeyA returned (%lu)\n", dwRet); + return; + } + + + if (pSHCopyKeyA) + { + dwRet = (*pSHCopyKeyA)(hKeySrc, NULL, hKeyDst, 0); + ok ( ERROR_SUCCESS == dwRet, "Copy failed, ret=(%lu)\n", dwRet); + } + + RegCloseKey(hKeySrc); + RegCloseKey(hKeyDst); + + /* Check we copied the sub keys, i.e. something that's on every windows system (including Wine) */ + hKeyDst = NULL; + dwRet = RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\CopyDestination\\Setup", &hKeyDst); + if (dwRet || !hKeyDst) + { + ok ( 0, "Copy couldn't be opened, RegOpenKeyA returned (%lu)\n", dwRet); + return; + } + + /* And the we copied the values too */ + ok(!SHQueryValueExA(hKeyDst, "BootDir", NULL, NULL, NULL, NULL), "SHQueryValueExA failed\n"); + + RegCloseKey(hKeyDst); +} + +static void test_SHDeleteKey(void) +{ + HKEY hKeyTest, hKeyS; + DWORD dwRet; + int sysfail = 1; + + if (!RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY, &hKeyTest)) + { + if (!RegCreateKey(hKeyTest, "ODBC", &hKeyS)) + { + HKEY hKeyO; + + if (!RegCreateKey(hKeyS, "ODBC.INI", &hKeyO)) + { + RegCloseKey (hKeyO); + + if (!RegCreateKey(hKeyS, "ODBCINST.INI", &hKeyO)) + { + RegCloseKey (hKeyO); + sysfail = 0; + } + } + RegCloseKey (hKeyS); + } + RegCloseKey (hKeyTest); + } + + if (!sysfail) + { + + dwRet = SHDeleteKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\ODBC"); + ok ( ERROR_SUCCESS == dwRet, "SHDeleteKey failed, ret=(%lu)\n", dwRet); + + dwRet = RegOpenKeyA(HKEY_CURRENT_USER, REG_TEST_KEY "\\ODBC", &hKeyS); + ok ( ERROR_FILE_NOT_FOUND == dwRet, "SHDeleteKey did not delete\n"); + + if (dwRet == ERROR_SUCCESS) + RegCloseKey (hKeyS); + } + else + ok( 0, "Could not set up SHDeleteKey test\n"); +} + +START_TEST(shreg) +{ + HKEY hkey = create_test_entries(); + + if (!hkey) return; + + hshlwapi = GetModuleHandleA("shlwapi.dll"); + if (hshlwapi) + { + pSHCopyKeyA=(SHCopyKeyA_func)GetProcAddress(hshlwapi,"SHCopyKeyA"); + pSHRegGetPathA=(SHRegGetPathA_func)GetProcAddress(hshlwapi,"SHRegGetPathA"); + } + test_SHGetValue(); + test_SHQUeryValueEx(); + test_SHGetRegPath(); + test_SHCopyKey(); + test_SHDeleteKey(); + delete_key( hkey, "Software\\Wine", "Test" ); +} diff --git a/reactos/regtests/winetests/shlwapi/string.c b/reactos/regtests/winetests/shlwapi/string.c new file mode 100755 index 00000000000..47d9a6c9bef --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/string.c @@ -0,0 +1,760 @@ +/* Unit test suite for SHLWAPI string functions + * + * Copyright 2003 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 + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT +#include "wine/test.h" +#include "winbase.h" +#include "winerror.h" +#include "winnls.h" +#define NO_SHLWAPI_REG +#define NO_SHLWAPI_PATH +#define NO_SHLWAPI_GDI +#define NO_SHLWAPI_STREAM +#include "shlwapi.h" +#include "shtypes.h" + +static HMODULE hShlwapi; +static LPSTR (WINAPI *pStrCpyNXA)(LPSTR,LPCSTR,int); +static LPWSTR (WINAPI *pStrCpyNXW)(LPWSTR,LPCWSTR,int); +static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,void*,BSTR*); +static DWORD (WINAPI *pSHAnsiToAnsi)(LPCSTR,LPSTR,int); +static DWORD (WINAPI *pSHUnicodeToUnicode)(LPCWSTR,LPWSTR,int); +static BOOL (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int); +static BOOL (WINAPI *pIntlStrEqWorkerA)(BOOL,LPCSTR,LPCSTR,int); +static BOOL (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int); +static BOOL (WINAPI *pIntlStrEqWorkerW)(BOOL,LPCWSTR,LPCWSTR,int); + +static inline int strcmpW(const WCHAR *str1, const WCHAR *str2) +{ + while (*str1 && (*str1 == *str2)) { str1++; str2++; } + return *str1 - *str2; +} + +/* StrToInt/StrToIntEx results */ +typedef struct tagStrToIntResult +{ + const char* string; + int str_to_int; + int str_to_int_ex; + int str_to_int_hex; +} StrToIntResult; + +static const StrToIntResult StrToInt_results[] = { + { "1099", 1099, 1099, 1099 }, + { "+88987", 0, 88987, 88987 }, + { "012", 12, 12, 12 }, + { "-55", -55, -55, -55 }, + { "-0", 0, 0, 0 }, + { "0x44ff", 0, 0, 0x44ff }, + { "+0x44f4", 0, 0, 0x44f4 }, + { "-0x44fd", 0, 0, 0x44fd }, + { "+ 88987", 0, 0, 0 }, + { "- 55", 0, 0, 0 }, + { "- 0", 0, 0, 0 }, + { "+ 0x44f4", 0, 0, 0 }, + { "--0x44fd", 0, 0, 0 }, + { " 1999", 0, 1999, 1999 }, + { " +88987", 0, 88987, 88987 }, + { " 012", 0, 12, 12 }, + { " -55", 0, -55, -55 }, + { " 0x44ff", 0, 0, 0x44ff }, + { " +0x44f4", 0, 0, 0x44f4 }, + { " -0x44fd", 0, 0, 0x44fd }, + { NULL, 0, 0, 0 } +}; + +/* pStrFormatByteSize64/StrFormatKBSize results */ +typedef struct tagStrFormatSizeResult +{ + LONGLONG value; + const char* byte_size_64; + const char* kb_size; +} StrFormatSizeResult; + + +static const StrFormatSizeResult StrFormatSize_results[] = { + { -1023, "-1023 bytes", "0 KB"}, + { -24, "-24 bytes", "0 KB"}, + { 309, "309 bytes", "1 KB"}, + { 10191, "9.95 KB", "10 KB"}, + { 100353, "98.0 KB", "99 KB"}, + { 1022286, "998 KB", "999 KB"}, + { 1046862, "0.99 MB", "1,023 KB"}, + { 1048574619, "999 MB", "1,023,999 KB"}, + { 1073741775, "0.99 GB", "1,048,576 KB"}, + { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB"}, + { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB"}, + { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB"}, + { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB"}, + { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB"}, + { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB"}, + { 0, NULL, NULL } +}; + +/* StrFormatByteSize64/StrFormatKBSize results */ +typedef struct tagStrFromTimeIntervalResult +{ + DWORD ms; + int digits; + const char* time_interval; +} StrFromTimeIntervalResult; + + +static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = { + { 1, 1, " 0 sec" }, + { 1, 2, " 0 sec" }, + { 1, 3, " 0 sec" }, + { 1, 4, " 0 sec" }, + { 1, 5, " 0 sec" }, + { 1, 6, " 0 sec" }, + { 1, 7, " 0 sec" }, + + { 1000000, 1, " 10 min" }, + { 1000000, 2, " 16 min" }, + { 1000000, 3, " 16 min 40 sec" }, + { 1000000, 4, " 16 min 40 sec" }, + { 1000000, 5, " 16 min 40 sec" }, + { 1000000, 6, " 16 min 40 sec" }, + { 1000000, 7, " 16 min 40 sec" }, + + { 1999999, 1, " 30 min" }, + { 1999999, 2, " 33 min" }, + { 1999999, 3, " 33 min 20 sec" }, + { 1999999, 4, " 33 min 20 sec" }, + { 1999999, 5, " 33 min 20 sec" }, + { 1999999, 6, " 33 min 20 sec" }, + { 1999999, 7, " 33 min 20 sec" }, + + { 3999997, 1, " 1 hr" }, + { 3999997, 2, " 1 hr 6 min" }, + { 3999997, 3, " 1 hr 6 min 40 sec" }, + { 3999997, 4, " 1 hr 6 min 40 sec" }, + { 3999997, 5, " 1 hr 6 min 40 sec" }, + { 3999997, 6, " 1 hr 6 min 40 sec" }, + { 3999997, 7, " 1 hr 6 min 40 sec" }, + + { 149999851, 7, " 41 hr 40 min 0 sec" }, + { 150999850, 1, " 40 hr" }, + { 150999850, 2, " 41 hr" }, + { 150999850, 3, " 41 hr 50 min" }, + { 150999850, 4, " 41 hr 56 min" }, + { 150999850, 5, " 41 hr 56 min 40 sec" }, + { 150999850, 6, " 41 hr 56 min 40 sec" }, + { 150999850, 7, " 41 hr 56 min 40 sec" }, + + { 493999507, 1, " 100 hr" }, + { 493999507, 2, " 130 hr" }, + { 493999507, 3, " 137 hr" }, + { 493999507, 4, " 137 hr 10 min" }, + { 493999507, 5, " 137 hr 13 min" }, + { 493999507, 6, " 137 hr 13 min 20 sec" }, + { 493999507, 7, " 137 hr 13 min 20 sec" }, + + { 0, 0, NULL } +}; + +static void test_StrChrA(void) +{ + char string[129]; + WORD count; + + /* this test crashes on win2k SP4 */ + /*ok(!StrChrA(NULL,'\0'), "found a character in a NULL string!\n");*/ + + for (count = 32; count < 128; count++) + string[count] = (char)count; + string[128] = '\0'; + + for (count = 32; count < 128; count++) + { + LPSTR result = StrChrA(string+32, count); + ok(result - string == count, + "found char '%c' in wrong place: got %d, expected %d\n", + count, result - string, count); + } + + for (count = 32; count < 128; count++) + { + LPSTR result = StrChrA(string+count+1, count); + ok(!result, "found char '%c' not in the string\n", count); + } +} + +static void test_StrChrW(void) +{ + WCHAR string[16385]; + WORD count; + + /* this test crashes on win2k SP4 */ + /*ok(!StrChrW(NULL,'\0'), "found a character in a NULL string!\n");*/ + + for (count = 32; count < 16384; count++) + string[count] = count; + string[16384] = '\0'; + + for (count = 32; count < 16384; count++) + { + LPWSTR result = StrChrW(string+32, count); + ok((result - string) == count, "found char %d in wrong place\n", count); + } + + for (count = 32; count < 16384; count++) + { + LPWSTR result = StrChrW(string+count+1, count); + ok(!result, "found char not in the string\n"); + } +} + +static void test_StrChrIA(void) +{ + char string[129]; + WORD count; + + /* this test crashes on win2k SP4 */ + /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/ + + for (count = 32; count < 128; count++) + string[count] = (char)count; + string[128] = '\0'; + + for (count = 'A'; count <= 'X'; count++) + { + LPSTR result = StrChrIA(string+32, count); + + ok(result - string == count, "found char '%c' in wrong place\n", count); + ok(StrChrIA(result, count)!=NULL, "didn't find lowercase '%c'\n", count); + } + + for (count = 'a'; count < 'z'; count++) + { + LPSTR result = StrChrIA(string+count+1, count); + ok(!result, "found char not in the string\n"); + } +} + +static void test_StrChrIW(void) +{ + WCHAR string[129]; + WORD count; + + /* this test crashes on win2k SP4 */ + /*ok(!StrChrIA(NULL,'\0'), "found a character in a NULL string!\n");*/ + + for (count = 32; count < 128; count++) + string[count] = count; + string[128] = '\0'; + + for (count = 'A'; count <= 'X'; count++) + { + LPWSTR result = StrChrIW(string+32, count); + + ok(result - string == count, "found char '%c' in wrong place\n", count); + ok(StrChrIW(result, count)!=NULL, "didn't find lowercase '%c'\n", count); + } + + for (count = 'a'; count < 'z'; count++) + { + LPWSTR result = StrChrIW(string+count+1, count); + ok(!result, "found char not in the string\n"); + } +} + +static void test_StrRChrA(void) +{ + char string[129]; + WORD count; + + /* this test crashes on win2k SP4 */ + /*ok(!StrRChrA(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/ + + for (count = 32; count < 128; count++) + string[count] = (char)count; + string[128] = '\0'; + + for (count = 32; count < 128; count++) + { + LPSTR result = StrRChrA(string+32, NULL, count); + ok(result - string == count, "found char %d in wrong place\n", count); + } + + for (count = 32; count < 128; count++) + { + LPSTR result = StrRChrA(string+count+1, NULL, count); + ok(!result, "found char not in the string\n"); + } + + for (count = 32; count < 128; count++) + { + LPSTR result = StrRChrA(string+count+1, string + 127, count); + ok(!result, "found char not in the string\n"); + } +} + +static void test_StrRChrW(void) +{ + WCHAR string[129]; + WORD count; + + /* this test crashes on win2k SP4 */ + /*ok(!StrRChrW(NULL, NULL,'\0'), "found a character in a NULL string!\n");*/ + + for (count = 32; count < 128; count++) + string[count] = count; + string[128] = '\0'; + + for (count = 32; count < 128; count++) + { + LPWSTR result = StrRChrW(string+32, NULL, count); + ok(result - string == count, + "found char %d in wrong place: got %d, expected %d\n", + count, result - string, count); + } + + for (count = 32; count < 128; count++) + { + LPWSTR result = StrRChrW(string+count+1, NULL, count); + ok(!result, "found char %d not in the string\n", count); + } + + for (count = 32; count < 128; count++) + { + LPWSTR result = StrRChrW(string+count+1, string + 127, count); + ok(!result, "found char %d not in the string\n", count); + } +} + +static void test_StrCpyW(void) +{ + WCHAR szSrc[256]; + WCHAR szBuff[256]; + const StrFormatSizeResult* result = StrFormatSize_results; + + + while(result->value) + { + MultiByteToWideChar(0,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR)); + + StrCpyW(szBuff, szSrc); + ok(!StrCmpW(szSrc, szBuff), "Copied string %s wrong\n", result->byte_size_64); + result++; + } +} + + +static void test_StrToIntA(void) +{ + const StrToIntResult *result = StrToInt_results; + int return_val; + + while (result->string) + { + return_val = StrToIntA(result->string); + ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n", + result->string, return_val); + result++; + } +} + +static void test_StrToIntW(void) +{ + WCHAR szBuff[256]; + const StrToIntResult *result = StrToInt_results; + int return_val; + + while (result->string) + { + MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR)); + return_val = StrToIntW(szBuff); + ok(return_val == result->str_to_int, "converted '%s' wrong (%d)\n", + result->string, return_val); + result++; + } +} + +static void test_StrToIntExA(void) +{ + const StrToIntResult *result = StrToInt_results; + int return_val; + BOOL bRet; + + while (result->string) + { + return_val = -1; + bRet = StrToIntExA(result->string,0,&return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n", + result->string, return_val); + result++; + } + + result = StrToInt_results; + while (result->string) + { + return_val = -1; + bRet = StrToIntExA(result->string,STIF_SUPPORT_HEX,&return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n", + result->string, return_val); + result++; + } +} + +static void test_StrToIntExW(void) +{ + WCHAR szBuff[256]; + const StrToIntResult *result = StrToInt_results; + int return_val; + BOOL bRet; + + while (result->string) + { + return_val = -1; + MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR)); + bRet = StrToIntExW(szBuff, 0, &return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int_ex, "converted '%s' wrong (%d)\n", + result->string, return_val); + result++; + } + + result = StrToInt_results; + while (result->string) + { + return_val = -1; + MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR)); + bRet = StrToIntExW(szBuff, STIF_SUPPORT_HEX, &return_val); + ok(!bRet || return_val != -1, "No result returned from '%s'\n", + result->string); + if (bRet) + ok(return_val == result->str_to_int_hex, "converted '%s' wrong (%d)\n", + result->string, return_val); + result++; + } +} + +static void test_StrDupA(void) +{ + LPSTR lpszStr; + const StrFormatSizeResult* result = StrFormatSize_results; + + while(result->value) + { + lpszStr = StrDupA(result->byte_size_64); + + ok(lpszStr != NULL, "Dup failed\n"); + if (lpszStr) + { + ok(!strcmp(result->byte_size_64, lpszStr), "Copied string wrong\n"); + LocalFree((HLOCAL)lpszStr); + } + result++; + } + + /* Later versions of shlwapi return NULL for this, but earlier versions + * returned an empty string (as Wine does). + */ + lpszStr = StrDupA(NULL); + ok(lpszStr == NULL || *lpszStr == '\0', "NULL string returned %p\n", lpszStr); +} + +static void test_StrFormatByteSize64A(void) +{ + char szBuff[256]; + const StrFormatSizeResult* result = StrFormatSize_results; + + while(result->value) + { + StrFormatByteSize64A(result->value, szBuff, 256); + + ok(!strcmp(result->byte_size_64, szBuff), + "Formatted %lx%08lx wrong: got %s, expected %s\n", + (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->byte_size_64); + + result++; + } +} + +static void test_StrFormatKBSizeW(void) +{ + WCHAR szBuffW[256]; + char szBuff[256]; + const StrFormatSizeResult* result = StrFormatSize_results; + + while(result->value) + { + StrFormatKBSizeW(result->value, szBuffW, 256); + WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0); + ok(!strcmp(result->kb_size, szBuff), + "Formatted %lx%08lx wrong: got %s, expected %s\n", + (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size); + result++; + } +} + +static void test_StrFormatKBSizeA(void) +{ + char szBuff[256]; + const StrFormatSizeResult* result = StrFormatSize_results; + + while(result->value) + { + StrFormatKBSizeA(result->value, szBuff, 256); + + ok(!strcmp(result->kb_size, szBuff), + "Formatted %lx%08lx wrong: got %s, expected %s\n", + (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size); + result++; + } +} + +static void test_StrFromTimeIntervalA(void) +{ + char szBuff[256]; + const StrFromTimeIntervalResult* result = StrFromTimeInterval_results; + + while(result->ms) + { + StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits); + + ok(!strcmp(result->time_interval, szBuff), "Formatted %ld %d wrong\n", + result->ms, result->digits); + result++; + } +} + +static void test_StrCmpA(void) +{ + static const char str1[] = {'a','b','c','d','e','f'}; + static const char str2[] = {'a','B','c','d','e','f'}; + ok(0 != StrCmpNA(str1, str2, 6), "StrCmpNA is case-insensitive\n"); + ok(0 == StrCmpNIA(str1, str2, 6), "StrCmpNIA is case-sensitive\n"); + ok(!ChrCmpIA('a', 'a'), "ChrCmpIA doesn't work at all!\n"); + ok(!ChrCmpIA('b', 'B'), "ChrCmpIA is not case-insensitive\n"); + ok(ChrCmpIA('a', 'z'), "ChrCmpIA believes that a == z!\n"); + + pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA"); + pIntlStrEqWorkerA = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerA"); + + if (!pStrIsIntlEqualA) + return; + + ok(pStrIsIntlEqualA(FALSE, str1, str2, 5), "StrIsIntlEqualA(FALSE,...) isn't case-insensitive\n"); + ok(!pStrIsIntlEqualA(TRUE, str1, str2, 5), "StrIsIntlEqualA(TRUE,...) isn't case-sensitive\n"); + + if (!pIntlStrEqWorkerA) + return; + + ok(pIntlStrEqWorkerA(FALSE, str1, str2, 5), "IntlStrEqWorkerA(FALSE,...) isn't case-insensitive\n"); + ok(!pIntlStrEqWorkerA(TRUE, str1, str2, 5), "pIntlStrEqWorkerA(TRUE,...) isn't case-sensitive\n"); +} + +static void test_StrCmpW(void) +{ + static const WCHAR str1[] = {'a','b','c','d','e','f'}; + static const WCHAR str2[] = {'a','B','c','d','e','f'}; + ok(0 != StrCmpNW(str1, str2, 5), "StrCmpNW is case-insensitive\n"); + ok(0 == StrCmpNIW(str1, str2, 5), "StrCmpNIW is case-sensitive\n"); + ok(!ChrCmpIW('a', 'a'), "ChrCmpIW doesn't work at all!\n"); + ok(!ChrCmpIW('b', 'B'), "ChrCmpIW is not case-insensitive\n"); + ok(ChrCmpIW('a', 'z'), "ChrCmpIW believes that a == z!\n"); + + pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW"); + pIntlStrEqWorkerW = (void *)GetProcAddress(hShlwapi, "IntlStrEqWorkerW"); + + if (!pStrIsIntlEqualW) + return; + + ok(pStrIsIntlEqualW(FALSE, str1, str2, 5), "StrIsIntlEqualW(FALSE,...) isn't case-insensitive\n"); + ok(!pStrIsIntlEqualW(TRUE, str1, str2, 5), "StrIsIntlEqualW(TRUE,...) isn't case-sensitive\n"); + + if (!pIntlStrEqWorkerW) + return; + + ok(pIntlStrEqWorkerW(FALSE, str1, str2, 5), "IntlStrEqWorkerW(FALSE,...) isn't case-insensitive\n"); + ok(!pIntlStrEqWorkerW(TRUE, str1, str2, 5), "IntlStrEqWorkerW(TRUE,...) isn't case-sensitive\n"); +} + +static WCHAR *CoDupStrW(const char* src) +{ + INT len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + WCHAR* szTemp = (WCHAR*)CoTaskMemAlloc(len * sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, src, -1, szTemp, len); + return szTemp; +} + +static void test_StrRetToBSTR(void) +{ + static const WCHAR szTestW[] = { 'T','e','s','t','\0' }; + ITEMIDLIST iidl[10]; + BSTR bstr; + STRRET strret; + HRESULT ret; + + pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR"); + if (!pStrRetToBSTR) return; + + strret.uType = STRRET_WSTR; + strret.u.pOleStr = CoDupStrW("Test"); + bstr = 0; + ret = pStrRetToBSTR(&strret, NULL, &bstr); + ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW), + "STRRET_WSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr); + if (bstr) + SysFreeString(bstr); + + strret.uType = STRRET_CSTR; + lstrcpyA(strret.u.cStr, "Test"); + ret = pStrRetToBSTR(&strret, NULL, &bstr); + ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW), + "STRRET_CSTR: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr); + if (bstr) + SysFreeString(bstr); + + strret.uType = STRRET_OFFSET; + strret.u.uOffset = 1; + strcpy((char*)&iidl, " Test"); + ret = pStrRetToBSTR(&strret, iidl, &bstr); + ok(ret == S_OK && bstr && !strcmpW(bstr, szTestW), + "STRRET_OFFSET: dup failed, ret=0x%08lx, bstr %p\n", ret, bstr); + if (bstr) + SysFreeString(bstr); + + /* Native crashes if str is NULL */ +} + +static void test_StrCpyNXA(void) +{ + LPCSTR lpSrc = "hello"; + LPSTR lpszRes; + char dest[8]; + + pStrCpyNXA = (void *)GetProcAddress(hShlwapi, (LPSTR)399); + if (!pStrCpyNXA) + return; + + memset(dest, '\n', sizeof(dest)); + lpszRes = pStrCpyNXA(dest, lpSrc, sizeof(dest)/sizeof(dest[0])); + ok(lpszRes == dest + 5 && !memcmp(dest, "hello\0\n\n", sizeof(dest)), + "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n", + dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); +} + +static void test_StrCpyNXW(void) +{ + static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' }; + static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' }; + static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' }; + LPWSTR lpszRes; + WCHAR dest[8]; + + pStrCpyNXW = (void *)GetProcAddress(hShlwapi, (LPSTR)400); + if (!pStrCpyNXW) + return; + + memcpy(dest, lpInit, sizeof(lpInit)); + lpszRes = pStrCpyNXW(dest, lpSrc, sizeof(dest)/sizeof(dest[0])); + ok(lpszRes == dest + 5 && !memcmp(dest, lpRes, sizeof(dest)), + "StrCpyNXA: expected %p, \"hello\\0\\n\\n\", got %p, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n", + dest + 5, lpszRes, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); +} + +static void test_SHAnsiToAnsi(void) +{ + char dest[8]; + DWORD dwRet; + + pSHAnsiToAnsi = (void *)GetProcAddress(hShlwapi, (LPSTR)345); + if (!pSHAnsiToAnsi) + return; + + memset(dest, '\n', sizeof(dest)); + dwRet = pSHAnsiToAnsi("hello", dest, sizeof(dest)/sizeof(dest[0])); + ok(dwRet == 6 && !memcmp(dest, "hello\0\n\n", sizeof(dest)), + "SHAnsiToAnsi: expected 6, \"hello\\0\\n\\n\", got %ld, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n", + dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); +} + +static void test_SHUnicodeToUnicode(void) +{ + static const WCHAR lpInit[] = { '\n','\n','\n','\n','\n','\n','\n','\n' }; + static const WCHAR lpSrc[] = { 'h','e','l','l','o','\0' }; + static const WCHAR lpRes[] = { 'h','e','l','l','o','\0','\n','\n' }; + WCHAR dest[8]; + DWORD dwRet; + + pSHUnicodeToUnicode = (void *)GetProcAddress(hShlwapi, (LPSTR)346); + if (!pSHUnicodeToUnicode) + return; + + memcpy(dest, lpInit, sizeof(lpInit)); + dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0])); + ok(dwRet == 6 && !memcmp(dest, lpRes, sizeof(dest)), + "SHUnicodeToUnicode: expected 6, \"hello\\0\\n\\n\", got %ld, \"%d,%d,%d,%d,%d,%d,%d,%d\"\n", + dwRet, dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); +} + +START_TEST(string) +{ + CoInitialize(0); + + hShlwapi = GetModuleHandleA("shlwapi"); + if (!hShlwapi) + return; + + test_StrChrA(); + test_StrChrW(); + test_StrChrIA(); + test_StrChrIW(); + test_StrRChrA(); + test_StrRChrW(); + test_StrCpyW(); + test_StrToIntA(); + test_StrToIntW(); + test_StrToIntExA(); + test_StrToIntExW(); + test_StrDupA(); + if (0) + { + /* this test fails on locales which do not use '.' as a decimal separator */ + test_StrFormatByteSize64A(); + + /* this test fails on locales which do not use '.' as a decimal separator */ + test_StrFormatKBSizeA(); + + /* FIXME: Awaiting NLS fixes in kernel before these succeed */ + test_StrFormatKBSizeW(); + } + test_StrFromTimeIntervalA(); + test_StrCmpA(); + test_StrCmpW(); + test_StrRetToBSTR(); + test_StrCpyNXA(); + test_StrCpyNXW(); + test_SHAnsiToAnsi(); + test_SHUnicodeToUnicode(); +} diff --git a/reactos/regtests/winetests/shlwapi/testlist.c b/reactos/regtests/winetests/shlwapi/testlist.c new file mode 100755 index 00000000000..16fec43993d --- /dev/null +++ b/reactos/regtests/winetests/shlwapi/testlist.c @@ -0,0 +1,32 @@ +/* Automatically generated file; DO NOT EDIT!! */ + +/* stdarg.h is needed for Winelib */ +#include +#include +#include +#include "windef.h" +#include "winbase.h" + +extern void func_clist(void); +extern void func_ordinal(void); +extern void func_path(void); +extern void func_shreg(void); +extern void func_string(void); + +struct test +{ + const char *name; + void (*func)(void); +}; + +const struct test winetest_testlist[] = +{ + { "clist", func_clist }, + { "ordinal", func_ordinal }, + { "shreg", func_shreg }, + { "string", func_string }, + { 0, 0 } +}; + +#define WINETEST_WANT_MAIN +#include "wine/test.h"