--- /dev/null
+Makefile
+clist.ok
+clsid.ok
+generated.ok
+ordinal.ok
+path.ok
+shreg.ok
+string.ok
+testlist.c
--- /dev/null
+/* 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 <stdarg.h>
+
+#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);
+}
--- /dev/null
+/* 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 <stdio.h>
+
+#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);
+}
--- /dev/null
+/* 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 <stdarg.h>
+#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();
+}
--- /dev/null
+/* 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 <stdio.h>
+
+#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);
+}
--- /dev/null
+/* 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#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<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
+ test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
+ TEST_ESCAPE[i].expectret, TEST_ESCAPE[i].expecturl);
+ }
+}
+
+static void test_UrlCanonicalize(void)
+{
+ unsigned int i;
+ for(i=0; i<sizeof(TEST_CANONICALIZE)/sizeof(TEST_CANONICALIZE[0]); i++) {
+ test_url_canonicalize(TEST_CANONICALIZE[i].url, TEST_CANONICALIZE[i].flags,
+ TEST_CANONICALIZE[i].expectret, TEST_CANONICALIZE[i].expecturl);
+ }
+}
+
+static void test_url_combine(const char *szUrl1, const char *szUrl2, DWORD dwFlags, HRESULT dwExpectReturn, const char *szExpectUrl)
+{
+ HRESULT hr;
+ CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
+ WCHAR wszReturnUrl[INTERNET_MAX_URL_LENGTH];
+ LPWSTR wszUrl1 = GetWideString(szUrl1);
+ LPWSTR wszUrl2 = GetWideString(szUrl2);
+ LPWSTR wszExpectUrl = GetWideString(szExpectUrl);
+ LPWSTR wszConvertedUrl;
+
+ DWORD dwSize;
+ DWORD dwExpectLen = lstrlen(szExpectUrl);
+
+ hr = UrlCombineA(szUrl1, szUrl2, NULL, NULL, dwFlags);
+ ok(hr == E_INVALIDARG, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_INVALIDARG);
+
+ dwSize = 0;
+ hr = UrlCombineA(szUrl1, szUrl2, NULL, &dwSize, dwFlags);
+ ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
+ ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
+
+ dwSize--;
+ hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
+ ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
+ ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
+
+ hr = UrlCombineA(szUrl1, szUrl2, szReturnUrl, &dwSize, dwFlags);
+ ok(hr == dwExpectReturn, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
+ ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
+ if(SUCCEEDED(hr)) {
+ ok(strcmp(szReturnUrl,szExpectUrl)==0, "Expected %s, but got %s\n", szExpectUrl, szReturnUrl);
+ }
+
+ dwSize = 0;
+ hr = UrlCombineW(wszUrl1, wszUrl2, NULL, &dwSize, dwFlags);
+ ok(hr == E_POINTER, "Checking length of string, return was 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
+ ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
+
+ dwSize--;
+ hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
+ ok(hr == E_POINTER, "UrlCombineA returned 0x%08lx, expected 0x%08lx\n", hr, E_POINTER);
+ ok(dwSize == dwExpectLen+1, "Got length %ld, expected %ld\n", dwSize, dwExpectLen+1);
+
+ hr = UrlCombineW(wszUrl1, wszUrl2, wszReturnUrl, &dwSize, dwFlags);
+ ok(hr == dwExpectReturn, "UrlCombineW returned 0x%08lx, expected 0x%08lx\n", hr, dwExpectReturn);
+ ok(dwSize == dwExpectLen, "Got length %ld, expected %ld\n", dwSize, dwExpectLen);
+ if(SUCCEEDED(hr)) {
+ wszConvertedUrl = GetWideString(szReturnUrl);
+ ok(strcmpW(wszReturnUrl, wszConvertedUrl)==0, "Strings didn't match between ascii and unicode UrlCombine!\n");
+ FreeWideString(wszConvertedUrl);
+ }
+
+ FreeWideString(wszUrl1);
+ FreeWideString(wszUrl2);
+ FreeWideString(wszExpectUrl);
+}
+
+static void test_UrlCombine(void)
+{
+ unsigned int i;
+ for(i=0; i<sizeof(TEST_COMBINE)/sizeof(TEST_COMBINE[0]); i++) {
+ test_url_combine(TEST_COMBINE[i].url1, TEST_COMBINE[i].url2, TEST_COMBINE[i].flags,
+ TEST_COMBINE[i].expectret, TEST_COMBINE[i].expecturl);
+ }
+}
+
+static void test_UrlCreateFromPath(void)
+{
+ size_t i;
+ char ret_url[INTERNET_MAX_URL_LENGTH];
+ DWORD len, ret;
+ WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
+ WCHAR *pathW, *urlW;
+
+ for(i = 0; i < sizeof(TEST_URLFROMPATH) / sizeof(TEST_URLFROMPATH[0]); i++) {
+ len = INTERNET_MAX_URL_LENGTH;
+ ret = UrlCreateFromPathA(TEST_URLFROMPATH[i].path, ret_url, &len, 0);
+ ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path %s\n", ret, TEST_URLFROMPATH[i].path);
+ ok(!lstrcmpi(ret_url, TEST_URLFROMPATH[i].url), "url %s from path %s\n", ret_url, TEST_URLFROMPATH[i].path);
+ ok(len == strlen(ret_url), "ret len %ld from path %s\n", len, TEST_URLFROMPATH[i].path);
+
+ len = INTERNET_MAX_URL_LENGTH;
+ pathW = GetWideString(TEST_URLFROMPATH[i].path);
+ urlW = GetWideString(TEST_URLFROMPATH[i].url);
+ ret = UrlCreateFromPathW(pathW, ret_urlW, &len, 0);
+ WideCharToMultiByte(CP_ACP, 0, ret_urlW, -1, ret_url, sizeof(ret_url),0,0);
+ ok(ret == TEST_URLFROMPATH[i].ret, "ret %08lx from path L\"%s\", expected %08lx\n",
+ ret, TEST_URLFROMPATH[i].path, TEST_URLFROMPATH[i].ret);
+ ok(!lstrcmpiW(ret_urlW, urlW), "got %s expected %s from path L\"%s\"\n", ret_url, TEST_URLFROMPATH[i].url, TEST_URLFROMPATH[i].path);
+ ok(len == strlenW(ret_urlW), "ret len %ld from path L\"%s\"\n", len, TEST_URLFROMPATH[i].path);
+ FreeWideString(urlW);
+ FreeWideString(pathW);
+ }
+}
+
+static void test_UrlIs(void)
+{
+ BOOL ret;
+ size_t i;
+ WCHAR wurl[80];
+
+ for(i = 0; i < sizeof(TEST_PATH_IS_URL) / sizeof(TEST_PATH_IS_URL[0]); i++) {
+ MultiByteToWideChar(CP_ACP, 0, TEST_PATH_IS_URL[i].path, -1, wurl, 80);
+
+ ret = UrlIsA( TEST_PATH_IS_URL[i].path, URLIS_URL );
+ ok( ret == TEST_PATH_IS_URL[i].expect,
+ "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
+ TEST_PATH_IS_URL[i].expect );
+
+ ret = UrlIsW( wurl, URLIS_URL );
+ ok( ret == TEST_PATH_IS_URL[i].expect,
+ "returned %d from path (UrlIsW) %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
+ TEST_PATH_IS_URL[i].expect );
+ }
+ for(i = 0; i < sizeof(TEST_URLIS_ATTRIBS) / sizeof(TEST_URLIS_ATTRIBS[0]); i++) {
+ MultiByteToWideChar(CP_ACP, 0, TEST_URLIS_ATTRIBS[i].url, -1, wurl, 80);
+
+ ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_OPAQUE);
+ ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
+ "returned %d for URLIS_OPAQUE, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
+ TEST_URLIS_ATTRIBS[i].expectOpaque );
+ ret = UrlIsA( TEST_URLIS_ATTRIBS[i].url, URLIS_FILEURL);
+ ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
+ "returned %d for URLIS_FILEURL, url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
+ TEST_URLIS_ATTRIBS[i].expectFile );
+
+ ret = UrlIsW( wurl, URLIS_OPAQUE);
+ ok( ret == TEST_URLIS_ATTRIBS[i].expectOpaque,
+ "returned %d for URLIS_OPAQUE (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
+ TEST_URLIS_ATTRIBS[i].expectOpaque );
+ ret = UrlIsW( wurl, URLIS_FILEURL);
+ ok( ret == TEST_URLIS_ATTRIBS[i].expectFile,
+ "returned %d for URLIS_FILEURL (UrlIsW), url \"%s\", expected %d\n", ret, TEST_URLIS_ATTRIBS[i].url,
+ TEST_URLIS_ATTRIBS[i].expectFile );
+ }
+}
+
+static void test_UrlUnescape(void)
+{
+ CHAR szReturnUrl[INTERNET_MAX_URL_LENGTH];
+ WCHAR ret_urlW[INTERNET_MAX_URL_LENGTH];
+ WCHAR *urlW, *expected_urlW;
+ DWORD dwEscaped;
+ size_t i;
+
+ for(i=0; i<sizeof(TEST_URL_UNESCAPE)/sizeof(TEST_URL_UNESCAPE[0]); i++) {
+ dwEscaped=INTERNET_MAX_URL_LENGTH;
+ ok(UrlUnescapeA(TEST_URL_UNESCAPE[i].url, szReturnUrl, &dwEscaped, 0) == S_OK, "UrlEscapeA didn't return 0x%08lx from \"%s\"\n", S_OK, TEST_URL_UNESCAPE[i].url);
+ ok(strcmp(szReturnUrl,TEST_URL_UNESCAPE[i].expect)==0, "Expected \"%s\", but got \"%s\" from \"%s\"\n", TEST_URL_UNESCAPE[i].expect, szReturnUrl, TEST_URL_UNESCAPE[i].url);
+
+ dwEscaped = INTERNET_MAX_URL_LENGTH;
+ urlW = GetWideString(TEST_URL_UNESCAPE[i].url);
+ expected_urlW = GetWideString(TEST_URL_UNESCAPE[i].expect);
+ ok(UrlUnescapeW(urlW, ret_urlW, &dwEscaped, 0) == S_OK, "UrlEscapeW didn't return 0x%08lx from \"%s\"\n", S_OK, TEST_URL_UNESCAPE[i].url);
+ 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", TEST_URL_UNESCAPE[i].expect, szReturnUrl, TEST_URL_UNESCAPE[i].url, 0L);
+ FreeWideString(urlW);
+ FreeWideString(expected_urlW);
+ }
+
+}
+
+static void test_PathSearchAndQualify(void)
+{
+ WCHAR path1[] = {'c',':','\\','f','o','o',0};
+ WCHAR expect1[] = {'c',':','\\','f','o','o',0};
+ WCHAR path2[] = {'c',':','f','o','o',0};
+ WCHAR c_drive[] = {'c',':',0};
+ WCHAR foo[] = {'f','o','o',0};
+ WCHAR path3[] = {'\\','f','o','o',0};
+ WCHAR winini[] = {'w','i','n','.','i','n','i',0};
+ WCHAR out[MAX_PATH];
+ WCHAR cur_dir[MAX_PATH];
+ WCHAR dot[] = {'.',0};
+
+ /* c:\foo */
+ ok(PathSearchAndQualifyW(path1, out, MAX_PATH) != 0,
+ "PathSearchAndQualify rets 0\n");
+ ok(!lstrcmpiW(out, expect1), "strings don't match\n");
+
+ /* c:foo */
+ ok(PathSearchAndQualifyW(path2, out, MAX_PATH) != 0,
+ "PathSearchAndQualify rets 0\n");
+ GetFullPathNameW(c_drive, MAX_PATH, cur_dir, NULL);
+ PathAddBackslashW(cur_dir);
+ strcatW(cur_dir, foo);
+ ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
+
+ /* foo */
+ ok(PathSearchAndQualifyW(foo, out, MAX_PATH) != 0,
+ "PathSearchAndQualify rets 0\n");
+ GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
+ PathAddBackslashW(cur_dir);
+ strcatW(cur_dir, foo);
+ ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
+
+ /* \foo */
+ ok(PathSearchAndQualifyW(path3, out, MAX_PATH) != 0,
+ "PathSearchAndQualify rets 0\n");
+ GetFullPathNameW(dot, MAX_PATH, cur_dir, NULL);
+ strcpyW(cur_dir + 2, path3);
+ ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
+
+ /* win.ini */
+ ok(PathSearchAndQualifyW(winini, out, MAX_PATH) != 0,
+ "PathSearchAndQualify rets 0\n");
+ if(!SearchPathW(NULL, winini, NULL, MAX_PATH, cur_dir, NULL))
+ GetFullPathNameW(winini, MAX_PATH, cur_dir, NULL);
+ ok(!lstrcmpiW(out, cur_dir), "strings don't match\n");
+
+}
+
+static void test_PathCreateFromUrl(void)
+{
+ size_t i;
+ char ret_path[INTERNET_MAX_URL_LENGTH];
+ DWORD len, ret;
+ WCHAR ret_pathW[INTERNET_MAX_URL_LENGTH];
+ WCHAR *pathW, *urlW;
+
+ for(i = 0; i < sizeof(TEST_PATHFROMURL) / sizeof(TEST_PATHFROMURL[0]); i++) {
+ len = INTERNET_MAX_URL_LENGTH;
+ ret = PathCreateFromUrlA(TEST_PATHFROMURL[i].url, ret_path, &len, 0);
+ ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url %s\n", ret, TEST_PATHFROMURL[i].url);
+ if(TEST_PATHFROMURL[i].path) {
+ ok(!lstrcmpi(ret_path, TEST_PATHFROMURL[i].path), "got %s expected %s from url %s\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
+ ok(len == strlen(ret_path), "ret len %ld from url %s\n", len, TEST_PATHFROMURL[i].url);
+ }
+ len = INTERNET_MAX_URL_LENGTH;
+ pathW = GetWideString(TEST_PATHFROMURL[i].path);
+ urlW = GetWideString(TEST_PATHFROMURL[i].url);
+ ret = PathCreateFromUrlW(urlW, ret_pathW, &len, 0);
+ WideCharToMultiByte(CP_ACP, 0, ret_pathW, -1, ret_path, sizeof(ret_path),0,0);
+ ok(ret == TEST_PATHFROMURL[i].ret, "ret %08lx from url L\"%s\"\n", ret, TEST_PATHFROMURL[i].url);
+ if(TEST_PATHFROMURL[i].path) {
+ ok(!lstrcmpiW(ret_pathW, pathW), "got %s expected %s from url L\"%s\"\n", ret_path, TEST_PATHFROMURL[i].path, TEST_PATHFROMURL[i].url);
+ ok(len == strlenW(ret_pathW), "ret len %ld from url L\"%s\"\n", len, TEST_PATHFROMURL[i].url);
+ }
+ FreeWideString(urlW);
+ FreeWideString(pathW);
+ }
+}
+
+
+static void test_PathIsUrl(void)
+{
+ size_t i;
+ BOOL ret;
+
+ for(i = 0; i < sizeof(TEST_PATH_IS_URL)/sizeof(TEST_PATH_IS_URL[0]); i++) {
+ ret = PathIsURLA(TEST_PATH_IS_URL[i].path);
+ ok(ret == TEST_PATH_IS_URL[i].expect,
+ "returned %d from path %s, expected %d\n", ret, TEST_PATH_IS_URL[i].path,
+ TEST_PATH_IS_URL[i].expect);
+ }
+}
+
+static const DWORD SHELL_charclass[] =
+{
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000080, 0x00000100, 0x00000200, 0x00000100,
+ 0x00000100, 0x00000100, 0x00000100, 0x00000100,
+ 0x00000100, 0x00000100, 0x00000002, 0x00000100,
+ 0x00000040, 0x00000100, 0x00000004, 0x00000000,
+ 0x00000100, 0x00000100, 0x00000100, 0x00000100,
+ 0x00000100, 0x00000100, 0x00000100, 0x00000100,
+ 0x00000100, 0x00000100, 0x00000010, 0x00000020,
+ 0x00000000, 0x00000100, 0x00000000, 0x00000001,
+ 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
+ 0x00000008, 0x00000100, 0x00000100, 0x00000100,
+ 0x00000100, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0x00000100,
+ 0x00000000, 0x00000100, 0x00000100
+};
+
+static void test_PathIsValidCharA(void)
+{
+ BOOL ret;
+ unsigned int c;
+
+ ret = pPathIsValidCharA( 0x7f, 0 );
+ ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
+
+ ret = pPathIsValidCharA( 0x7f, 1 );
+ ok ( !ret, "PathIsValidCharA succeeded: 0x%08lx\n", (DWORD)ret );
+
+ for (c = 0; c < 0x7f; c++)
+ {
+ ret = pPathIsValidCharA( c, ~0U );
+ ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
+ "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
+ c, (DWORD)ret, SHELL_charclass[c] );
+ }
+
+ for (c = 0x7f; c <= 0xff; c++)
+ {
+ ret = pPathIsValidCharA( c, ~0U );
+ ok ( ret == 0x00000100,
+ "PathIsValidCharA failed: 0x%02x got 0x%08lx expected 0x00000100\n",
+ c, (DWORD)ret );
+ }
+}
+
+static void test_PathIsValidCharW(void)
+{
+ BOOL ret;
+ unsigned int c;
+
+ ret = pPathIsValidCharW( 0x7f, 0 );
+ ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
+
+ ret = pPathIsValidCharW( 0x7f, 1 );
+ ok ( !ret, "PathIsValidCharW succeeded: 0x%08lx\n", (DWORD)ret );
+
+ for (c = 0; c < 0x7f; c++)
+ {
+ ret = pPathIsValidCharW( c, ~0U );
+ ok ( ret == SHELL_charclass[c] || (ret == 1 && SHELL_charclass[c] == 0xffffffff),
+ "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x%08lx\n",
+ c, (DWORD)ret, SHELL_charclass[c] );
+ }
+
+ for (c = 0x007f; c <= 0xffff; c++)
+ {
+ ret = pPathIsValidCharW( c, ~0U );
+ ok ( ret == 0x00000100,
+ "PathIsValidCharW failed: 0x%02x got 0x%08lx expected 0x00000100\n",
+ c, (DWORD)ret );
+ }
+}
+
+static void test_PathMakePretty(void)
+{
+ char buff[MAX_PATH];
+
+ ok (PathMakePrettyA(NULL) == FALSE, "PathMakePretty: NULL path succeeded\n");
+ buff[0] = '\0';
+ ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Empty path failed\n");
+
+ strcpy(buff, "C:\\A LONG FILE NAME WITH \\SPACES.TXT");
+ ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Long UC name failed\n");
+ ok (strcmp(buff, "C:\\a long file name with \\spaces.txt") == 0,
+ "PathMakePretty: Long UC name not changed\n");
+
+ strcpy(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT");
+ ok (PathMakePrettyA(buff) == FALSE, "PathMakePretty: Long MC name succeeded\n");
+ ok (strcmp(buff, "C:\\A LONG FILE NAME WITH \\MixedCase.TXT") == 0,
+ "PathMakePretty: Failed but modified path\n");
+
+ strcpy(buff, "TEST");
+ ok (PathMakePrettyA(buff) == TRUE, "PathMakePretty: Short name failed\n");
+ ok (strcmp(buff, "Test") == 0, "PathMakePretty: 1st char lowercased %s\n", buff);
+}
+
+START_TEST(path)
+{
+ hShlwapi = LoadLibraryA("shlwapi.dll");
+ if (!hShlwapi) return;
+
+ test_UrlHash();
+ test_UrlGetPart();
+ test_UrlCanonicalize();
+ test_UrlEscape();
+ test_UrlCombine();
+ test_UrlCreateFromPath();
+ test_UrlIs();
+ test_UrlUnescape();
+
+ test_PathSearchAndQualify();
+ test_PathCreateFromUrl();
+ test_PathIsUrl();
+
+ test_PathMakePretty();
+
+ /* For whatever reason, PathIsValidCharA and PathAppendA share the same
+ * ordinal number in some native versions. Check this to prevent a crash.
+ */
+ pPathIsValidCharA = (void*)GetProcAddress(hShlwapi, (LPSTR)455);
+ if (pPathIsValidCharA && pPathIsValidCharA != (void*)GetProcAddress(hShlwapi, "PathAppendA"))
+ {
+ test_PathIsValidCharA();
+
+ pPathIsValidCharW = (void*)GetProcAddress(hShlwapi, (LPSTR)456);
+ if (pPathIsValidCharW) test_PathIsValidCharW();
+ }
+}
--- /dev/null
+<module name="shlwapi_test" type="win32cui" installbase="bin" installname="shlwapi_test.exe" warnings="true">
+ <include base="shlwapi_test">.</include>
+ <define name="__USE_W32API" />
+ <library>ntdll</library>
+ <library>shlwapi</library>
+ <library>ole32</library>
+ <library>oleaut32</library>
+ <file>clist.c</file>
+ <file>ordinal.c</file>
+ <file>shreg.c</file>
+ <file>string.c</file>
+ <file>testlist.c</file>
+</module>
--- /dev/null
+/* 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#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" );
+}
--- /dev/null
+/* 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 <stdio.h>
+
+#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();
+}
--- /dev/null
+/* Automatically generated file; DO NOT EDIT!! */
+
+/* stdarg.h is needed for Winelib */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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"