[SHLWAPI_WINETEST]: Sync to Wine 1.5.13.
authorAmine Khaldi <amine.khaldi@reactos.org>
Sat, 29 Sep 2012 13:14:50 +0000 (13:14 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Sat, 29 Sep 2012 13:14:50 +0000 (13:14 +0000)
CORE-6415

svn path=/trunk/; revision=57428

rostests/winetests/shlwapi/CMakeLists.txt
rostests/winetests/shlwapi/clist.c
rostests/winetests/shlwapi/clsid.c
rostests/winetests/shlwapi/istream.c
rostests/winetests/shlwapi/ordinal.c
rostests/winetests/shlwapi/path.c
rostests/winetests/shlwapi/shreg.c
rostests/winetests/shlwapi/string.c
rostests/winetests/shlwapi/thread.c
rostests/winetests/shlwapi/url.c

index 807f11a..1676f6c 100644 (file)
@@ -1,7 +1,5 @@
 
 
-add_definitions(
-    -D__ROS_LONG64__
-    -D_DLL -D__USE_CRTIMP)
+add_definitions(-D__ROS_LONG64__)
 
 remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502)
 
 
 remove_definitions(-DWINVER=0x502 -D_WIN32_IE=0x600 -D_WIN32_WINNT=0x502)
 
@@ -15,9 +13,9 @@ list(APPEND SOURCE
     path.c
     shreg.c
     string.c
     path.c
     shreg.c
     string.c
+    thread.c
     url.c
     url.c
-    testlist.c
-    thread.c)
+    testlist.c)
 
 add_executable(shlwapi_winetest ${SOURCE})
 target_link_libraries(shlwapi_winetest wine uuid)
 
 add_executable(shlwapi_winetest ${SOURCE})
 target_link_libraries(shlwapi_winetest wine uuid)
index 3b979fd..65d3178 100755 (executable)
@@ -212,10 +212,16 @@ static HRESULT (WINAPI *pSHLWAPI_213)(_IDummyStream*);
 static HRESULT (WINAPI *pSHLWAPI_214)(_IDummyStream*,ULARGE_INTEGER*);
 
 
 static HRESULT (WINAPI *pSHLWAPI_214)(_IDummyStream*,ULARGE_INTEGER*);
 
 
-static void InitFunctionPtrs(void)
+static BOOL InitFunctionPtrs(void)
 {
   SHLWAPI_hshlwapi = GetModuleHandleA("shlwapi.dll");
 
 {
   SHLWAPI_hshlwapi = GetModuleHandleA("shlwapi.dll");
 
+  /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
+  if(!GetProcAddress(SHLWAPI_hshlwapi, "SHCreateStreamOnFileEx")){
+      win_skip("Too old shlwapi version\n");
+      return FALSE;
+  }
+
   pSHLWAPI_17 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)17);
   ok(pSHLWAPI_17 != 0, "No Ordinal 17\n");
   pSHLWAPI_18 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)18);
   pSHLWAPI_17 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)17);
   ok(pSHLWAPI_17 != 0, "No Ordinal 17\n");
   pSHLWAPI_18 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)18);
@@ -238,6 +244,8 @@ static void InitFunctionPtrs(void)
   ok(pSHLWAPI_213 != 0, "No Ordinal 213\n");
   pSHLWAPI_214 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)214);
   ok(pSHLWAPI_214 != 0, "No Ordinal 214\n");
   ok(pSHLWAPI_213 != 0, "No Ordinal 213\n");
   pSHLWAPI_214 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)214);
   ok(pSHLWAPI_214 != 0, "No Ordinal 214\n");
+
+  return TRUE;
 }
 
 static void InitDummyStream(_IDummyStream* iface)
 }
 
 static void InitDummyStream(_IDummyStream* iface)
@@ -363,26 +371,22 @@ static void test_CList(void)
   inserted = (LPSHLWAPI_CLIST)buff;
   inserted->ulSize = sizeof(SHLWAPI_CLIST) -1;
   inserted->ulId = 33;
   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.
    */
   /* 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");
-  }
+  pSHLWAPI_20(&list, inserted);
+
   inserted = pSHLWAPI_22(list, 33);
   ok(inserted == NULL, "inserted bad element size\n");
 
   inserted = (LPSHLWAPI_CLIST)buff;
   inserted->ulSize = 44;
   inserted->ulId = ~0U;
   inserted = pSHLWAPI_22(list, 33);
   ok(inserted == NULL, "inserted bad element size\n");
 
   inserted = (LPSHLWAPI_CLIST)buff;
   inserted->ulSize = 44;
   inserted->ulId = ~0U;
-  hRet = pSHLWAPI_20(&list, inserted);
+
   /* See comment above, some early versions fail this call */
   /* See comment above, some early versions fail this call */
-  if (0)
-  {
-  ok(hRet == S_OK, "failed adding a container\n");
-  }
+  pSHLWAPI_20(&list, inserted);
+
   item = SHLWAPI_CLIST_items;
 
   /* Look for nonexistent item in populated list */
   item = SHLWAPI_CLIST_items;
 
   /* Look for nonexistent item in populated list */
@@ -623,7 +627,8 @@ static void test_SHLWAPI_214(void)
 
 START_TEST(clist)
 {
 
 START_TEST(clist)
 {
-  InitFunctionPtrs();
+  if(!InitFunctionPtrs())
+    return;
 
   test_CList();
 
 
   test_CList();
 
index 98a8c6d..cf9be96 100755 (executable)
@@ -40,7 +40,7 @@ static BOOL (WINAPI *pSHLWAPI_269)(LPCSTR, CLSID *) = 0;
 static DWORD (WINAPI *pSHLWAPI_23)(REFGUID, LPSTR, INT) = 0;
 
 /* GUIDs to test */
 static DWORD (WINAPI *pSHLWAPI_23)(REFGUID, LPSTR, INT) = 0;
 
 /* GUIDs to test */
-const GUID * TEST_guids[] = {
+static const GUID * TEST_guids[] = {
   &CLSID_ShellDesktop,
   &CLSID_ShellLink,
   &CATID_BrowsableShellExt,
   &CLSID_ShellDesktop,
   &CLSID_ShellLink,
   &CATID_BrowsableShellExt,
@@ -96,7 +96,7 @@ const GUID * TEST_guids[] = {
   NULL
 };
 
   NULL
 };
 
-DEFINE_GUID(IID_Endianess, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B,
+DEFINE_GUID(IID_Endianness, 0x01020304, 0x0506, 0x0708, 0x09, 0x0A, 0x0B,
             0x0C, 0x0D, 0x0E, 0x0F, 0x0A);
 
 static void test_ClassIDs(void)
             0x0C, 0x0D, 0x0E, 0x0F, 0x0A);
 
 static void test_ClassIDs(void)
@@ -128,26 +128,26 @@ static void test_ClassIDs(void)
     i++;
   }
 
     i++;
   }
 
-  /* Test endianess */
-  dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 256);
-  ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for IID_Endianess\n", dwLen);
+  /* Test endianness */
+  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 256);
+  ok(dwLen == (is_vista ? S_OK : 39), "wrong size %u for IID_Endianness\n", dwLen);
 
   ok(!strcmp(szBuff, "{01020304-0506-0708-090A-0B0C0D0E0F0A}"),
 
   ok(!strcmp(szBuff, "{01020304-0506-0708-090A-0B0C0D0E0F0A}"),
-     "Endianess Broken, got '%s'\n", szBuff);
+     "Endianness Broken, got '%s'\n", szBuff);
 
   /* test lengths */
   szBuff[0] = ':';
 
   /* test lengths */
   szBuff[0] = ':';
-  dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 0);
+  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 0);
   ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n");
   ok(szBuff[0] == ':', "wrote to buffer with no length\n");
 
   szBuff[0] = ':';
   ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n");
   ok(szBuff[0] == ':', "wrote to buffer with no length\n");
 
   szBuff[0] = ':';
-  dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 38);
+  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 38);
   ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n");
   ok(szBuff[0] == ':', "wrote to buffer with no length\n");
 
   szBuff[0] = ':';
   ok(dwLen == (is_vista ? E_FAIL : 0), "accepted bad length\n");
   ok(szBuff[0] == ':', "wrote to buffer with no length\n");
 
   szBuff[0] = ':';
-  dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39);
+  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 39);
   ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n");
   ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n");
 
   ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n");
   ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n");
 
@@ -156,7 +156,7 @@ static void test_ClassIDs(void)
   bRet = pSHLWAPI_269(szBuff, &guid);
   ok(bRet == FALSE, "accepted invalid string\n");
 
   bRet = pSHLWAPI_269(szBuff, &guid);
   ok(bRet == FALSE, "accepted invalid string\n");
 
-  dwLen = pSHLWAPI_23(&IID_Endianess, szBuff, 39);
+  dwLen = pSHLWAPI_23(&IID_Endianness, szBuff, 39);
   ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n");
   ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n");
 }
   ok(dwLen == (is_vista ? S_OK : 39), "rejected ok length\n");
   ok(szBuff[0] == '{', "Didn't write to buffer with ok length\n");
 }
@@ -185,6 +185,13 @@ static void test_CLSIDFromProgIDWrap(void)
 START_TEST(clsid)
 {
   hShlwapi = GetModuleHandleA("shlwapi.dll");
 START_TEST(clsid)
 {
   hShlwapi = GetModuleHandleA("shlwapi.dll");
+
+  /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
+  if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
+      win_skip("Too old shlwapi version\n");
+      return;
+  }
+
   pSHLWAPI_269 = (void*)GetProcAddress(hShlwapi, (LPSTR)269);
   pSHLWAPI_23 = (void*)GetProcAddress(hShlwapi, (LPSTR)23);
 
   pSHLWAPI_269 = (void*)GetProcAddress(hShlwapi, (LPSTR)269);
   pSHLWAPI_23 = (void*)GetProcAddress(hShlwapi, (LPSTR)23);
 
index 4a36b3a..f525d7c 100644 (file)
@@ -281,12 +281,15 @@ static void test_SHCreateStreamOnFileA(DWORD mode, DWORD stgm)
     ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
 
     if (stream) {
     ok(stream != NULL, "SHCreateStreamOnFileA: expected a valid IStream object, got NULL\n");
 
     if (stream) {
+        BOOL delret;
         test_IStream_invalid_operations(stream, mode);
 
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
 
         test_IStream_invalid_operations(stream, mode);
 
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileA: expected 0, got %d\n", refcount);
 
-        ok(DeleteFileA(test_file), "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n", test_file, GetLastError());
+        delret = DeleteFileA(test_file);
+        ok(delret, "SHCreateStreamOnFileA: could not delete file '%s', got error %d\n",
+           test_file, GetLastError());
     }
 }
 
     }
 }
 
@@ -388,14 +391,15 @@ static void test_SHCreateStreamOnFileW(DWORD mode, DWORD stgm)
     ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
 
     if (stream) {
     ok(stream != NULL, "SHCreateStreamOnFileW: expected a valid IStream object, got NULL\n");
 
     if (stream) {
+        BOOL delret;
         test_IStream_invalid_operations(stream, mode);
 
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
 
         test_IStream_invalid_operations(stream, mode);
 
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileW: expected 0, got %d\n", refcount);
 
-        ok(DeleteFileA(test_fileA),
-            "SHCreateStreamOnFileW: could not delete the test file, got error %d\n",
-            GetLastError());
+        delret = DeleteFileA(test_fileA);
+        ok(delret, "SHCreateStreamOnFileW: could not delete the test file, got error %d\n",
+           GetLastError());
     }
 }
 
     }
 }
 
@@ -409,6 +413,7 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
     WCHAR test_file[MAX_PATH];
     CHAR  test_fileA[MAX_PATH];
     static const CHAR testEx_txt[] = "\\testEx.txt";
     WCHAR test_file[MAX_PATH];
     CHAR  test_fileA[MAX_PATH];
     static const CHAR testEx_txt[] = "\\testEx.txt";
+    BOOL delret;
 
     trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm);
 
 
     trace("SHCreateStreamOnFileEx: testing mode %d, STGM flags %08x\n", mode, stgm);
 
@@ -489,9 +494,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
 
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
 
-        ok(DeleteFileA(test_fileA),
-            "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
-            GetLastError());
+        delret = DeleteFileA(test_fileA);
+        ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
+           GetLastError());
     }
 
     stream = NULL;
     }
 
     stream = NULL;
@@ -510,9 +515,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
 
         refcount = IStream_Release(stream);
         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
 
-        ok(DeleteFileA(test_fileA),
-            "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
-            GetLastError());
+        delret = DeleteFileA(test_fileA);
+        ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
+           GetLastError());
     }
 
     stream = NULL;
     }
 
     stream = NULL;
@@ -577,9 +582,9 @@ static void test_SHCreateStreamOnFileEx(DWORD mode, DWORD stgm)
         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
     }
 
         ok(refcount == 0, "SHCreateStreamOnFileEx: expected 0, got %d\n", refcount);
     }
 
-    ok(DeleteFileA(test_fileA),
-        "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
-        GetLastError());
+    delret = DeleteFileA(test_fileA);
+    ok(delret, "SHCreateStreamOnFileEx: could not delete the test file, got error %d\n",
+       GetLastError());
 }
 
 
 }
 
 
index bf61418..1229ae2 100755 (executable)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 
 #define COBJMACROS
 #include <stdio.h>
 
 #define COBJMACROS
+#define CONST_VTABLE
 #include "wine/test.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "wine/test.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "shlwapi.h"
 #include "docobj.h"
 #include "shobjidl.h"
 #include "shlwapi.h"
 #include "docobj.h"
 #include "shobjidl.h"
+#include "shlobj.h"
 
 /* Function ptrs for ordinal calls */
 static HMODULE hShlwapi;
 static BOOL is_win2k_and_lower;
 
 /* Function ptrs for ordinal calls */
 static HMODULE hShlwapi;
 static BOOL is_win2k_and_lower;
+static BOOL is_win9x;
 
 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
 
 static int (WINAPI *pSHSearchMapInt)(const int*,const int*,int,int);
 static HRESULT (WINAPI *pGetAcceptLanguagesA)(LPSTR,LPDWORD);
@@ -56,10 +59,22 @@ static BOOL   (WINAPI *pGUIDFromStringA)(LPSTR, CLSID *);
 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
 static HWND    (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
 static HRESULT (WINAPI *pIUnknown_QueryServiceExec)(IUnknown*, REFIID, const GUID*, DWORD, DWORD, VARIANT*, VARIANT*);
 static HRESULT (WINAPI *pIUnknown_ProfferService)(IUnknown*, REFGUID, IServiceProvider*, DWORD*);
 static HWND    (WINAPI *pSHCreateWorkerWindowA)(LONG, HWND, DWORD, DWORD, HMENU, LONG_PTR);
+static HRESULT (WINAPI *pSHIShellFolder_EnumObjects)(LPSHELLFOLDER, HWND, SHCONTF, IEnumIDList**);
+static DWORD   (WINAPI *pSHGetIniStringW)(LPCWSTR, LPCWSTR, LPWSTR, DWORD, LPCWSTR);
+static BOOL    (WINAPI *pSHSetIniStringW)(LPCWSTR, LPCWSTR, LPCWSTR, LPCWSTR);
+static HKEY    (WINAPI *pSHGetShellKey)(DWORD, LPCWSTR, BOOL);
+static HRESULT (WINAPI *pSKGetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void*, DWORD*);
+static HRESULT (WINAPI *pSKSetValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD, void*, DWORD);
+static HRESULT (WINAPI *pSKDeleteValueW)(DWORD, LPCWSTR, LPCWSTR);
+static HRESULT (WINAPI *pSKAllocValueW)(DWORD, LPCWSTR, LPCWSTR, DWORD*, void**, DWORD*);
+static HWND    (WINAPI *pSHSetParentHwnd)(HWND, HWND);
 
 static HMODULE hmlang;
 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
 
 
 static HMODULE hmlang;
 static HRESULT (WINAPI *pLcidToRfc1766A)(LCID, LPSTR, INT);
 
+static HMODULE hshell32;
+static HRESULT (WINAPI *pSHGetDesktopFolder)(IShellFolder**);
+
 static const CHAR ie_international[] = {
     'S','o','f','t','w','a','r','e','\\',
     'M','i','c','r','o','s','o','f','t','\\',
 static const CHAR ie_international[] = {
     'S','o','f','t','w','a','r','e','\\',
     'M','i','c','r','o','s','o','f','t','\\',
@@ -68,6 +83,13 @@ static const CHAR ie_international[] = {
 static const CHAR acceptlanguage[] = {
     'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
 
 static const CHAR acceptlanguage[] = {
     'A','c','c','e','p','t','L','a','n','g','u','a','g','e',0};
 
+static int strcmp_wa(LPCWSTR strw, const char *stra)
+{
+    CHAR buf[512];
+    WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
+    return lstrcmpA(stra, buf);
+}
+
 typedef struct {
     int id;
     const void *args[5];
 typedef struct {
     int id;
     const void *args[5];
@@ -335,7 +357,7 @@ static void test_GetAcceptLanguagesA(void)
     buffer[maxlen] = 0;
     hr = pGetAcceptLanguagesA( buffer, &len);
     /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
     buffer[maxlen] = 0;
     hr = pGetAcceptLanguagesA( buffer, &len);
     /* When the buffer is too small, win7_32 and w2k8_64 and above fail with
-       HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions suceed
+       HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), other versions succeed
        and return a partial 0 terminated result while other versions
        fail with E_INVALIDARG and return a partial unterminated result */
     ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
        and return a partial 0 terminated result while other versions
        fail with E_INVALIDARG and return a partial unterminated result */
     ok( (((hr == S_OK) || (hr == E_INVALIDARG)) && !memcmp(buffer, language, len)) ||
@@ -576,6 +598,7 @@ static void test_GetShellSecurityDescriptor(void)
     };
     SECURITY_DESCRIPTOR* psd;
     SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
     };
     SECURITY_DESCRIPTOR* psd;
     SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int);
+    void *pChrCmpIW = GetProcAddress(hShlwapi, "ChrCmpIW");
 
     pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
 
 
     pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475);
 
@@ -585,12 +608,18 @@ static void test_GetShellSecurityDescriptor(void)
         return;
     }
 
         return;
     }
 
+    if(pChrCmpIW && pChrCmpIW == pGetShellSecurityDescriptor) /* win2k */
+    {
+        win_skip("Skipping for GetShellSecurityDescriptor, same ordinal used for ChrCmpIW\n");
+        return;
+    }
+
     psd = pGetShellSecurityDescriptor(NULL, 2);
     ok(psd==NULL ||
        broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
        "GetShellSecurityDescriptor should fail\n");
     psd = pGetShellSecurityDescriptor(rgsup, 0);
     psd = pGetShellSecurityDescriptor(NULL, 2);
     ok(psd==NULL ||
        broken(psd==INVALID_HANDLE_VALUE), /* IE5 */
        "GetShellSecurityDescriptor should fail\n");
     psd = pGetShellSecurityDescriptor(rgsup, 0);
-    ok(psd==NULL, "GetShellSecurityDescriptor should fail\n");
+    ok(psd==NULL, "GetShellSecurityDescriptor should fail, got %p\n", psd);
 
     SetLastError(0xdeadbeef);
     psd = pGetShellSecurityDescriptor(rgsup, 2);
 
     SetLastError(0xdeadbeef);
     psd = pGetShellSecurityDescriptor(rgsup, 2);
@@ -600,7 +629,7 @@ static void test_GetShellSecurityDescriptor(void)
         win_skip("GetShellSecurityDescriptor is not implemented\n");
         return;
     }
         win_skip("GetShellSecurityDescriptor is not implemented\n");
         return;
     }
-    if (psd==INVALID_HANDLE_VALUE)
+    if (psd == INVALID_HANDLE_VALUE)
     {
         win_skip("GetShellSecurityDescriptor is broken on IE5\n");
         return;
     {
         win_skip("GetShellSecurityDescriptor is broken on IE5\n");
         return;
@@ -608,19 +637,19 @@ static void test_GetShellSecurityDescriptor(void)
     ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
     if (psd!=NULL)
     {
     ok(psd!=NULL, "GetShellSecurityDescriptor failed\n");
     if (psd!=NULL)
     {
-        BOOL bHasDacl = FALSE, bDefaulted;
+        BOOL bHasDacl = FALSE, bDefaulted, ret;
         PACL pAcl;
         DWORD dwRev;
         SECURITY_DESCRIPTOR_CONTROL control;
 
         ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
 
         PACL pAcl;
         DWORD dwRev;
         SECURITY_DESCRIPTOR_CONTROL control;
 
         ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n");
 
-        ok(GetSecurityDescriptorControl(psd, &control, &dwRev),
-                "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
+        ret = GetSecurityDescriptorControl(psd, &control, &dwRev);
+        ok(ret, "GetSecurityDescriptorControl failed with error %u\n", GetLastError());
         ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
 
         ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n");
 
-        ok(GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted), 
-            "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
+        ret = GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted);
+        ok(ret, "GetSecurityDescriptorDacl failed with error %u\n", GetLastError());
 
         ok(bHasDacl, "SD has no DACL\n");
         if (bHasDacl)
 
         ok(bHasDacl, "SD has no DACL\n");
         if (bHasDacl)
@@ -634,28 +663,31 @@ static void test_GetShellSecurityDescriptor(void)
 
                 ok(IsValidAcl(pAcl), "DACL is not valid\n");
 
 
                 ok(IsValidAcl(pAcl), "DACL is not valid\n");
 
-                ok(GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation),
-                        "GetAclInformation failed with error %u\n", GetLastError());
+                ret = GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation);
+                ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
 
                 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
                 if (asiSize.AceCount == 3)
                 {
                     ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
 
 
                 ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount);
                 if (asiSize.AceCount == 3)
                 {
                     ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */
 
-                    ok(GetAce(pAcl, 0, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
+                    ret = GetAce(pAcl, 0, (LPVOID*)&paaa);
+                    ok(ret, "GetAce failed with error %u\n", GetLastError());
                     ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, 
                             "Invalid ACE type %d\n", paaa->Header.AceType); 
                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
                     ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
 
                     ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, 
                             "Invalid ACE type %d\n", paaa->Header.AceType); 
                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
                     ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask);
 
-                    ok(GetAce(pAcl, 1, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
+                    ret = GetAce(pAcl, 1, (LPVOID*)&paaa);
+                    ok(ret, "GetAce failed with error %u\n", GetLastError());
                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
                             "Invalid ACE type %d\n", paaa->Header.AceType); 
                     /* first one of two ACEs generated from inheritable entry - without inheritance */
                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
                     ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
 
                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
                             "Invalid ACE type %d\n", paaa->Header.AceType); 
                     /* first one of two ACEs generated from inheritable entry - without inheritance */
                     ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags);
                     ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask);
 
-                    ok(GetAce(pAcl, 2, (LPVOID*)&paaa), "GetAce failed with error %u\n", GetLastError());
+                    ret = GetAce(pAcl, 2, (LPVOID*)&paaa);
+                    ok(ret, "GetAce failed with error %u\n", GetLastError());
                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
                             "Invalid ACE type %d\n", paaa->Header.AceType); 
                     /* second ACE - with inheritance */
                     ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, 
                             "Invalid ACE type %d\n", paaa->Header.AceType); 
                     /* second ACE - with inheritance */
@@ -719,22 +751,32 @@ static void test_SHPackDispParams(void)
 
 typedef struct _disp
 {
 
 typedef struct _disp
 {
-    const IDispatchVtbl *vtbl;
+    IDispatch IDispatch_iface;
     LONG   refCount;
 } Disp;
 
     LONG   refCount;
 } Disp;
 
+static inline Disp *impl_from_IDispatch(IDispatch *iface)
+{
+    return CONTAINING_RECORD(iface, Disp, IDispatch_iface);
+}
+
 typedef struct _contain
 {
 typedef struct _contain
 {
-    const IConnectionPointContainerVtbl *vtbl;
+    IConnectionPointContainer IConnectionPointContainer_iface;
     LONG   refCount;
 
     UINT  ptCount;
     IConnectionPoint **pt;
 } Contain;
 
     LONG   refCount;
 
     UINT  ptCount;
     IConnectionPoint **pt;
 } Contain;
 
+static inline Contain *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
+{
+    return CONTAINING_RECORD(iface, Contain, IConnectionPointContainer_iface);
+}
+
 typedef struct _cntptn
 {
 typedef struct _cntptn
 {
-    const IConnectionPointVtbl *vtbl;
+    IConnectionPoint IConnectionPoint_iface;
     LONG refCount;
 
     Contain *container;
     LONG refCount;
 
     Contain *container;
@@ -743,24 +785,39 @@ typedef struct _cntptn
     IUnknown **sink;
 } ConPt;
 
     IUnknown **sink;
 } ConPt;
 
+static inline ConPt *impl_from_IConnectionPoint(IConnectionPoint *iface)
+{
+    return CONTAINING_RECORD(iface, ConPt, IConnectionPoint_iface);
+}
+
 typedef struct _enum
 {
 typedef struct _enum
 {
-    const IEnumConnectionsVtbl *vtbl;
+    IEnumConnections IEnumConnections_iface;
     LONG   refCount;
 
     UINT idx;
     ConPt *pt;
 } EnumCon;
 
     LONG   refCount;
 
     UINT idx;
     ConPt *pt;
 } EnumCon;
 
+static inline EnumCon *impl_from_IEnumConnections(IEnumConnections *iface)
+{
+    return CONTAINING_RECORD(iface, EnumCon, IEnumConnections_iface);
+}
+
 typedef struct _enumpt
 {
 typedef struct _enumpt
 {
-    const IEnumConnectionPointsVtbl *vtbl;
+    IEnumConnectionPoints IEnumConnectionPoints_iface;
     LONG   refCount;
 
     int idx;
     Contain *container;
 } EnumPt;
 
     LONG   refCount;
 
     int idx;
     Contain *container;
 } EnumPt;
 
+static inline EnumPt *impl_from_IEnumConnectionPoints(IEnumConnectionPoints *iface)
+{
+    return CONTAINING_RECORD(iface, EnumPt, IEnumConnectionPoints_iface);
+}
+
 
 static HRESULT WINAPI Disp_QueryInterface(
         IDispatch* This,
 
 static HRESULT WINAPI Disp_QueryInterface(
         IDispatch* This,
@@ -776,7 +833,7 @@ static HRESULT WINAPI Disp_QueryInterface(
 
     if (*ppvObject)
     {
 
     if (*ppvObject)
     {
-        IUnknown_AddRef(This);
+        IDispatch_AddRef(This);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -786,13 +843,13 @@ static HRESULT WINAPI Disp_QueryInterface(
 
 static ULONG WINAPI Disp_AddRef(IDispatch* This)
 {
 
 static ULONG WINAPI Disp_AddRef(IDispatch* This)
 {
-    Disp *iface = (Disp*)This;
+    Disp *iface = impl_from_IDispatch(This);
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Disp_Release(IDispatch* This)
 {
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Disp_Release(IDispatch* This)
 {
-    Disp *iface = (Disp*)This;
+    Disp *iface = impl_from_IDispatch(This);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
@@ -891,7 +948,7 @@ static HRESULT WINAPI Enum_QueryInterface(
 
     if (*ppvObject)
     {
 
     if (*ppvObject)
     {
-        IUnknown_AddRef(This);
+        IEnumConnections_AddRef(This);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -901,13 +958,13 @@ static HRESULT WINAPI Enum_QueryInterface(
 
 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
 {
 
 static ULONG WINAPI Enum_AddRef(IEnumConnections* This)
 {
-    EnumCon *iface = (EnumCon*)This;
+    EnumCon *iface = impl_from_IEnumConnections(This);
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Enum_Release(IEnumConnections* This)
 {
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Enum_Release(IEnumConnections* This)
 {
-    EnumCon *iface = (EnumCon*)This;
+    EnumCon *iface = impl_from_IEnumConnections(This);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
@@ -922,7 +979,7 @@ static HRESULT WINAPI Enum_Next(
         LPCONNECTDATA rgcd,
         ULONG *pcFetched)
 {
         LPCONNECTDATA rgcd,
         ULONG *pcFetched)
 {
-    EnumCon *iface = (EnumCon*)This;
+    EnumCon *iface = impl_from_IEnumConnections(This);
 
     if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
     {
 
     if (cConnections > 0 && iface->idx < iface->pt->sinkCount)
     {
@@ -983,7 +1040,7 @@ static HRESULT WINAPI ConPt_QueryInterface(
 
     if (*ppvObject)
     {
 
     if (*ppvObject)
     {
-        IUnknown_AddRef(This);
+        IConnectionPoint_AddRef(This);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -994,14 +1051,14 @@ static HRESULT WINAPI ConPt_QueryInterface(
 static ULONG WINAPI ConPt_AddRef(
         IConnectionPoint* This)
 {
 static ULONG WINAPI ConPt_AddRef(
         IConnectionPoint* This)
 {
-    ConPt *iface = (ConPt*)This;
+    ConPt *iface = impl_from_IConnectionPoint(This);
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI ConPt_Release(
         IConnectionPoint* This)
 {
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI ConPt_Release(
         IConnectionPoint* This)
 {
-    ConPt *iface = (ConPt*)This;
+    ConPt *iface = impl_from_IConnectionPoint(This);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
@@ -1027,7 +1084,7 @@ static HRESULT WINAPI ConPt_GetConnectionInterface(
         IID *pIID)
 {
     static int i = 0;
         IID *pIID)
 {
     static int i = 0;
-    ConPt *iface = (ConPt*)This;
+    ConPt *iface = impl_from_IConnectionPoint(This);
     if (i==0)
     {
         i++;
     if (i==0)
     {
         i++;
@@ -1042,9 +1099,9 @@ static HRESULT WINAPI ConPt_GetConnectionPointContainer(
         IConnectionPoint* This,
         IConnectionPointContainer **ppCPC)
 {
         IConnectionPoint* This,
         IConnectionPointContainer **ppCPC)
 {
-    ConPt *iface = (ConPt*)This;
+    ConPt *iface = impl_from_IConnectionPoint(This);
 
 
-    *ppCPC = (IConnectionPointContainer*)iface->container;
+    *ppCPC = &iface->container->IConnectionPointContainer_iface;
     return S_OK;
 }
 
     return S_OK;
 }
 
@@ -1053,7 +1110,7 @@ static HRESULT WINAPI ConPt_Advise(
         IUnknown *pUnkSink,
         DWORD *pdwCookie)
 {
         IUnknown *pUnkSink,
         DWORD *pdwCookie)
 {
-    ConPt *iface = (ConPt*)This;
+    ConPt *iface = impl_from_IConnectionPoint(This);
 
     if (iface->sinkCount == 0)
         iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
 
     if (iface->sinkCount == 0)
         iface->sink = HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
@@ -1070,7 +1127,7 @@ static HRESULT WINAPI ConPt_Unadvise(
         IConnectionPoint* This,
         DWORD dwCookie)
 {
         IConnectionPoint* This,
         DWORD dwCookie)
 {
-    ConPt *iface = (ConPt*)This;
+    ConPt *iface = impl_from_IConnectionPoint(This);
 
     if (dwCookie > iface->sinkCount)
         return E_FAIL;
 
     if (dwCookie > iface->sinkCount)
         return E_FAIL;
@@ -1089,11 +1146,11 @@ static HRESULT WINAPI ConPt_EnumConnections(
     EnumCon *ec;
 
     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
     EnumCon *ec;
 
     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumCon));
-    ec->vtbl = &enum_vtbl;
+    ec->IEnumConnections_iface.lpVtbl = &enum_vtbl;
     ec->refCount = 1;
     ec->refCount = 1;
-    ec->pt = (ConPt*)This;
+    ec->pt = impl_from_IConnectionPoint(This);
     ec->idx = 0;
     ec->idx = 0;
-    *ppEnum = (IEnumConnections*)ec;
+    *ppEnum = &ec->IEnumConnections_iface;
 
     return S_OK;
 }
 
     return S_OK;
 }
@@ -1124,7 +1181,7 @@ static HRESULT WINAPI EnumPt_QueryInterface(
 
     if (*ppvObject)
     {
 
     if (*ppvObject)
     {
-        IUnknown_AddRef(This);
+        IEnumConnectionPoints_AddRef(This);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -1134,13 +1191,13 @@ static HRESULT WINAPI EnumPt_QueryInterface(
 
 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
 {
 
 static ULONG WINAPI EnumPt_AddRef(IEnumConnectionPoints* This)
 {
-    EnumPt *iface = (EnumPt*)This;
+    EnumPt *iface = impl_from_IEnumConnectionPoints(This);
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
 {
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI EnumPt_Release(IEnumConnectionPoints* This)
 {
-    EnumPt *iface = (EnumPt*)This;
+    EnumPt *iface = impl_from_IEnumConnectionPoints(This);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
@@ -1155,12 +1212,12 @@ static HRESULT WINAPI EnumPt_Next(
         IConnectionPoint **rgcd,
         ULONG *pcFetched)
 {
         IConnectionPoint **rgcd,
         ULONG *pcFetched)
 {
-    EnumPt *iface = (EnumPt*)This;
+    EnumPt *iface = impl_from_IEnumConnectionPoints(This);
 
     if (cConnections > 0 && iface->idx < iface->container->ptCount)
     {
         *rgcd = iface->container->pt[iface->idx];
 
     if (cConnections > 0 && iface->idx < iface->container->ptCount)
     {
         *rgcd = iface->container->pt[iface->idx];
-        IUnknown_AddRef(iface->container->pt[iface->idx]);
+        IConnectionPoint_AddRef(iface->container->pt[iface->idx]);
         if (pcFetched)
             *pcFetched = 1;
         iface->idx++;
         if (pcFetched)
             *pcFetched = 1;
         iface->idx++;
@@ -1215,7 +1272,7 @@ static HRESULT WINAPI Contain_QueryInterface(
 
     if (*ppvObject)
     {
 
     if (*ppvObject)
     {
-        IUnknown_AddRef(This);
+        IConnectionPointContainer_AddRef(This);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -1226,14 +1283,14 @@ static HRESULT WINAPI Contain_QueryInterface(
 static ULONG WINAPI Contain_AddRef(
         IConnectionPointContainer* This)
 {
 static ULONG WINAPI Contain_AddRef(
         IConnectionPointContainer* This)
 {
-    Contain *iface = (Contain*)This;
+    Contain *iface = impl_from_IConnectionPointContainer(This);
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Contain_Release(
         IConnectionPointContainer* This)
 {
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Contain_Release(
         IConnectionPointContainer* This)
 {
-    Contain *iface = (Contain*)This;
+    Contain *iface = impl_from_IConnectionPointContainer(This);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
@@ -1243,7 +1300,7 @@ static ULONG WINAPI Contain_Release(
         {
             int i;
             for (i = 0; i < iface->ptCount; i++)
         {
             int i;
             for (i = 0; i < iface->ptCount; i++)
-                IUnknown_Release(iface->pt[i]);
+                IConnectionPoint_Release(iface->pt[i]);
             HeapFree(GetProcessHeap(),0,iface->pt);
         }
         HeapFree(GetProcessHeap(),0,This);
             HeapFree(GetProcessHeap(),0,iface->pt);
         }
         HeapFree(GetProcessHeap(),0,This);
@@ -1258,11 +1315,11 @@ static HRESULT WINAPI Contain_EnumConnectionPoints(
     EnumPt *ec;
 
     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
     EnumPt *ec;
 
     ec = HeapAlloc(GetProcessHeap(),0,sizeof(EnumPt));
-    ec->vtbl = &enumpt_vtbl;
+    ec->IEnumConnectionPoints_iface.lpVtbl = &enumpt_vtbl;
     ec->refCount = 1;
     ec->idx= 0;
     ec->refCount = 1;
     ec->idx= 0;
-    ec->container = (Contain*)This;
-    *ppEnum = (IEnumConnectionPoints*)ec;
+    ec->container = impl_from_IConnectionPointContainer(This);
+    *ppEnum = &ec->IEnumConnectionPoints_iface;
 
     return S_OK;
 }
 
     return S_OK;
 }
@@ -1272,13 +1329,13 @@ static HRESULT WINAPI Contain_FindConnectionPoint(
         REFIID riid,
         IConnectionPoint **ppCP)
 {
         REFIID riid,
         IConnectionPoint **ppCP)
 {
-    Contain *iface = (Contain*)This;
+    Contain *iface = impl_from_IConnectionPointContainer(This);
     ConPt *pt;
 
     if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
     {
         pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
     ConPt *pt;
 
     if (!IsEqualIID(riid, &IID_NULL) || iface->ptCount ==0)
     {
         pt = HeapAlloc(GetProcessHeap(),0,sizeof(ConPt));
-        pt->vtbl = &point_vtbl;
+        pt->IConnectionPoint_iface.lpVtbl = &point_vtbl;
         pt->refCount = 1;
         pt->sinkCount = 0;
         pt->sink = NULL;
         pt->refCount = 1;
         pt->sinkCount = 0;
         pt->sink = NULL;
@@ -1289,10 +1346,10 @@ static HRESULT WINAPI Contain_FindConnectionPoint(
             iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
         else
             iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
             iface->pt =HeapAlloc(GetProcessHeap(),0,sizeof(IUnknown*));
         else
             iface->pt = HeapReAlloc(GetProcessHeap(),0,iface->pt,sizeof(IUnknown*)*(iface->ptCount+1));
-        iface->pt[iface->ptCount] = (IConnectionPoint*)pt;
+        iface->pt[iface->ptCount] = &pt->IConnectionPoint_iface;
         iface->ptCount++;
 
         iface->ptCount++;
 
-        *ppCP = (IConnectionPoint*)pt;
+        *ppCP = &pt->IConnectionPoint_iface;
     }
     else
     {
     }
     else
     {
@@ -1330,13 +1387,13 @@ static void test_IConnectionPoint(void)
     }
 
     container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
     }
 
     container = HeapAlloc(GetProcessHeap(),0,sizeof(Contain));
-    container->vtbl = &contain_vtbl;
+    container->IConnectionPointContainer_iface.lpVtbl = &contain_vtbl;
     container->refCount = 1;
     container->ptCount = 0;
     container->pt = NULL;
 
     dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
     container->refCount = 1;
     container->ptCount = 0;
     container->pt = NULL;
 
     dispatch = HeapAlloc(GetProcessHeap(),0,sizeof(Disp));
-    dispatch->vtbl = &disp_vtbl;
+    dispatch->IDispatch_iface.lpVtbl = &disp_vtbl;
     dispatch->refCount = 1;
 
     rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
     dispatch->refCount = 1;
 
     rc = pConnectToConnectionPoint((IUnknown*)dispatch, &IID_NULL, TRUE, (IUnknown*)container, &cookie, &point);
@@ -1374,11 +1431,16 @@ static void test_IConnectionPoint(void)
 
 typedef struct _propbag
 {
 
 typedef struct _propbag
 {
-    const IPropertyBagVtbl *vtbl;
+    IPropertyBag IPropertyBag_iface;
     LONG   refCount;
 
 } PropBag;
 
     LONG   refCount;
 
 } PropBag;
 
+static inline PropBag *impl_from_IPropertyBag(IPropertyBag *iface)
+{
+    return CONTAINING_RECORD(iface, PropBag, IPropertyBag_iface);
+}
+
 
 static HRESULT WINAPI Prop_QueryInterface(
         IPropertyBag* This,
 
 static HRESULT WINAPI Prop_QueryInterface(
         IPropertyBag* This,
@@ -1394,7 +1456,7 @@ static HRESULT WINAPI Prop_QueryInterface(
 
     if (*ppvObject)
     {
 
     if (*ppvObject)
     {
-        IUnknown_AddRef(This);
+        IPropertyBag_AddRef(This);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -1405,14 +1467,14 @@ static HRESULT WINAPI Prop_QueryInterface(
 static ULONG WINAPI Prop_AddRef(
         IPropertyBag* This)
 {
 static ULONG WINAPI Prop_AddRef(
         IPropertyBag* This)
 {
-    PropBag *iface = (PropBag*)This;
+    PropBag *iface = impl_from_IPropertyBag(This);
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Prop_Release(
         IPropertyBag* This)
 {
     return InterlockedIncrement(&iface->refCount);
 }
 
 static ULONG WINAPI Prop_Release(
         IPropertyBag* This)
 {
-    PropBag *iface = (PropBag*)This;
+    PropBag *iface = impl_from_IPropertyBag(This);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
     ULONG ret;
 
     ret = InterlockedDecrement(&iface->refCount);
@@ -1465,19 +1527,18 @@ static void test_SHPropertyBag_ReadLONG(void)
 
     pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
     pb->refCount = 1;
 
     pb = HeapAlloc(GetProcessHeap(),0,sizeof(PropBag));
     pb->refCount = 1;
-    pb->vtbl = &prop_vtbl;
+    pb->IPropertyBag_iface.lpVtbl = &prop_vtbl;
 
     out = 0xfeedface;
     rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
     ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
     ok(out == 0xfeedface, "value should not have changed\n");
 
     out = 0xfeedface;
     rc = pSHPropertyBag_ReadLONG(NULL, szName1, &out);
     ok(rc == E_INVALIDARG || broken(rc == 0), "incorrect return %x\n",rc);
     ok(out == 0xfeedface, "value should not have changed\n");
-    rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, NULL, &out);
+    rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, NULL, &out);
     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
     ok(out == 0xfeedface, "value should not have changed\n");
     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
     ok(out == 0xfeedface, "value should not have changed\n");
-    rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, NULL);
+    rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, NULL);
     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
     ok(rc == E_INVALIDARG || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
-    ok(out == 0xfeedface, "value should not have changed\n");
-    rc = pSHPropertyBag_ReadLONG((IPropertyBag*)pb, szName1, &out);
+    rc = pSHPropertyBag_ReadLONG(&pb->IPropertyBag_iface, szName1, &out);
     ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
     ok(out == 0xfeedface  || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
     IUnknown_Release((IUnknown*)pb);
     ok(rc == DISP_E_BADVARTYPE || broken(rc == 0) || broken(rc == 1), "incorrect return %x\n",rc);
     ok(out == 0xfeedface  || broken(out == 0xfeedfa00), "value should not have changed %x\n",out);
     IUnknown_Release((IUnknown*)pb);
@@ -1577,7 +1638,7 @@ static void test_SHFormatDateTimeA(void)
 if (0)
 {
     /* crashes on native */
 if (0)
 {
     /* crashes on native */
-    ret = pSHFormatDateTimeA(NULL, NULL, NULL, 0);
+    pSHFormatDateTimeA(NULL, NULL, NULL, 0);
 }
 
     GetLocalTime(&st);
 }
 
     GetLocalTime(&st);
@@ -1589,7 +1650,8 @@ if (0)
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
     ok(ret == 0, "got %d\n", ret);
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeA(&filetime, NULL, NULL, 0);
     ok(ret == 0, "got %d\n", ret);
-    ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
+    ok(GetLastError() == 0xdeadbeef || broken(GetLastError() == ERROR_SUCCESS /* Win7 */),
+        "expected 0xdeadbeef, got %d\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     buff[0] = 'a'; buff[1] = 0;
 
     SetLastError(0xdeadbeef);
     buff[0] = 'a'; buff[1] = 0;
@@ -1670,24 +1732,30 @@ if (0)
     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
     ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
     ok(ret == lstrlenA(buff)+1, "got %d, length %d\n", ret, lstrlenA(buff)+1);
-    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
-    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
-    strcat(buff2, ", ");
     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
     ret = GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3));
     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
-    strcat(buff2, buff3);
-    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+    ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
+       "expected (%s), got (%s) for time part\n",
+       buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    buff[lstrlenA(buff2)] = '\0';
+    ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
+       buff2, buff);
 
     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
 
     flags = FDTF_NOAUTOREADINGORDER | FDTF_LONGDATE | FDTF_LONGTIME;
     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
     ok(ret == lstrlenA(buff)+1, "got %d\n", ret);
-    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
-    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
-    strcat(buff2, ", ");
     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
     ret = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3));
     ok(ret == lstrlenA(buff3)+1, "got %d\n", ret);
-    strcat(buff2, buff3);
-    ok(lstrcmpA(buff, buff2) == 0, "expected (%s), got (%s)\n", buff2, buff);
+    ok(lstrcmpA(buff3, buff + lstrlenA(buff) - lstrlenA(buff3)) == 0,
+       "expected (%s), got (%s) for time part\n",
+       buff3, buff + lstrlenA(buff) - lstrlenA(buff3));
+    ret = GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2));
+    ok(ret == lstrlenA(buff2)+1, "got %d\n", ret);
+    buff[lstrlenA(buff2)] = '\0';
+    ok(lstrcmpA(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
+       buff2, buff);
 
     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
 
     flags = FDTF_NOAUTOREADINGORDER | FDTF_SHORTDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeA(&filetime, &flags, buff, sizeof(buff));
@@ -1715,12 +1783,12 @@ if (0)
 static void test_SHFormatDateTimeW(void)
 {
     FILETIME UNALIGNED filetime;
 static void test_SHFormatDateTimeW(void)
 {
     FILETIME UNALIGNED filetime;
-    WCHAR buff[100], buff2[100], buff3[100];
+    WCHAR buff[100], buff2[100], buff3[100], *p1, *p2;
     SYSTEMTIME st;
     DWORD flags;
     INT ret;
     static const WCHAR spaceW[] = {' ',0};
     SYSTEMTIME st;
     DWORD flags;
     INT ret;
     static const WCHAR spaceW[] = {' ',0};
-    static const WCHAR commaW[] = {',',' ',0};
+#define UNICODE_LTR_MARK 0x200e
 
     if(!pSHFormatDateTimeW)
     {
 
     if(!pSHFormatDateTimeW)
     {
@@ -1731,7 +1799,7 @@ static void test_SHFormatDateTimeW(void)
 if (0)
 {
     /* crashes on native */
 if (0)
 {
     /* crashes on native */
-    ret = pSHFormatDateTimeW(NULL, NULL, NULL, 0);
+    pSHFormatDateTimeW(NULL, NULL, NULL, 0);
 }
 
     GetLocalTime(&st);
 }
 
     GetLocalTime(&st);
@@ -1742,13 +1810,13 @@ if (0)
     /* no way to get required buffer length here */
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
     /* no way to get required buffer length here */
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeW(&filetime, NULL, NULL, 0);
-    ok(ret == 0, "got %d\n", ret);
+    ok(ret == 0, "expected 0, got %d\n", ret);
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     buff[0] = 'a'; buff[1] = 0;
     ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     buff[0] = 'a'; buff[1] = 0;
     ret = pSHFormatDateTimeW(&filetime, NULL, buff, 0);
-    ok(ret == 0, "got %d\n", ret);
+    ok(ret == 0, "expected 0, got %d\n", ret);
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
     ok(buff[0] == 'a', "expected same string\n");
 
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
     ok(buff[0] == 'a', "expected same string\n");
 
@@ -1756,20 +1824,23 @@ if (0)
     flags = FDTF_SHORTTIME | FDTF_LONGTIME;
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     flags = FDTF_SHORTTIME | FDTF_LONGTIME;
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
 
     flags = FDTF_SHORTDATE | FDTF_LONGDATE;
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
 
     flags = FDTF_SHORTDATE | FDTF_LONGDATE;
     SetLastError(0xdeadbeef);
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
 
     flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
     SetLastError(0xdeadbeef);
     buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(GetLastError() == 0xdeadbeef, "expected 0xdeadbeef, got %d\n", GetLastError());
 
     flags = FDTF_SHORTDATE | FDTF_LTRDATE | FDTF_RTLDATE;
     SetLastError(0xdeadbeef);
     buff[0] = 0; /* NT4 doesn't clear the buffer on failure */
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ok(GetLastError() == 0xdeadbeef ||
         broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
         "expected 0xdeadbeef, got %d\n", GetLastError());
     ok(GetLastError() == 0xdeadbeef ||
         broken(GetLastError() == ERROR_INVALID_FLAGS), /* Win9x/WinMe/NT4 */
         "expected 0xdeadbeef, got %d\n", GetLastError());
@@ -1777,7 +1848,8 @@ if (0)
     /* now check returned strings */
     flags = FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     /* now check returned strings */
     flags = FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     SetLastError(0xdeadbeef);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
     SetLastError(0xdeadbeef);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     if (ret == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
@@ -1785,88 +1857,125 @@ if (0)
         win_skip("Needed W-functions are not implemented\n");
         return;
     }
         win_skip("Needed W-functions are not implemented\n");
         return;
     }
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     flags = FDTF_LONGTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     flags = FDTF_LONGTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     /* both time flags */
     flags = FDTF_LONGTIME | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     /* both time flags */
     flags = FDTF_LONGTIME | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
 
     flags = FDTF_SHORTDATE;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(lstrcmpW(buff, buff2) == 0, "expected equal string\n");
 
     flags = FDTF_SHORTDATE;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     flags = FDTF_LONGDATE;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     flags = FDTF_LONGDATE;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     /* both date flags */
     flags = FDTF_LONGDATE | FDTF_SHORTDATE;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     /* both date flags */
     flags = FDTF_LONGDATE | FDTF_SHORTDATE;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     /* various combinations of date/time flags */
     flags = FDTF_LONGDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     /* various combinations of date/time flags */
     flags = FDTF_LONGDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d, length %d\n", ret, lstrlenW(buff)+1);
-    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
-    lstrcatW(buff2, commaW);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
-    lstrcatW(buff2, buff3);
-    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+    ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
+    ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
+       "expected (%s), got (%s) for time part\n",
+       wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
+    p1 = buff;
+    p2 = buff2;
+    while (*p2 != '\0')
+    {
+        while (*p1 == UNICODE_LTR_MARK)
+            p1++;
+        while (*p2 == UNICODE_LTR_MARK)
+            p2++;
+        p1++;
+        p2++;
+    }
+    *p1 = '\0';
+    ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
+       wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
 
     flags = FDTF_LONGDATE | FDTF_LONGTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
 
     flags = FDTF_LONGDATE | FDTF_LONGTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
-    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
-    lstrcatW(buff2, commaW);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
-    lstrcatW(buff2, buff3);
-    ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
+    ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
+    ok(lstrcmpW(buff3, buff + lstrlenW(buff) - lstrlenW(buff3)) == 0,
+       "expected (%s), got (%s) for time part\n",
+       wine_dbgstr_w(buff3), wine_dbgstr_w(buff + lstrlenW(buff) - lstrlenW(buff3)));
+    ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
+    p1 = buff;
+    p2 = buff2;
+    while (*p2 != '\0')
+    {
+        while (*p1 == UNICODE_LTR_MARK)
+            p1++;
+        while (*p2 == UNICODE_LTR_MARK)
+            p2++;
+        p1++;
+        p2++;
+    }
+    *p1 = '\0';
+    ok(lstrcmpW(buff2, buff) == 0, "expected (%s) got (%s) for date part\n",
+       wine_dbgstr_w(buff2), wine_dbgstr_w(buff));
 
     flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
 
     flags = FDTF_SHORTDATE | FDTF_SHORTTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     lstrcatW(buff2, spaceW);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
     lstrcatW(buff2, spaceW);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
     lstrcatW(buff2, buff3);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     flags = FDTF_SHORTDATE | FDTF_LONGTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
     lstrcatW(buff2, buff3);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 
     flags = FDTF_SHORTDATE | FDTF_LONGTIME;
     ret = pSHFormatDateTimeW(&filetime, &flags, buff, sizeof(buff)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff)+1 || ret == lstrlenW(buff),
+       "expected %d or %d, got %d\n", lstrlenW(buff)+1, lstrlenW(buff), ret);
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, buff2, sizeof(buff2)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff2)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff2)+1, "expected %d, got %d\n", lstrlenW(buff2)+1, ret);
     lstrcatW(buff2, spaceW);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
     lstrcatW(buff2, spaceW);
     ret = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, buff3, sizeof(buff3)/sizeof(WCHAR));
-    ok(ret == lstrlenW(buff3)+1, "got %d\n", ret);
+    ok(ret == lstrlenW(buff3)+1, "expected %d, got %d\n", lstrlenW(buff3)+1, ret);
     lstrcatW(buff2, buff3);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 }
     lstrcatW(buff2, buff3);
     ok(lstrcmpW(buff, buff2) == 0, "expected equal strings\n");
 }
@@ -1895,6 +2004,7 @@ static void test_SHGetObjectCompatFlags(void)
     };
 
     static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
     };
 
     static const char compat_path[] = "Software\\Microsoft\\Windows\\CurrentVersion\\ShellCompatibility\\Objects";
+    void *pColorAdjustLuma = GetProcAddress(hShlwapi, "ColorAdjustLuma");
     CHAR keyA[39]; /* {CLSID} */
     HKEY root;
     DWORD ret;
     CHAR keyA[39]; /* {CLSID} */
     HKEY root;
     DWORD ret;
@@ -1906,6 +2016,12 @@ static void test_SHGetObjectCompatFlags(void)
         return;
     }
 
         return;
     }
 
+    if (pColorAdjustLuma && pColorAdjustLuma == pSHGetObjectCompatFlags) /* win2k */
+    {
+        win_skip("Skipping SHGetObjectCompatFlags, same ordinal used for ColorAdjustLuma\n");
+        return;
+    }
+
     /* null args */
     ret = pSHGetObjectCompatFlags(NULL, NULL);
     ok(ret == 0, "got %d\n", ret);
     /* null args */
     ret = pSHGetObjectCompatFlags(NULL, NULL);
     ok(ret == 0, "got %d\n", ret);
@@ -1954,10 +2070,15 @@ static void test_SHGetObjectCompatFlags(void)
 }
 
 typedef struct {
 }
 
 typedef struct {
-    const IOleCommandTargetVtbl *lpVtbl;
+    IOleCommandTarget IOleCommandTarget_iface;
     LONG ref;
 } IOleCommandTargetImpl;
 
     LONG ref;
 } IOleCommandTargetImpl;
 
+static inline IOleCommandTargetImpl *impl_from_IOleCommandTarget(IOleCommandTarget *iface)
+{
+    return CONTAINING_RECORD(iface, IOleCommandTargetImpl, IOleCommandTarget_iface);
+}
+
 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
 
 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
 static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
 
 static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
@@ -1965,15 +2086,15 @@ static IOleCommandTarget* IOleCommandTargetImpl_Construct(void)
     IOleCommandTargetImpl *obj;
 
     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
     IOleCommandTargetImpl *obj;
 
     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
-    obj->lpVtbl = &IOleCommandTargetImpl_Vtbl;
+    obj->IOleCommandTarget_iface.lpVtbl = &IOleCommandTargetImpl_Vtbl;
     obj->ref = 1;
 
     obj->ref = 1;
 
-    return (IOleCommandTarget*)obj;
+    return &obj->IOleCommandTarget_iface;
 }
 
 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
 {
 }
 
 static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *iface, REFIID riid, void **ppvObj)
 {
-    IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
+    IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
 
     if (IsEqualIID(riid, &IID_IUnknown) ||
         IsEqualIID(riid, &IID_IOleCommandTarget))
 
     if (IsEqualIID(riid, &IID_IUnknown) ||
         IsEqualIID(riid, &IID_IOleCommandTarget))
@@ -1983,7 +2104,7 @@ static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *if
 
     if(*ppvObj)
     {
 
     if(*ppvObj)
     {
-        IUnknown_AddRef(iface);
+        IOleCommandTarget_AddRef(iface);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -1992,13 +2113,13 @@ static HRESULT WINAPI IOleCommandTargetImpl_QueryInterface(IOleCommandTarget *if
 
 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
 {
 
 static ULONG WINAPI IOleCommandTargetImpl_AddRef(IOleCommandTarget *iface)
 {
-    IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
+    IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
 {
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IOleCommandTargetImpl_Release(IOleCommandTarget *iface)
 {
-    IOleCommandTargetImpl *This = (IOleCommandTargetImpl *)iface;
+    IOleCommandTargetImpl *This = impl_from_IOleCommandTarget(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
@@ -2037,15 +2158,25 @@ static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
 };
 
 typedef struct {
 };
 
 typedef struct {
-    const IServiceProviderVtbl *lpVtbl;
+    IServiceProvider IServiceProvider_iface;
     LONG ref;
 } IServiceProviderImpl;
 
     LONG ref;
 } IServiceProviderImpl;
 
+static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
+{
+    return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
+}
+
 typedef struct {
 typedef struct {
-    const IProfferServiceVtbl *lpVtbl;
+    IProfferService IProfferService_iface;
     LONG ref;
 } IProfferServiceImpl;
 
     LONG ref;
 } IProfferServiceImpl;
 
+static inline IProfferServiceImpl *impl_from_IProfferService(IProfferService *iface)
+{
+    return CONTAINING_RECORD(iface, IProfferServiceImpl, IProfferService_iface);
+}
+
 
 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
 
 static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
 static const IProfferServiceVtbl IProfferServiceImpl_Vtbl;
@@ -2055,10 +2186,10 @@ static IServiceProvider* IServiceProviderImpl_Construct(void)
     IServiceProviderImpl *obj;
 
     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
     IServiceProviderImpl *obj;
 
     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
-    obj->lpVtbl = &IServiceProviderImpl_Vtbl;
+    obj->IServiceProvider_iface.lpVtbl = &IServiceProviderImpl_Vtbl;
     obj->ref = 1;
 
     obj->ref = 1;
 
-    return (IServiceProvider*)obj;
+    return &obj->IServiceProvider_iface;
 }
 
 static IProfferService* IProfferServiceImpl_Construct(void)
 }
 
 static IProfferService* IProfferServiceImpl_Construct(void)
@@ -2066,15 +2197,15 @@ static IProfferService* IProfferServiceImpl_Construct(void)
     IProfferServiceImpl *obj;
 
     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
     IProfferServiceImpl *obj;
 
     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
-    obj->lpVtbl = &IProfferServiceImpl_Vtbl;
+    obj->IProfferService_iface.lpVtbl = &IProfferServiceImpl_Vtbl;
     obj->ref = 1;
 
     obj->ref = 1;
 
-    return (IProfferService*)obj;
+    return &obj->IProfferService_iface;
 }
 
 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
 {
 }
 
 static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppvObj)
 {
-    IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
+    IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
 
     if (IsEqualIID(riid, &IID_IUnknown) ||
         IsEqualIID(riid, &IID_IServiceProvider))
 
     if (IsEqualIID(riid, &IID_IUnknown) ||
         IsEqualIID(riid, &IID_IServiceProvider))
@@ -2084,7 +2215,7 @@ static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *ifac
 
     if(*ppvObj)
     {
 
     if(*ppvObj)
     {
-        IUnknown_AddRef(iface);
+        IServiceProvider_AddRef(iface);
         /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
         if (IsEqualIID(riid, &IID_IServiceProvider))
             add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
         /* native uses redefined IID_IServiceProvider symbol, so we can't compare pointers */
         if (IsEqualIID(riid, &IID_IServiceProvider))
             add_call(&trace_got, 1, iface, &IID_IServiceProvider, 0, 0, 0);
@@ -2096,13 +2227,13 @@ static HRESULT WINAPI IServiceProviderImpl_QueryInterface(IServiceProvider *ifac
 
 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
 {
 
 static ULONG WINAPI IServiceProviderImpl_AddRef(IServiceProvider *iface)
 {
-    IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
+    IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
 {
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IServiceProviderImpl_Release(IServiceProvider *iface)
 {
-    IServiceProviderImpl *This = (IServiceProviderImpl *)iface;
+    IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
@@ -2186,7 +2317,7 @@ static void test_IUnknown_QueryServiceExec(void)
 
 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
 {
 
 static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface, REFIID riid, void **ppvObj)
 {
-    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+    IProfferServiceImpl *This = impl_from_IProfferService(iface);
 
     if (IsEqualIID(riid, &IID_IUnknown) ||
         IsEqualIID(riid, &IID_IProfferService))
 
     if (IsEqualIID(riid, &IID_IUnknown) ||
         IsEqualIID(riid, &IID_IProfferService))
@@ -2202,7 +2333,7 @@ static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface,
 
     if(*ppvObj)
     {
 
     if(*ppvObj)
     {
-        IUnknown_AddRef(iface);
+        IProfferService_AddRef(iface);
         return S_OK;
     }
 
         return S_OK;
     }
 
@@ -2211,13 +2342,13 @@ static HRESULT WINAPI IProfferServiceImpl_QueryInterface(IProfferService *iface,
 
 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
 {
 
 static ULONG WINAPI IProfferServiceImpl_AddRef(IProfferService *iface)
 {
-    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+    IProfferServiceImpl *This = impl_from_IProfferService(iface);
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
 {
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
 {
-    IProfferServiceImpl *This = (IProfferServiceImpl *)iface;
+    IProfferServiceImpl *This = impl_from_IProfferService(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
@@ -2231,6 +2362,7 @@ static ULONG WINAPI IProfferServiceImpl_Release(IProfferService *iface)
 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
     REFGUID service, IServiceProvider *pService, DWORD *pCookie)
 {
 static HRESULT WINAPI IProfferServiceImpl_ProfferService(IProfferService *iface,
     REFGUID service, IServiceProvider *pService, DWORD *pCookie)
 {
+    *pCookie = 0xdeadbeef;
     add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
     return S_OK;
 }
     add_call(&trace_got, 3, service, pService, pCookie, 0, 0);
     return S_OK;
 }
@@ -2288,8 +2420,10 @@ static void test_IUnknown_ProfferService(void)
     add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
 
     init_call_trace(&trace_got);
     add_call(&trace_expected, 3, &dummy_serviceid, provider, &cookie, 0, 0);
 
     init_call_trace(&trace_got);
+    cookie = 0;
     hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
     ok(hr == S_OK, "got 0x%08x\n", hr);
     hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, provider, &cookie);
     ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(cookie == 0xdeadbeef, "got %x\n", cookie);
 
     ok_trace(&trace_expected, &trace_got);
     free_call_trace(&trace_got);
 
     ok_trace(&trace_expected, &trace_got);
     free_call_trace(&trace_got);
@@ -2303,8 +2437,10 @@ static void test_IUnknown_ProfferService(void)
     add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
 
     init_call_trace(&trace_got);
     add_call(&trace_expected, 4, (void*)(DWORD_PTR)cookie, 0, 0, 0, 0);
 
     init_call_trace(&trace_got);
+    ok(cookie != 0, "got %x\n", cookie);
     hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
     ok(hr == S_OK, "got 0x%08x\n", hr);
     hr = pIUnknown_ProfferService((IUnknown*)proff, &dummy_serviceid, 0, &cookie);
     ok(hr == S_OK, "got 0x%08x\n", hr);
+    ok(cookie == 0, "got %x\n", cookie);
     ok_trace(&trace_expected, &trace_got);
     free_call_trace(&trace_got);
     free_call_trace(&trace_expected);
     ok_trace(&trace_expected, &trace_got);
     free_call_trace(&trace_got);
     free_call_trace(&trace_expected);
@@ -2359,16 +2495,427 @@ static void test_SHCreateWorkerWindowA(void)
 
     /* test exstyle */
     ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
 
     /* test exstyle */
     ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
-    ok(ret == WS_EX_WINDOWEDGE, "0x%08lx\n", ret);
+    ok(ret == WS_EX_WINDOWEDGE ||
+       ret == (WS_EX_WINDOWEDGE|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
 
     DestroyWindow(hwnd);
 
     hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
     ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
 
     DestroyWindow(hwnd);
 
     hwnd = pSHCreateWorkerWindowA(0, NULL, WS_EX_TOOLWINDOW, 0, 0, 0);
     ret = GetWindowLongA(hwnd, GWL_EXSTYLE);
-    ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW), "0x%08lx\n", ret);
+    ok(ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW) ||
+       ret == (WS_EX_WINDOWEDGE|WS_EX_TOOLWINDOW|WS_EX_LAYOUTRTL) /* systems with RTL locale */, "0x%08lx\n", ret);
     DestroyWindow(hwnd);
 }
 
     DestroyWindow(hwnd);
 }
 
+static HRESULT WINAPI SF_QueryInterface(IShellFolder *iface,
+        REFIID riid, void **ppv)
+{
+    /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
+    ok(!IsEqualGUID(&IID_IShellFolder, riid),
+            "Unexpected QI for IShellFolder\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI SF_AddRef(IShellFolder *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI SF_Release(IShellFolder *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI SF_ParseDisplayName(IShellFolder *iface,
+        HWND owner, LPBC reserved, LPOLESTR displayName, ULONG *eaten,
+        LPITEMIDLIST *idl, ULONG *attr)
+{
+    ok(0, "Didn't expect ParseDisplayName\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_EnumObjects(IShellFolder *iface,
+        HWND owner, SHCONTF flags, IEnumIDList **enm)
+{
+    *enm = (IEnumIDList*)0xcafebabe;
+    return S_OK;
+}
+
+static HRESULT WINAPI SF_BindToObject(IShellFolder *iface,
+        LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
+{
+    ok(0, "Didn't expect BindToObject\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_BindToStorage(IShellFolder *iface,
+        LPCITEMIDLIST idl, LPBC reserved, REFIID riid, void **obj)
+{
+    ok(0, "Didn't expect BindToStorage\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_CompareIDs(IShellFolder *iface,
+        LPARAM lparam, LPCITEMIDLIST idl1, LPCITEMIDLIST idl2)
+{
+    ok(0, "Didn't expect CompareIDs\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_CreateViewObject(IShellFolder *iface,
+        HWND owner, REFIID riid, void **out)
+{
+    ok(0, "Didn't expect CreateViewObject\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_GetAttributesOf(IShellFolder *iface,
+        UINT cidl, LPCITEMIDLIST *idl, SFGAOF *inOut)
+{
+    ok(0, "Didn't expect GetAttributesOf\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_GetUIObjectOf(IShellFolder *iface,
+        HWND owner, UINT cidl, LPCITEMIDLIST *idls, REFIID riid, UINT *inOut,
+        void **out)
+{
+    ok(0, "Didn't expect GetUIObjectOf\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_GetDisplayNameOf(IShellFolder *iface,
+        LPCITEMIDLIST idl, SHGDNF flags, STRRET *name)
+{
+    ok(0, "Didn't expect GetDisplayNameOf\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI SF_SetNameOf(IShellFolder *iface,
+        HWND hwnd, LPCITEMIDLIST idl, LPCOLESTR name, SHGDNF flags,
+        LPITEMIDLIST *idlOut)
+{
+    ok(0, "Didn't expect SetNameOf\n");
+    return E_NOTIMPL;
+}
+
+static IShellFolderVtbl ShellFolderVtbl = {
+    SF_QueryInterface,
+    SF_AddRef,
+    SF_Release,
+    SF_ParseDisplayName,
+    SF_EnumObjects,
+    SF_BindToObject,
+    SF_BindToStorage,
+    SF_CompareIDs,
+    SF_CreateViewObject,
+    SF_GetAttributesOf,
+    SF_GetUIObjectOf,
+    SF_GetDisplayNameOf,
+    SF_SetNameOf
+};
+
+static IShellFolder ShellFolder = { &ShellFolderVtbl };
+
+static void test_SHIShellFolder_EnumObjects(void)
+{
+    IEnumIDList *enm;
+    HRESULT hres;
+    IShellFolder *folder;
+
+    if(!pSHIShellFolder_EnumObjects || is_win2k_and_lower){
+        win_skip("SHIShellFolder_EnumObjects not available\n");
+        return;
+    }
+
+    if(0){
+        /* NULL object crashes on Windows */
+        pSHIShellFolder_EnumObjects(NULL, NULL, 0, NULL);
+    }
+
+    /* SHIShellFolder_EnumObjects doesn't QI the object for IShellFolder */
+    enm = (IEnumIDList*)0xdeadbeef;
+    hres = pSHIShellFolder_EnumObjects(&ShellFolder, NULL, 0, &enm);
+    ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
+    ok(enm == (IEnumIDList*)0xcafebabe, "Didn't get expected enumerator location, instead: %p\n", enm);
+
+    /* SHIShellFolder_EnumObjects isn't strict about the IShellFolder object */
+    hres = pSHGetDesktopFolder(&folder);
+    ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
+
+    enm = NULL;
+    hres = pSHIShellFolder_EnumObjects(folder, NULL, 0, &enm);
+    ok(hres == S_OK, "SHIShellFolder_EnumObjects failed: 0x%08x\n", hres);
+    ok(enm != NULL, "Didn't get an enumerator\n");
+    if(enm)
+        IEnumIDList_Release(enm);
+
+    IShellFolder_Release(folder);
+}
+
+static void write_inifile(LPCWSTR filename)
+{
+    DWORD written;
+    HANDLE file;
+
+    static const char data[] =
+        "[TestApp]\r\n"
+        "AKey=1\r\n"
+        "AnotherKey=asdf\r\n";
+
+    file = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+    if(file == INVALID_HANDLE_VALUE)
+        return;
+
+    WriteFile(file, data, sizeof(data), &written, NULL);
+
+    CloseHandle(file);
+}
+
+#define verify_inifile(f, e) r_verify_inifile(__LINE__, f, e)
+static void r_verify_inifile(unsigned l, LPCWSTR filename, LPCSTR exp)
+{
+    HANDLE file;
+    CHAR buf[1024];
+    DWORD read;
+
+    file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+    if(file == INVALID_HANDLE_VALUE)
+        return;
+
+    ReadFile(file, buf, sizeof(buf) * sizeof(CHAR), &read, NULL);
+    buf[read] = '\0';
+
+    CloseHandle(file);
+
+    ok_(__FILE__,l)(!strcmp(buf, exp), "Expected:\n%s\nGot:\n%s\n", exp,
+            buf);
+}
+
+static void test_SHGetIniString(void)
+{
+    DWORD ret;
+    WCHAR out[64] = {0};
+
+    static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
+    static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
+    static const WCHAR AKeyW[] = {'A','K','e','y',0};
+    static const WCHAR AnotherKeyW[] = {'A','n','o','t','h','e','r','K','e','y',0};
+    static const WCHAR JunkKeyW[] = {'J','u','n','k','K','e','y',0};
+
+    if(!pSHGetIniStringW || is_win2k_and_lower){
+        win_skip("SHGetIniStringW is not available\n");
+        return;
+    }
+
+    write_inifile(TestIniW);
+
+    if(0){
+        /* these crash on Windows */
+        pSHGetIniStringW(NULL, NULL, NULL, 0, NULL);
+        pSHGetIniStringW(NULL, AKeyW, out, sizeof(out), TestIniW);
+        pSHGetIniStringW(TestAppW, AKeyW, NULL, sizeof(out), TestIniW);
+    }
+
+    ret = pSHGetIniStringW(TestAppW, AKeyW, out, 0, TestIniW);
+    ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
+
+    /* valid arguments */
+    ret = pSHGetIniStringW(TestAppW, NULL, out, sizeof(out), TestIniW);
+    ok(broken(ret == 0) || /* win 98 */
+            ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
+    ok(!lstrcmpW(out, AKeyW), "Expected %s, got: %s\n",
+                wine_dbgstr_w(AKeyW), wine_dbgstr_w(out));
+
+    ret = pSHGetIniStringW(TestAppW, AKeyW, out, sizeof(out), TestIniW);
+    ok(broken(ret == 0) || /* win 98 */
+                ret == 1, "SHGetIniStringW should have given 1, instead: %d\n", ret);
+    ok(broken(*out == 0) || /*win 98 */
+        !strcmp_wa(out, "1"), "Expected L\"1\", got: %s\n", wine_dbgstr_w(out));
+
+    ret = pSHGetIniStringW(TestAppW, AnotherKeyW, out, sizeof(out), TestIniW);
+    ok(broken(ret == 0) || /* win 98 */
+            ret == 4, "SHGetIniStringW should have given 4, instead: %d\n", ret);
+    ok(broken(*out == 0) || /* win 98 */
+            !strcmp_wa(out, "asdf"), "Expected L\"asdf\", got: %s\n", wine_dbgstr_w(out));
+
+    ret = pSHGetIniStringW(TestAppW, JunkKeyW, out, sizeof(out), TestIniW);
+    ok(ret == 0, "SHGetIniStringW should have given 0, instead: %d\n", ret);
+    ok(*out == 0, "Expected L\"\", got: %s\n", wine_dbgstr_w(out));
+
+    DeleteFileW(TestIniW);
+}
+
+static void test_SHSetIniString(void)
+{
+    BOOL ret;
+
+    static const WCHAR TestAppW[] = {'T','e','s','t','A','p','p',0};
+    static const WCHAR AnotherAppW[] = {'A','n','o','t','h','e','r','A','p','p',0};
+    static const WCHAR TestIniW[] = {'C',':','\\','t','e','s','t','.','i','n','i',0};
+    static const WCHAR AKeyW[] = {'A','K','e','y',0};
+    static const WCHAR NewKeyW[] = {'N','e','w','K','e','y',0};
+    static const WCHAR AValueW[] = {'A','V','a','l','u','e',0};
+
+    if(!pSHSetIniStringW || is_win2k_and_lower){
+        win_skip("SHSetIniStringW is not available\n");
+        return;
+    }
+
+    write_inifile(TestIniW);
+
+    ret = pSHSetIniStringW(TestAppW, AKeyW, AValueW, TestIniW);
+    ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
+    todo_wine /* wine sticks an extra \r\n at the end of the file */
+        verify_inifile(TestIniW, "[TestApp]\r\nAKey=AValue\r\nAnotherKey=asdf\r\n");
+
+    ret = pSHSetIniStringW(TestAppW, AKeyW, NULL, TestIniW);
+    ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
+    verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n");
+
+    ret = pSHSetIniStringW(AnotherAppW, NewKeyW, AValueW, TestIniW);
+    ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
+    verify_inifile(TestIniW, "[TestApp]\r\nAnotherKey=asdf\r\n[AnotherApp]\r\nNewKey=AValue\r\n");
+
+    ret = pSHSetIniStringW(TestAppW, NULL, AValueW, TestIniW);
+    ok(ret == TRUE, "SHSetIniStringW should not have failed\n");
+    verify_inifile(TestIniW, "[AnotherApp]\r\nNewKey=AValue\r\n");
+
+    DeleteFileW(TestIniW);
+}
+
+enum _shellkey_flags {
+    SHKEY_Root_HKCU = 0x1,
+    SHKEY_Root_HKLM = 0x2,
+    SHKEY_Key_Explorer  = 0x00,
+    SHKEY_Key_Shell = 0x10,
+    SHKEY_Key_ShellNoRoam = 0x20,
+    SHKEY_Key_Classes = 0x30,
+    SHKEY_Subkey_Default = 0x0000,
+    SHKEY_Subkey_ResourceName = 0x1000,
+    SHKEY_Subkey_Handlers = 0x2000,
+    SHKEY_Subkey_Associations = 0x3000,
+    SHKEY_Subkey_Volatile = 0x4000,
+    SHKEY_Subkey_MUICache = 0x5000,
+    SHKEY_Subkey_FileExts = 0x6000
+};
+
+static void test_SHGetShellKey(void)
+{
+    static const WCHAR ShellFoldersW[] = { 'S','h','e','l','l',' ','F','o','l','d','e','r','s',0 };
+    static const WCHAR WineTestW[] = { 'W','i','n','e','T','e','s','t',0 };
+
+    void *pPathBuildRootW = GetProcAddress(hShlwapi, "PathBuildRootW");
+    DWORD *alloc_data, data, size;
+    HKEY hkey;
+    HRESULT hres;
+
+    if (!pSHGetShellKey)
+    {
+        win_skip("SHGetShellKey(ordinal 491) isn't available\n");
+        return;
+    }
+
+    /* some win2k */
+    if (pPathBuildRootW && pPathBuildRootW == pSHGetShellKey)
+    {
+        win_skip("SHGetShellKey(ordinal 491) used for PathBuildRootW\n");
+        return;
+    }
+
+    if (is_win9x || is_win2k_and_lower)
+    {
+        win_skip("Ordinal 491 used for another call, skipping SHGetShellKey tests\n");
+        return;
+    }
+
+    /* Vista+ limits SHKEY enumeration values */
+    SetLastError(0xdeadbeef);
+    hkey = pSHGetShellKey(SHKEY_Key_Explorer, ShellFoldersW, FALSE);
+    if (hkey)
+    {
+        /* Tests not working on Vista+ */
+        RegCloseKey(hkey);
+
+        hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Classes, NULL, FALSE);
+        ok(hkey != NULL, "hkey = NULL\n");
+        RegCloseKey(hkey);
+    }
+
+    hkey = pSHGetShellKey(SHKEY_Root_HKCU|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
+    ok(hkey != NULL, "hkey = NULL\n");
+    RegCloseKey(hkey);
+
+    hkey = pSHGetShellKey(SHKEY_Root_HKLM|SHKEY_Key_Explorer, ShellFoldersW, FALSE);
+    ok(hkey != NULL, "hkey = NULL\n");
+    RegCloseKey(hkey);
+
+    hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, FALSE);
+    ok(hkey == NULL, "hkey != NULL\n");
+
+    hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
+    ok(hkey != NULL, "Can't open key\n");
+    ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
+    RegCloseKey(hkey);
+
+    hkey = pSHGetShellKey(SHKEY_Root_HKLM, WineTestW, TRUE);
+    if (!hkey && GetLastError() == ERROR_ACCESS_DENIED)
+    {
+        skip("Not authorized to create keys\n");
+        return;
+    }
+    ok(hkey != NULL, "Can't create key\n");
+    RegCloseKey(hkey);
+
+    if (!pSKGetValueW || !pSKSetValueW || !pSKDeleteValueW || !pSKAllocValueW)
+    {
+        win_skip("SKGetValueW, SKSetValueW, SKDeleteValueW or SKAllocValueW not available\n");
+        return;
+    }
+
+    size = sizeof(data);
+    hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
+    ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
+
+    data = 1234;
+    hres = pSKSetValueW(SHKEY_Root_HKLM, WineTestW, NULL, REG_DWORD, &data, sizeof(DWORD));
+    ok(hres == S_OK, "hres = %x\n", hres);
+
+    size = 1;
+    hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, NULL, &size);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    ok(size == sizeof(DWORD), "size = %d\n", size);
+
+    data = 0xdeadbeef;
+    hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    ok(size == sizeof(DWORD), "size = %d\n", size);
+    ok(data == 1234, "data = %d\n", data);
+
+    hres = pSKAllocValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, (void**)&alloc_data, &size);
+    ok(hres == S_OK, "hres= %x\n", hres);
+    ok(size == sizeof(DWORD), "size = %d\n", size);
+    if (SUCCEEDED(hres))
+    {
+        ok(*alloc_data == 1234, "*alloc_data = %d\n", *alloc_data);
+        LocalFree(alloc_data);
+    }
+
+    hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
+    ok(hres == S_OK, "hres = %x\n", hres);
+
+    hres = pSKDeleteValueW(SHKEY_Root_HKLM, WineTestW, NULL);
+    ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
+
+    hres = pSKGetValueW(SHKEY_Root_HKLM, WineTestW, NULL, NULL, &data, &size);
+    ok(hres == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "hres = %x\n", hres);
+
+    hkey = pSHGetShellKey(SHKEY_Root_HKLM, NULL, FALSE);
+    ok(hkey != NULL, "Can't create key\n");
+    ok(SUCCEEDED(RegDeleteKeyW(hkey, WineTestW)), "Can't delete key\n");
+    RegCloseKey(hkey);
+}
+
 static void init_pointers(void)
 {
 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
 static void init_pointers(void)
 {
 #define MAKEFUNC(f, ord) (p##f = (void*)GetProcAddress(hShlwapi, (LPSTR)(ord)))
@@ -2378,6 +2925,7 @@ static void init_pointers(void)
     MAKEFUNC(SHFreeShared, 10);
     MAKEFUNC(GetAcceptLanguagesA, 14);
     MAKEFUNC(SHSetWindowBits, 165);
     MAKEFUNC(SHFreeShared, 10);
     MAKEFUNC(GetAcceptLanguagesA, 14);
     MAKEFUNC(SHSetWindowBits, 165);
+    MAKEFUNC(SHSetParentHwnd, 167);
     MAKEFUNC(ConnectToConnectionPoint, 168);
     MAKEFUNC(SHSearchMapInt, 198);
     MAKEFUNC(SHCreateWorkerWindowA, 257);
     MAKEFUNC(ConnectToConnectionPoint, 168);
     MAKEFUNC(SHSearchMapInt, 198);
     MAKEFUNC(SHCreateWorkerWindowA, 257);
@@ -2385,25 +2933,125 @@ static void init_pointers(void)
     MAKEFUNC(SHPackDispParams, 282);
     MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
     MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
     MAKEFUNC(SHPackDispParams, 282);
     MAKEFUNC(IConnectionPoint_InvokeWithCancel, 283);
     MAKEFUNC(IConnectionPoint_SimpleInvoke, 284);
+    MAKEFUNC(SHGetIniStringW, 294);
+    MAKEFUNC(SHSetIniStringW, 295);
     MAKEFUNC(SHFormatDateTimeA, 353);
     MAKEFUNC(SHFormatDateTimeW, 354);
     MAKEFUNC(SHFormatDateTimeA, 353);
     MAKEFUNC(SHFormatDateTimeW, 354);
+    MAKEFUNC(SHIShellFolder_EnumObjects, 404);
     MAKEFUNC(SHGetObjectCompatFlags, 476);
     MAKEFUNC(IUnknown_QueryServiceExec, 484);
     MAKEFUNC(SHGetObjectCompatFlags, 476);
     MAKEFUNC(IUnknown_QueryServiceExec, 484);
+    MAKEFUNC(SHGetShellKey, 491);
     MAKEFUNC(SHPropertyBag_ReadLONG, 496);
     MAKEFUNC(IUnknown_ProfferService, 514);
     MAKEFUNC(SHPropertyBag_ReadLONG, 496);
     MAKEFUNC(IUnknown_ProfferService, 514);
+    MAKEFUNC(SKGetValueW, 516);
+    MAKEFUNC(SKSetValueW, 517);
+    MAKEFUNC(SKDeleteValueW, 518);
+    MAKEFUNC(SKAllocValueW, 519);
 #undef MAKEFUNC
 }
 
 #undef MAKEFUNC
 }
 
+static void test_SHSetParentHwnd(void)
+{
+    HWND hwnd, hwnd2, ret;
+    DWORD style;
+
+    if (!pSHSetParentHwnd)
+    {
+        win_skip("SHSetParentHwnd not available\n");
+        return;
+    }
+
+    hwnd = CreateWindowA("Button", "", WS_VISIBLE, 0, 0, 10, 10, NULL, NULL, NULL, NULL);
+    ok(hwnd != NULL, "got %p\n", hwnd);
+
+    hwnd2 = CreateWindowA("Button", "", WS_VISIBLE | WS_CHILD, 0, 0, 10, 10, hwnd, NULL, NULL, NULL);
+    ok(hwnd2 != NULL, "got %p\n", hwnd2);
+
+    /* null params */
+    ret = pSHSetParentHwnd(NULL, NULL);
+    ok(ret == NULL, "got %p\n", ret);
+
+    /* set to no parent while already no parent present */
+    ret = GetParent(hwnd);
+    ok(ret == NULL, "got %p\n", ret);
+    style = GetWindowLongA(hwnd, GWL_STYLE);
+    ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
+    ret = pSHSetParentHwnd(hwnd, NULL);
+    ok(ret == NULL, "got %p\n", ret);
+    style = GetWindowLongA(hwnd, GWL_STYLE);
+    ok((style & (WS_POPUP|WS_CHILD)) == 0, "got style 0x%08x\n", style);
+
+    /* reset to null parent from not null */
+    ret = GetParent(hwnd2);
+    ok(ret == hwnd, "got %p\n", ret);
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
+    ret = pSHSetParentHwnd(hwnd2, NULL);
+    ok(ret == NULL, "got %p\n", ret);
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    ok((style & (WS_POPUP|WS_CHILD)) == WS_POPUP, "got style 0x%08x\n", style);
+    ret = GetParent(hwnd2);
+    ok(ret == NULL, "got %p\n", ret);
+
+    /* set parent back */
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    SetWindowLongA(hwnd2, GWL_STYLE, style & ~(WS_CHILD|WS_POPUP));
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    ok((style & (WS_CHILD|WS_POPUP)) == 0, "got 0x%08x\n", style);
+
+    ret = pSHSetParentHwnd(hwnd2, hwnd);
+    todo_wine ok(ret == NULL, "got %p\n", ret);
+
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    ok((style & (WS_POPUP|WS_CHILD)) == WS_CHILD, "got style 0x%08x\n", style);
+    ret = GetParent(hwnd2);
+    ok(ret == hwnd, "got %p\n", ret);
+
+    /* try to set same parent again */
+    /* with WS_POPUP */
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    SetWindowLongA(hwnd2, GWL_STYLE, style | WS_POPUP);
+    ret = pSHSetParentHwnd(hwnd2, hwnd);
+    todo_wine ok(ret == NULL, "got %p\n", ret);
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
+    ret = GetParent(hwnd2);
+    ok(ret == hwnd, "got %p\n", ret);
+
+    /* without WS_POPUP */
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    SetWindowLongA(hwnd2, GWL_STYLE, style | ~WS_POPUP);
+    ret = pSHSetParentHwnd(hwnd2, hwnd);
+    todo_wine ok(ret == hwnd, "got %p\n", ret);
+    style = GetWindowLongA(hwnd2, GWL_STYLE);
+    ok((style & (WS_CHILD|WS_POPUP)) == WS_CHILD, "got 0x%08x\n", style);
+    ret = GetParent(hwnd2);
+    ok(ret == hwnd, "got %p\n", ret);
+
+    DestroyWindow(hwnd);
+    DestroyWindow(hwnd2);
+}
+
 START_TEST(ordinal)
 {
     hShlwapi = GetModuleHandleA("shlwapi.dll");
     is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
 START_TEST(ordinal)
 {
     hShlwapi = GetModuleHandleA("shlwapi.dll");
     is_win2k_and_lower = GetProcAddress(hShlwapi, "StrChrNW") == 0;
+    is_win9x = GetProcAddress(hShlwapi, (LPSTR)99) == 0; /* StrCpyNXA */
+
+    /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
+    if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
+        win_skip("Too old shlwapi version\n");
+        return;
+    }
 
     init_pointers();
 
     hmlang = LoadLibraryA("mlang.dll");
     pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
 
 
     init_pointers();
 
     hmlang = LoadLibraryA("mlang.dll");
     pLcidToRfc1766A = (void *)GetProcAddress(hmlang, "LcidToRfc1766A");
 
+    hshell32 = LoadLibraryA("shell32.dll");
+    pSHGetDesktopFolder = (void *)GetProcAddress(hshell32, "SHGetDesktopFolder");
+
     test_GetAcceptLanguagesA();
     test_SHSearchMapInt();
     test_alloc_shared();
     test_GetAcceptLanguagesA();
     test_SHSearchMapInt();
     test_alloc_shared();
@@ -2419,4 +3067,12 @@ START_TEST(ordinal)
     test_IUnknown_QueryServiceExec();
     test_IUnknown_ProfferService();
     test_SHCreateWorkerWindowA();
     test_IUnknown_QueryServiceExec();
     test_IUnknown_ProfferService();
     test_SHCreateWorkerWindowA();
+    test_SHIShellFolder_EnumObjects();
+    test_SHGetIniString();
+    test_SHSetIniString();
+    test_SHGetShellKey();
+    test_SHSetParentHwnd();
+
+    FreeLibrary(hshell32);
+    FreeLibrary(hmlang);
 }
 }
index 3e83a45..d459570 100755 (executable)
@@ -17,7 +17,6 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #include <stdarg.h>
 #include <stdio.h>
 
@@ -37,7 +36,7 @@ static BOOL    (WINAPI *pPathAppendA)(LPSTR, LPCSTR);
 
 /* ################ */
 
 
 /* ################ */
 
-struct {
+static const struct {
     const char *url;
     const char *path;
     DWORD ret;
     const char *url;
     const char *path;
     DWORD ret;
@@ -106,7 +105,7 @@ static struct {
     {NULL, FALSE}
 };
 
     {NULL, FALSE}
 };
 
-struct {
+static const struct {
     const char *path;
     const char *result;
 } TEST_PATH_UNQUOTE_SPACES[] = {
     const char *path;
     const char *result;
 } TEST_PATH_UNQUOTE_SPACES[] = {
@@ -1362,6 +1361,12 @@ START_TEST(path)
 {
     HMODULE hShlwapi = GetModuleHandleA("shlwapi.dll");
 
 {
     HMODULE hShlwapi = GetModuleHandleA("shlwapi.dll");
 
+    /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
+    if(!GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx")){
+        win_skip("Too old shlwapi version\n");
+        return;
+    }
+
     pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA");
     pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW");
     pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
     pPathCreateFromUrlA = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlA");
     pPathCreateFromUrlW = (void*)GetProcAddress(hShlwapi, "PathCreateFromUrlW");
     pPathCombineW = (void*)GetProcAddress(hShlwapi, "PathCombineW");
index 5fb3dac..3634041 100755 (executable)
@@ -17,7 +17,6 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <assert.h>
 #include <stdarg.h>
 #include <stdio.h>
 
 #include <stdarg.h>
 #include <stdio.h>
 
 #define REG_CURRENT_VERSION "Software\\Microsoft\\Windows\\CurrentVersion\\explorer"
 
 static HMODULE hshlwapi;
 #define REG_CURRENT_VERSION "Software\\Microsoft\\Windows\\CurrentVersion\\explorer"
 
 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;
-typedef LSTATUS (WINAPI *SHRegGetValueA_func)(HKEY,LPCSTR,LPCSTR,SRRF,LPDWORD,LPVOID,LPDWORD);
-static SHRegGetValueA_func pSHRegGetValueA;
+
+static DWORD (WINAPI *pSHCopyKeyA)(HKEY,LPCSTR,HKEY,DWORD);
+static DWORD (WINAPI *pSHRegGetPathA)(HKEY,LPCSTR,LPCSTR,LPSTR,DWORD);
+static LSTATUS (WINAPI *pSHRegGetValueA)(HKEY,LPCSTR,LPCSTR,SRRF,LPDWORD,LPVOID,LPDWORD);
+static LSTATUS (WINAPI *pSHRegCreateUSKeyW)(LPCWSTR,REGSAM,HUSKEY,PHUSKEY,DWORD);
 
 static char sTestpath1[] = "%LONGSYSTEMVAR%\\subdir1";
 static char sTestpath2[] = "%FOO%\\subdir1";
 
 static char sTestpath1[] = "%LONGSYSTEMVAR%\\subdir1";
 static char sTestpath2[] = "%FOO%\\subdir1";
@@ -192,7 +190,7 @@ static void test_SHGetRegPath(void)
        ok( 0 == strcmp(sExpTestpath1, buf) , "Comparing (%s) with (%s) failed\n", buf, sExpTestpath1);
 }
 
        ok( 0 == strcmp(sExpTestpath1, buf) , "Comparing (%s) with (%s) failed\n", buf, sExpTestpath1);
 }
 
-static void test_SHQUeryValueEx(void)
+static void test_SHQueryValueEx(void)
 {
        HKEY hKey;
        DWORD dwSize;
 {
        HKEY hKey;
        DWORD dwSize;
@@ -445,21 +443,47 @@ static void test_SHDeleteKey(void)
         ok( 0, "Could not set up SHDeleteKey test\n");
 }
 
         ok( 0, "Could not set up SHDeleteKey test\n");
 }
 
+static void test_SHRegCreateUSKeyW(void)
+{
+    static const WCHAR subkeyW[] = {'s','u','b','k','e','y',0};
+    LONG ret;
+
+    if (!pSHRegCreateUSKeyW)
+    {
+        win_skip("SHRegCreateUSKeyW not available\n");
+        return;
+    }
+
+    ret = pSHRegCreateUSKeyW(subkeyW, KEY_ALL_ACCESS, NULL, NULL, SHREGSET_FORCE_HKCU);
+    ok(ret == ERROR_INVALID_PARAMETER, "got %d\n", ret);
+}
+
 START_TEST(shreg)
 {
 START_TEST(shreg)
 {
-       HKEY hkey = create_test_entries();
-
-        if (!hkey) return;
-
-       hshlwapi = GetModuleHandleA("shlwapi.dll");
-        pSHCopyKeyA=(SHCopyKeyA_func)GetProcAddress(hshlwapi,"SHCopyKeyA");
-        pSHRegGetPathA=(SHRegGetPathA_func)GetProcAddress(hshlwapi,"SHRegGetPathA");
-        pSHRegGetValueA=(SHRegGetValueA_func)GetProcAddress(hshlwapi,"SHRegGetValueA");
-       test_SHGetValue();
-        test_SHRegGetValue();
-       test_SHQUeryValueEx();
-       test_SHGetRegPath();
-       test_SHCopyKey();
-        test_SHDeleteKey();
-        delete_key( hkey, "Software\\Wine", "Test" );
+    HKEY hkey = create_test_entries();
+
+    if (!hkey) return;
+
+    hshlwapi = GetModuleHandleA("shlwapi.dll");
+
+    /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
+    if(!GetProcAddress(hshlwapi, "SHCreateStreamOnFileEx")){
+        win_skip("Too old shlwapi version\n");
+        return;
+    }
+
+    pSHCopyKeyA = (void*)GetProcAddress(hshlwapi,"SHCopyKeyA");
+    pSHRegGetPathA = (void*)GetProcAddress(hshlwapi,"SHRegGetPathA");
+    pSHRegGetValueA = (void*)GetProcAddress(hshlwapi,"SHRegGetValueA");
+    pSHRegCreateUSKeyW = (void*)GetProcAddress(hshlwapi, "SHRegCreateUSKeyW");
+
+    test_SHGetValue();
+    test_SHRegGetValue();
+    test_SHQueryValueEx();
+    test_SHGetRegPath();
+    test_SHCopyKey();
+    test_SHDeleteKey();
+    test_SHRegCreateUSKeyW();
+
+    delete_key( hkey, "Software\\Wine", "Test" );
 }
 }
index 17c652d..aac79f8 100755 (executable)
@@ -55,12 +55,18 @@ static LPSTR   (WINAPI *pStrFormatKBSizeA)(LONGLONG,LPSTR,UINT);
 static LPWSTR  (WINAPI *pStrFormatKBSizeW)(LONGLONG,LPWSTR,UINT);
 static BOOL    (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int);
 static BOOL    (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int);
 static LPWSTR  (WINAPI *pStrFormatKBSizeW)(LONGLONG,LPWSTR,UINT);
 static BOOL    (WINAPI *pStrIsIntlEqualA)(BOOL,LPCSTR,LPCSTR,int);
 static BOOL    (WINAPI *pStrIsIntlEqualW)(BOOL,LPCWSTR,LPCWSTR,int);
-static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,void*,BSTR*);
+static LPWSTR  (WINAPI *pStrPBrkW)(LPCWSTR,LPCWSTR);
+static LPSTR   (WINAPI *pStrRChrA)(LPCSTR,LPCSTR,WORD);
+static HRESULT (WINAPI *pStrRetToBSTR)(STRRET*,LPCITEMIDLIST,BSTR*);
 static HRESULT (WINAPI *pStrRetToBufA)(STRRET*,LPCITEMIDLIST,LPSTR,UINT);
 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
 static HRESULT (WINAPI *pStrRetToBufA)(STRRET*,LPCITEMIDLIST,LPSTR,UINT);
 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
+static LPWSTR  (WINAPI *pStrStrNW)(LPCWSTR,LPCWSTR,UINT);
+static LPWSTR  (WINAPI *pStrStrNIW)(LPCWSTR,LPCWSTR,UINT);
 static INT     (WINAPIV *pwnsprintfA)(LPSTR,INT,LPCSTR, ...);
 static INT     (WINAPIV *pwnsprintfW)(LPWSTR,INT,LPCWSTR, ...);
 static LPWSTR  (WINAPI *pStrChrNW)(LPWSTR,WCHAR,UINT);
 static INT     (WINAPIV *pwnsprintfA)(LPSTR,INT,LPCSTR, ...);
 static INT     (WINAPIV *pwnsprintfW)(LPWSTR,INT,LPCWSTR, ...);
 static LPWSTR  (WINAPI *pStrChrNW)(LPWSTR,WCHAR,UINT);
+static BOOL    (WINAPI *pStrToInt64ExA)(LPCSTR,DWORD,LONGLONG*);
+static BOOL    (WINAPI *pStrToInt64ExW)(LPCWSTR,DWORD,LONGLONG*);
 
 static int strcmpW(const WCHAR *str1, const WCHAR *str2)
 {
 
 static int strcmpW(const WCHAR *str1, const WCHAR *str2)
 {
@@ -73,17 +79,19 @@ typedef struct tagStrToIntResult
 {
   const char* string;
   int str_to_int;
 {
   const char* string;
   int str_to_int;
-  int str_to_int_ex;
-  int str_to_int_hex;
+  LONGLONG str_to_int64_ex;
+  LONGLONG str_to_int64_hex;
 } StrToIntResult;
 
 static const StrToIntResult StrToInt_results[] = {
      { "1099", 1099, 1099, 1099 },
 } StrToIntResult;
 
 static const StrToIntResult StrToInt_results[] = {
      { "1099", 1099, 1099, 1099 },
+     { "4294967319", 23, ((LONGLONG)1 << 32) | 23, ((LONGLONG)1 << 32) | 23 },
      { "+88987", 0, 88987, 88987 },
      { "012", 12, 12, 12 },
      { "-55", -55, -55, -55 },
      { "-0", 0, 0, 0 },
      { "0x44ff", 0, 0, 0x44ff },
      { "+88987", 0, 88987, 88987 },
      { "012", 12, 12, 12 },
      { "-55", -55, -55, -55 },
      { "-0", 0, 0, 0 },
      { "0x44ff", 0, 0, 0x44ff },
+     { "0x2bdc546291f4b1", 0, 0, ((LONGLONG)0x2bdc54 << 32) | 0x6291f4b1 },
      { "+0x44f4", 0, 0, 0x44f4 },
      { "-0x44fd", 0, 0, 0x44fd },
      { "+ 88987", 0, 0, 0 },
      { "+0x44f4", 0, 0, 0x44f4 },
      { "-0x44fd", 0, 0, 0x44fd },
      { "+ 88987", 0, 0, 0 },
@@ -107,6 +115,8 @@ typedef struct tagStrFormatSizeResult
   LONGLONG value;
   const char* byte_size_64;
   const char* kb_size;
   LONGLONG value;
   const char* byte_size_64;
   const char* kb_size;
+  int kb_size_broken;
+  const char* kb_size2;
 } StrFormatSizeResult;
 
 
 } StrFormatSizeResult;
 
 
@@ -117,19 +127,19 @@ static const StrFormatSizeResult StrFormatSize_results[] = {
   { 10191, "9.95 KB", "10 KB"},
   { 100353, "98.0 KB", "99 KB"},
   { 1022286, "998 KB", "999 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"},
+  { 1046862, "0.99 MB", "1,023 KB", 1, "1023 KB"},
+  { 1048574619, "999 MB", "1,023,999 KB", 1, "1023999 KB"},
+  { 1073741775, "0.99 GB", "1,048,576 KB", 1, "1048576 KB"},
+  { ((LONGLONG)0x000000f9 << 32) | 0xfffff94e, "999 GB", "1,048,575,999 KB", 1, "1048575999 KB"},
+  { ((LONGLONG)0x000000ff << 32) | 0xfffffa9b, "0.99 TB", "1,073,741,823 KB", 1, "1073741823 KB"},
+  { ((LONGLONG)0x0003e7ff << 32) | 0xfffffa9b, "999 TB", "1,073,741,823,999 KB", 1, "4294967295 KB"},
+  { ((LONGLONG)0x0003ffff << 32) | 0xfffffbe8, "0.99 PB", "1,099,511,627,775 KB", 1, "4294967295 KB"},
+  { ((LONGLONG)0x0f9fffff << 32) | 0xfffffd35, "999 PB", "1,099,511,627,776,000 KB", 1, "0 KB"},
+  { ((LONGLONG)0x0fffffff << 32) | 0xfffffa9b, "0.99 EB", "1,125,899,906,842,623 KB", 1, "4294967295 KB"},
   { 0, NULL, NULL }
 };
 
   { 0, NULL, NULL }
 };
 
-/* StrFormatByteSize64/StrFormatKBSize results */
+/* StrFromTimeIntervalA/StrFromTimeIntervalW results */
 typedef struct tagStrFromTimeIntervalResult
 {
   DWORD ms;
 typedef struct tagStrFromTimeIntervalResult
 {
   DWORD ms;
@@ -191,6 +201,39 @@ static const StrFromTimeIntervalResult StrFromTimeInterval_results[] = {
   { 0, 0, NULL }
 };
 
   { 0, 0, NULL }
 };
 
+
+/* Returns true if the user interface is in English. Note that this does not
+ * presume of the formatting of dates, numbers, etc.
+ */
+static BOOL is_lang_english(void)
+{
+    static HMODULE hkernel32 = NULL;
+    static LANGID (WINAPI *pGetThreadUILanguage)(void) = NULL;
+    static LANGID (WINAPI *pGetUserDefaultUILanguage)(void) = NULL;
+
+    if (!hkernel32)
+    {
+        hkernel32 = GetModuleHandleA("kernel32.dll");
+        pGetThreadUILanguage = (void*)GetProcAddress(hkernel32, "GetThreadUILanguage");
+        pGetUserDefaultUILanguage = (void*)GetProcAddress(hkernel32, "GetUserDefaultUILanguage");
+    }
+    if (pGetThreadUILanguage)
+        return PRIMARYLANGID(pGetThreadUILanguage()) == LANG_ENGLISH;
+    if (pGetUserDefaultUILanguage)
+        return PRIMARYLANGID(pGetUserDefaultUILanguage()) == LANG_ENGLISH;
+
+    return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
+}
+
+/* Returns true if the dates, numbers, etc. are formatted using English
+ * conventions.
+ */
+static BOOL is_locale_english(void)
+{
+    /* Surprisingly GetThreadLocale() is irrelevant here */
+    return PRIMARYLANGID(GetUserDefaultLangID()) == LANG_ENGLISH;
+}
+
 static void test_StrChrA(void)
 {
   char string[129];
 static void test_StrChrA(void)
 {
   char string[129];
@@ -364,16 +407,28 @@ static void test_StrCpyW(void)
   WCHAR szSrc[256];
   WCHAR szBuff[256];
   const StrFormatSizeResult* result = StrFormatSize_results;
   WCHAR szSrc[256];
   WCHAR szBuff[256];
   const StrFormatSizeResult* result = StrFormatSize_results;
-
+  LPWSTR lpRes;
 
   while(result->value)
   {
     MultiByteToWideChar(0,0,result->byte_size_64,-1,szSrc,sizeof(szSrc)/sizeof(WCHAR));
 
 
   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);
+    lpRes = StrCpyW(szBuff, szSrc);
+    ok(!StrCmpW(szSrc, szBuff) && lpRes == szBuff, "Copied string %s wrong\n", result->byte_size_64);
     result++;
   }
     result++;
   }
+
+  /* this test crashes on win2k SP4 */
+  /*lpRes = StrCpyW(szBuff, NULL);*/
+  /*ok(lpRes == szBuff, "Wrong return value: got %p expected %p\n", lpRes, szBuff);*/
+
+  /* this test crashes on win2k SP4 */
+  /*lpRes = StrCpyW(NULL, szSrc);*/
+  /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
+
+  /* this test crashes on win2k SP4 */
+  /*lpRes = StrCpyW(NULL, NULL);*/
+  /*ok(lpRes == NULL, "Wrong return value: got %p expected NULL\n", lpRes);*/
 }
 
 static void test_StrChrNW(void)
 }
 
 static void test_StrChrNW(void)
@@ -441,7 +496,7 @@ static void test_StrToIntExA(void)
     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
        result->string);
     if (bRet)
     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",
+      ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n",
          result->string, return_val);
     result++;
   }
          result->string, return_val);
     result++;
   }
@@ -454,7 +509,7 @@ static void test_StrToIntExA(void)
     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
        result->string);
     if (bRet)
     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",
+      ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n",
          result->string, return_val);
     result++;
   }
          result->string, return_val);
     result++;
   }
@@ -475,7 +530,7 @@ static void test_StrToIntExW(void)
     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
        result->string);
     if (bRet)
     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",
+      ok(return_val == (int)result->str_to_int64_ex, "converted '%s' wrong (%d)\n",
          result->string, return_val);
     result++;
   }
          result->string, return_val);
     result++;
   }
@@ -489,12 +544,91 @@ static void test_StrToIntExW(void)
     ok(!bRet || return_val != -1, "No result returned from '%s'\n",
        result->string);
     if (bRet)
     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",
+      ok(return_val == (int)result->str_to_int64_hex, "converted '%s' wrong (%d)\n",
          result->string, return_val);
     result++;
   }
 }
 
          result->string, return_val);
     result++;
   }
 }
 
+static void test_StrToInt64ExA(void)
+{
+  const StrToIntResult *result = StrToInt_results;
+  LONGLONG return_val;
+  BOOL bRet;
+
+  if (!pStrToInt64ExA)
+  {
+    win_skip("StrToInt64ExA() is not available\n");
+    return;
+  }
+
+  while (result->string)
+  {
+    return_val = -1;
+    bRet = pStrToInt64ExA(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_int64_ex, "converted '%s' wrong (%08x%08x)\n",
+         result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
+    result++;
+  }
+
+  result = StrToInt_results;
+  while (result->string)
+  {
+    return_val = -1;
+    bRet = pStrToInt64ExA(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_int64_hex, "converted '%s' wrong (%08x%08x)\n",
+         result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
+    result++;
+  }
+}
+
+static void test_StrToInt64ExW(void)
+{
+  WCHAR szBuff[256];
+  const StrToIntResult *result = StrToInt_results;
+  LONGLONG return_val;
+  BOOL bRet;
+
+  if (!pStrToInt64ExW)
+  {
+    win_skip("StrToInt64ExW() is not available\n");
+    return;
+  }
+
+  while (result->string)
+  {
+    return_val = -1;
+    MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
+    bRet = pStrToInt64ExW(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_int64_ex, "converted '%s' wrong (%08x%08x)\n",
+         result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
+    result++;
+  }
+
+  result = StrToInt_results;
+  while (result->string)
+  {
+    return_val = -1;
+    MultiByteToWideChar(0,0,result->string,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR));
+    bRet = pStrToInt64ExW(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_int64_hex, "converted '%s' wrong (%08x%08x)\n",
+         result->string, (DWORD)(return_val >> 32), (DWORD)return_val);
+    result++;
+  }
+}
+
 static void test_StrDupA(void)
 {
   LPSTR lpszStr;
 static void test_StrDupA(void)
 {
   LPSTR lpszStr;
@@ -560,8 +694,8 @@ static void test_StrFormatKBSizeW(void)
   {
     pStrFormatKBSizeW(result->value, szBuffW, 256);
     WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0);
   {
     pStrFormatKBSizeW(result->value, szBuffW, 256);
     WideCharToMultiByte(0,0,szBuffW,-1,szBuff,sizeof(szBuff)/sizeof(WCHAR),0,0);
-    ok(!strcmp(result->kb_size, szBuff),
-        "Formatted %x%08x wrong: got %s, expected %s\n",
+
+    ok(!strcmp(result->kb_size, szBuff), "Formatted %x%08x wrong: got %s, expected %s\n",
        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
     result++;
   }
        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
     result++;
   }
@@ -582,7 +716,10 @@ static void test_StrFormatKBSizeA(void)
   {
     pStrFormatKBSizeA(result->value, szBuff, 256);
 
   {
     pStrFormatKBSizeA(result->value, szBuff, 256);
 
-    ok(!strcmp(result->kb_size, szBuff),
+    /* shlwapi on Win98 SE does not appear to apply delimiters to the output
+     * and does not correctly handle extremely large values. */
+    ok(!strcmp(result->kb_size, szBuff) ||
+      (result->kb_size_broken && !strcmp(result->kb_size2, szBuff)),
         "Formatted %x%08x wrong: got %s, expected %s\n",
        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
     result++;
         "Formatted %x%08x wrong: got %s, expected %s\n",
        (LONG)(result->value >> 32), (LONG)result->value, szBuff, result->kb_size);
     result++;
@@ -598,8 +735,8 @@ static void test_StrFromTimeIntervalA(void)
   {
     StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits);
 
   {
     StrFromTimeIntervalA(szBuff, 256, result->ms, result->digits);
 
-    ok(!strcmp(result->time_interval, szBuff), "Formatted %d %d wrong\n",
-       result->ms, result->digits);
+    ok(!strcmp(result->time_interval, szBuff), "Formatted %d %d wrong: %s\n",
+       result->ms, result->digits, szBuff);
     result++;
   }
 }
     result++;
   }
 }
@@ -772,7 +909,7 @@ static void test_StrRStrI(void)
     static const WCHAR wszPattern4[] = {'a','b',0};
     LPWSTR retW;
     LPSTR retA;
     static const WCHAR wszPattern4[] = {'a','b',0};
     LPWSTR retW;
     LPSTR retA;
-    
+
     check_strrstri(A, szTest, 4, "A", szTest+1);
     check_strrstri(A, szTest, 4, "aX", szTest+1);
     check_strrstri(A, szTest, 4, "Ay", NULL);
     check_strrstri(A, szTest, 4, "A", szTest+1);
     check_strrstri(A, szTest, 4, "aX", szTest+1);
     check_strrstri(A, szTest, 4, "Ay", NULL);
@@ -804,6 +941,12 @@ static void test_SHAnsiToAnsi(void)
     return;
   }
 
     return;
   }
 
+  if (pSHAnsiToAnsi == (void *)pStrPBrkW)
+  {
+    win_skip("Ordinal 345 corresponds to StrPBrkW, skipping SHAnsiToAnsi tests\n");
+    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)),
   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)),
@@ -825,6 +968,12 @@ static void test_SHUnicodeToUnicode(void)
     return;
   }
 
     return;
   }
 
+  if (pSHUnicodeToUnicode == (void *)pStrRChrA)
+  {
+    win_skip("Ordinal 346 corresponds to StrRChrA, skipping SHUnicodeToUnicode tests\n");
+    return;
+  }
+
   memcpy(dest, lpInit, sizeof(lpInit));
   dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0]));
   ok(dwRet == 6 && !memcmp(dest, lpRes, sizeof(dest)),
   memcpy(dest, lpInit, sizeof(lpInit));
   dwRet = pSHUnicodeToUnicode(lpSrc, dest, sizeof(dest)/sizeof(dest[0]));
   ok(dwRet == 6 && !memcmp(dest, lpRes, sizeof(dest)),
@@ -932,7 +1081,7 @@ if (0)
     {
         memset(buf, 0xbf, sizeof(buf));
         ret = pwnsprintfA(buf, 10, "%s", str1);
     {
         memset(buf, 0xbf, sizeof(buf));
         ret = pwnsprintfA(buf, 10, "%s", str1);
-        ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wsnprintfA return %d, expected 9 or -1\n", ret);
+        ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfA return %d, expected 9 or -1\n", ret);
         expect_eq(buf[9], 0, CHAR, "%x");
         expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x");
     }
         expect_eq(buf[9], 0, CHAR, "%x");
         expect_eq(buf[10], (CHAR)0xbf, CHAR, "%x");
     }
@@ -943,7 +1092,7 @@ if (0)
     {
         memset(wbuf, 0xbf, sizeof(wbuf));
         ret = pwnsprintfW(wbuf, 10, fmt, wstr1);
     {
         memset(wbuf, 0xbf, sizeof(wbuf));
         ret = pwnsprintfW(wbuf, 10, fmt, wstr1);
-        ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wsnprintfW return %d, expected 9 or -1\n", ret);
+        ok(broken(ret == 9) || ret == -1 /* Vista */, "Unexpected wnsprintfW return %d, expected 9 or -1\n", ret);
         expect_eq(wbuf[9], 0, WCHAR, "%x");
         expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
     }
         expect_eq(wbuf[9], 0, WCHAR, "%x");
         expect_eq(wbuf[10], (WCHAR)0xbfbf, WCHAR, "%x");
     }
@@ -951,6 +1100,387 @@ if (0)
         win_skip("wnsprintfW() is not available\n");
 }
 
         win_skip("wnsprintfW() is not available\n");
 }
 
+static void test_StrStrA(void)
+{
+    static const char *deadbeefA = "DeAdBeEf";
+
+    const struct
+    {
+        const char *search;
+        const char *expect;
+    } StrStrA_cases[] =
+    {
+        {"", NULL},
+        {"DeAd", deadbeefA},
+        {"dead", NULL},
+        {"AdBe", deadbeefA + 2},
+        {"adbe", NULL},
+        {"BeEf", deadbeefA + 4},
+        {"beef", NULL},
+    };
+
+    LPSTR ret;
+    int i;
+
+    /* Tests crash on Win2k */
+    if (0)
+    {
+        ret = StrStrA(NULL, NULL);
+        ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
+
+        ret = StrStrA(NULL, "");
+        ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
+
+        ret = StrStrA("", NULL);
+        ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
+    }
+
+    ret = StrStrA("", "");
+    ok(!ret, "Expected StrStrA to return NULL, got %p\n", ret);
+
+    for (i = 0; i < sizeof(StrStrA_cases)/sizeof(StrStrA_cases[0]); i++)
+    {
+        ret = StrStrA(deadbeefA, StrStrA_cases[i].search);
+        ok(ret == StrStrA_cases[i].expect,
+           "[%d] Expected StrStrA to return %p, got %p\n",
+           i, StrStrA_cases[i].expect, ret);
+    }
+}
+
+static void test_StrStrW(void)
+{
+    static const WCHAR emptyW[] = {0};
+    static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
+    static const WCHAR deadW[] = {'D','e','A','d',0};
+    static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
+    static const WCHAR adbeW[] = {'A','d','B','e',0};
+    static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
+    static const WCHAR beefW[] = {'B','e','E','f',0};
+    static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
+
+    const struct
+    {
+        const WCHAR *search;
+        const WCHAR *expect;
+    } StrStrW_cases[] =
+    {
+        {emptyW, NULL},
+        {deadW, deadbeefW},
+        {dead_lowerW, NULL},
+        {adbeW, deadbeefW + 2},
+        {adbe_lowerW, NULL},
+        {beefW, deadbeefW + 4},
+        {beef_lowerW, NULL},
+    };
+
+    LPWSTR ret;
+    int i;
+
+    /* Tests crash on Win2k */
+    if (0)
+    {
+        ret = StrStrW(NULL, NULL);
+        ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
+
+        ret = StrStrW(NULL, emptyW);
+        ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
+
+        ret = StrStrW(emptyW, NULL);
+        ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
+    }
+
+    ret = StrStrW(emptyW, emptyW);
+    ok(!ret, "Expected StrStrW to return NULL, got %p\n", ret);
+
+    for (i = 0; i < sizeof(StrStrW_cases)/sizeof(StrStrW_cases[0]); i++)
+    {
+        ret = StrStrW(deadbeefW, StrStrW_cases[i].search);
+        ok(ret == StrStrW_cases[i].expect,
+           "[%d] Expected StrStrW to return %p, got %p\n",
+           i, StrStrW_cases[i].expect, ret);
+    }
+}
+
+static void test_StrStrIA(void)
+{
+    static const char *deadbeefA = "DeAdBeEf";
+
+    const struct
+    {
+        const char *search;
+        const char *expect;
+    } StrStrIA_cases[] =
+    {
+        {"", NULL},
+        {"DeAd", deadbeefA},
+        {"dead", deadbeefA},
+        {"AdBe", deadbeefA + 2},
+        {"adbe", deadbeefA + 2},
+        {"BeEf", deadbeefA + 4},
+        {"beef", deadbeefA + 4},
+        {"cafe", NULL},
+    };
+
+    LPSTR ret;
+    int i;
+
+    /* Tests crash on Win2k */
+    if (0)
+    {
+        ret = StrStrIA(NULL, NULL);
+        ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
+
+        ret = StrStrIA(NULL, "");
+        ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
+
+        ret = StrStrIA("", NULL);
+        ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
+    }
+
+    ret = StrStrIA("", "");
+    ok(!ret, "Expected StrStrIA to return NULL, got %p\n", ret);
+
+    for (i = 0; i < sizeof(StrStrIA_cases)/sizeof(StrStrIA_cases[0]); i++)
+    {
+        ret = StrStrIA(deadbeefA, StrStrIA_cases[i].search);
+        ok(ret == StrStrIA_cases[i].expect,
+           "[%d] Expected StrStrIA to return %p, got %p\n",
+           i, StrStrIA_cases[i].expect, ret);
+    }
+}
+
+static void test_StrStrIW(void)
+{
+    static const WCHAR emptyW[] = {0};
+    static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
+    static const WCHAR deadW[] = {'D','e','A','d',0};
+    static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
+    static const WCHAR adbeW[] = {'A','d','B','e',0};
+    static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
+    static const WCHAR beefW[] = {'B','e','E','f',0};
+    static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
+    static const WCHAR cafeW[] = {'c','a','f','e',0};
+
+    const struct
+    {
+        const WCHAR *search;
+        const WCHAR *expect;
+    } StrStrIW_cases[] =
+    {
+        {emptyW, NULL},
+        {deadW, deadbeefW},
+        {dead_lowerW, deadbeefW},
+        {adbeW, deadbeefW + 2},
+        {adbe_lowerW, deadbeefW + 2},
+        {beefW, deadbeefW + 4},
+        {beef_lowerW, deadbeefW + 4},
+        {cafeW, NULL},
+    };
+
+    LPWSTR ret;
+    int i;
+
+    /* Tests crash on Win2k */
+    if (0)
+    {
+        ret = StrStrIW(NULL, NULL);
+        ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
+
+        ret = StrStrIW(NULL, emptyW);
+        ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
+
+        ret = StrStrIW(emptyW, NULL);
+        ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
+    }
+
+    ret = StrStrIW(emptyW, emptyW);
+    ok(!ret, "Expected StrStrIW to return NULL, got %p\n", ret);
+
+    for (i = 0; i < sizeof(StrStrIW_cases)/sizeof(StrStrIW_cases[0]); i++)
+    {
+        ret = StrStrIW(deadbeefW, StrStrIW_cases[i].search);
+        ok(ret == StrStrIW_cases[i].expect,
+           "[%d] Expected StrStrIW to return %p, got %p\n",
+           i, StrStrIW_cases[i].expect, ret);
+    }
+}
+
+static void test_StrStrNW(void)
+{
+    static const WCHAR emptyW[] = {0};
+    static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
+    static const WCHAR deadW[] = {'D','e','A','d',0};
+    static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
+    static const WCHAR adbeW[] = {'A','d','B','e',0};
+    static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
+    static const WCHAR beefW[] = {'B','e','E','f',0};
+    static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
+
+    const struct
+    {
+        const WCHAR *search;
+        const UINT count;
+        const WCHAR *expect;
+    } StrStrNW_cases[] =
+    {
+        {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
+        {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
+        {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
+        {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
+        {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
+        {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
+        {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
+        {beefW, 0, NULL},
+        {beefW, 1, NULL},
+        {beefW, 2, NULL},
+        {beefW, 3, NULL},
+        {beefW, 4, NULL},
+        {beefW, 5, deadbeefW + 4},
+        {beefW, 6, deadbeefW + 4},
+        {beefW, 7, deadbeefW + 4},
+        {beefW, 8, deadbeefW + 4},
+        {beefW, 9, deadbeefW + 4},
+    };
+
+    LPWSTR ret;
+    UINT i;
+
+    if (!pStrStrNW)
+    {
+        win_skip("StrStrNW() is not available\n");
+        return;
+    }
+
+    ret = pStrStrNW(NULL, NULL, 0);
+    ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNW(NULL, NULL, 10);
+    ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNW(NULL, emptyW, 10);
+    ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNW(emptyW, NULL, 10);
+    ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNW(emptyW, emptyW, 10);
+    ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
+
+    for (i = 0; i < sizeof(StrStrNW_cases)/sizeof(StrStrNW_cases[0]); i++)
+    {
+        ret = pStrStrNW(deadbeefW, StrStrNW_cases[i].search, StrStrNW_cases[i].count);
+        ok(ret == StrStrNW_cases[i].expect,
+           "[%d] Expected StrStrNW to return %p, got %p\n",
+           i, StrStrNW_cases[i].expect, ret);
+    }
+
+    /* StrStrNW accepts counts larger than the search string length but rejects
+     * counts larger than around 2G. The limit seems to change based on the
+     * caller executable itself. */
+    ret = pStrStrNW(deadbeefW, beefW, 100);
+    ok(ret == deadbeefW + 4, "Expected StrStrNW to return deadbeefW + 4, got %p\n", ret);
+
+    if (0)
+    {
+        ret = pStrStrNW(deadbeefW, beefW, ~0U);
+        ok(!ret, "Expected StrStrNW to return NULL, got %p\n", ret);
+    }
+}
+
+static void test_StrStrNIW(void)
+{
+    static const WCHAR emptyW[] = {0};
+    static const WCHAR deadbeefW[] = {'D','e','A','d','B','e','E','f',0};
+    static const WCHAR deadW[] = {'D','e','A','d',0};
+    static const WCHAR dead_lowerW[] = {'d','e','a','d',0};
+    static const WCHAR adbeW[] = {'A','d','B','e',0};
+    static const WCHAR adbe_lowerW[] = {'a','d','b','e',0};
+    static const WCHAR beefW[] = {'B','e','E','f',0};
+    static const WCHAR beef_lowerW[] = {'b','e','e','f',0};
+    static const WCHAR cafeW[] = {'c','a','f','e',0};
+
+    const struct
+    {
+        const WCHAR *search;
+        const UINT count;
+        const WCHAR *expect;
+    } StrStrNIW_cases[] =
+    {
+        {emptyW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
+        {deadW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
+        {dead_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW},
+        {adbeW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
+        {adbe_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 2},
+        {beefW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
+        {beef_lowerW, sizeof(deadbeefW)/sizeof(WCHAR), deadbeefW + 4},
+        {cafeW, sizeof(deadbeefW)/sizeof(WCHAR), NULL},
+        {beefW, 0, NULL},
+        {beefW, 1, NULL},
+        {beefW, 2, NULL},
+        {beefW, 3, NULL},
+        {beefW, 4, NULL},
+        {beefW, 5, deadbeefW + 4},
+        {beefW, 6, deadbeefW + 4},
+        {beefW, 7, deadbeefW + 4},
+        {beefW, 8, deadbeefW + 4},
+        {beefW, 9, deadbeefW + 4},
+        {beef_lowerW, 0, NULL},
+        {beef_lowerW, 1, NULL},
+        {beef_lowerW, 2, NULL},
+        {beef_lowerW, 3, NULL},
+        {beef_lowerW, 4, NULL},
+        {beef_lowerW, 5, deadbeefW + 4},
+        {beef_lowerW, 6, deadbeefW + 4},
+        {beef_lowerW, 7, deadbeefW + 4},
+        {beef_lowerW, 8, deadbeefW + 4},
+        {beef_lowerW, 9, deadbeefW + 4},
+    };
+
+    LPWSTR ret;
+    UINT i;
+
+    if (!pStrStrNIW)
+    {
+        win_skip("StrStrNIW() is not available\n");
+        return;
+    }
+
+    ret = pStrStrNIW(NULL, NULL, 0);
+    ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNIW(NULL, NULL, 10);
+    ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNIW(NULL, emptyW, 10);
+    ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNIW(emptyW, NULL, 10);
+    ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
+
+    ret = pStrStrNIW(emptyW, emptyW, 10);
+    ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
+
+    for (i = 0; i < sizeof(StrStrNIW_cases)/sizeof(StrStrNIW_cases[0]); i++)
+    {
+        ret = pStrStrNIW(deadbeefW, StrStrNIW_cases[i].search, StrStrNIW_cases[i].count);
+        ok(ret == StrStrNIW_cases[i].expect,
+           "[%d] Expected StrStrNIW to return %p, got %p\n",
+           i, StrStrNIW_cases[i].expect, ret);
+    }
+
+    /* StrStrNIW accepts counts larger than the search string length but rejects
+     * counts larger than around 2G. The limit seems to change based on the
+     * caller executable itself. */
+    ret = pStrStrNIW(deadbeefW, beefW, 100);
+    ok(ret == deadbeefW + 4, "Expected StrStrNIW to return deadbeefW + 4, got %p\n", ret);
+
+    if (0)
+    {
+        ret = pStrStrNIW(deadbeefW, beefW, ~0U);
+        ok(!ret, "Expected StrStrNIW to return NULL, got %p\n", ret);
+    }
+}
+
 START_TEST(string)
 {
   HMODULE hShlwapi;
 START_TEST(string)
 {
   HMODULE hShlwapi;
@@ -978,11 +1508,17 @@ START_TEST(string)
   pStrFormatKBSizeW = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeW");
   pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA");
   pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW");
   pStrFormatKBSizeW = (void *)GetProcAddress(hShlwapi, "StrFormatKBSizeW");
   pStrIsIntlEqualA = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualA");
   pStrIsIntlEqualW = (void *)GetProcAddress(hShlwapi, "StrIsIntlEqualW");
+  pStrPBrkW = (void *)GetProcAddress(hShlwapi, "StrPBrkW");
+  pStrRChrA = (void *)GetProcAddress(hShlwapi, "StrRChrA");
   pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR");
   pStrRetToBufA = (void *)GetProcAddress(hShlwapi, "StrRetToBufA");
   pStrRetToBufW = (void *)GetProcAddress(hShlwapi, "StrRetToBufW");
   pStrRetToBSTR = (void *)GetProcAddress(hShlwapi, "StrRetToBSTR");
   pStrRetToBufA = (void *)GetProcAddress(hShlwapi, "StrRetToBufA");
   pStrRetToBufW = (void *)GetProcAddress(hShlwapi, "StrRetToBufW");
+  pStrStrNW = (void *)GetProcAddress(hShlwapi, "StrStrNW");
+  pStrStrNIW = (void *)GetProcAddress(hShlwapi, "StrStrNIW");
   pwnsprintfA = (void *)GetProcAddress(hShlwapi, "wnsprintfA");
   pwnsprintfW = (void *)GetProcAddress(hShlwapi, "wnsprintfW");
   pwnsprintfA = (void *)GetProcAddress(hShlwapi, "wnsprintfA");
   pwnsprintfW = (void *)GetProcAddress(hShlwapi, "wnsprintfW");
+  pStrToInt64ExA = (void *)GetProcAddress(hShlwapi, "StrToInt64ExA");
+  pStrToInt64ExW = (void *)GetProcAddress(hShlwapi, "StrToInt64ExW");
 
   test_StrChrA();
   test_StrChrW();
 
   test_StrChrA();
   test_StrChrW();
@@ -996,20 +1532,23 @@ START_TEST(string)
   test_StrToIntW();
   test_StrToIntExA();
   test_StrToIntExW();
   test_StrToIntW();
   test_StrToIntExA();
   test_StrToIntExW();
+  test_StrToInt64ExA();
+  test_StrToInt64ExW();
   test_StrDupA();
   test_StrDupA();
-  if (lstrcmp(thousandDelim, ",")==0 && lstrcmp(decimalDelim, ".")==0)
+
+  /* language-dependent test */
+  if (is_lang_english() && is_locale_english())
   {
   {
-    /* these tests are locale-dependent */
     test_StrFormatByteSize64A();
     test_StrFormatKBSizeA();
     test_StrFormatKBSizeW();
   }
     test_StrFormatByteSize64A();
     test_StrFormatKBSizeA();
     test_StrFormatKBSizeW();
   }
-
-  /* language-dependent test */
-  if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH)
-    trace("Skipping StrFromTimeInterval test for non English language\n");
   else
   else
+    skip("An English UI and locale is required for the StrFormat*Size tests\n");
+  if (is_lang_english())
     test_StrFromTimeIntervalA();
     test_StrFromTimeIntervalA();
+  else
+    skip("An English UI is required for the StrFromTimeInterval tests\n");
 
   test_StrCmpA();
   test_StrCmpW();
 
   test_StrCmpA();
   test_StrCmpW();
@@ -1020,6 +1559,12 @@ START_TEST(string)
   test_SHAnsiToAnsi();
   test_SHUnicodeToUnicode();
   test_StrXXX_overflows();
   test_SHAnsiToAnsi();
   test_SHUnicodeToUnicode();
   test_StrXXX_overflows();
+  test_StrStrA();
+  test_StrStrW();
+  test_StrStrIA();
+  test_StrStrIW();
+  test_StrStrNW();
+  test_StrStrNIW();
 
   CoUninitialize();
 }
 
   CoUninitialize();
 }
index 24d5be1..d4a1787 100644 (file)
@@ -21,6 +21,8 @@
 #include <stdarg.h>
 
 #define COBJMACROS
 #include <stdarg.h>
 
 #define COBJMACROS
+#define CONST_VTABLE
+
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winerror.h"
@@ -37,13 +39,18 @@ static DWORD AddRef_called;
 
 typedef struct
 {
 
 typedef struct
 {
-  const IUnknownVtbl* lpVtbl;
+  IUnknown IUnknown_iface;
   LONG  *ref;
 } threadref;
 
   LONG  *ref;
 } threadref;
 
+static inline threadref *impl_from_IUnknown(IUnknown *iface)
+{
+  return CONTAINING_RECORD(iface, threadref, IUnknown_iface);
+}
+
 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj)
 {
 static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPVOID *ppvObj)
 {
-    threadref * This = (threadref *)iface;
+    threadref * This = impl_from_IUnknown(iface);
 
     trace("unexpected QueryInterface(%p, %p, %p) called\n", This, riid, ppvObj);
     *ppvObj = NULL;
 
     trace("unexpected QueryInterface(%p, %p, %p) called\n", This, riid, ppvObj);
     *ppvObj = NULL;
@@ -52,7 +59,7 @@ static HRESULT WINAPI threadref_QueryInterface(IUnknown *iface, REFIID riid, LPV
 
 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
 {
 
 static ULONG WINAPI threadref_AddRef(IUnknown *iface)
 {
-    threadref * This = (threadref *)iface;
+    threadref * This = impl_from_IUnknown(iface);
 
     AddRef_called++;
     return InterlockedIncrement(This->ref);
 
     AddRef_called++;
     return InterlockedIncrement(This->ref);
@@ -60,7 +67,7 @@ static ULONG WINAPI threadref_AddRef(IUnknown *iface)
 
 static ULONG WINAPI threadref_Release(IUnknown *iface)
 {
 
 static ULONG WINAPI threadref_Release(IUnknown *iface)
 {
-    threadref * This = (threadref *)iface;
+    threadref * This = impl_from_IUnknown(iface);
 
     trace("unexpected Release(%p) called\n", This);
     return InterlockedDecrement(This->ref);
 
     trace("unexpected Release(%p) called\n", This);
     return InterlockedDecrement(This->ref);
@@ -76,7 +83,7 @@ static const IUnknownVtbl threadref_vt =
 
 static void init_threadref(threadref* iface, LONG *refcount)
 {
 
 static void init_threadref(threadref* iface, LONG *refcount)
 {
-  iface->lpVtbl = &threadref_vt;
+  iface->IUnknown_iface.lpVtbl = &threadref_vt;
   iface->ref = refcount;
 }
 
   iface->ref = refcount;
 }
 
@@ -184,7 +191,7 @@ static void test_SHGetThreadRef(void)
 
     if (0) {
         /* this crash on Windows */
 
     if (0) {
         /* this crash on Windows */
-        hr = pSHGetThreadRef(NULL);
+        pSHGetThreadRef(NULL);
     }
 }
 
     }
 }
 
@@ -209,7 +216,7 @@ static void test_SHSetThreadRef(void)
     init_threadref(&ref, &refcount);
     AddRef_called = 0;
     refcount = 1;
     init_threadref(&ref, &refcount);
     AddRef_called = 0;
     refcount = 1;
-    hr = pSHSetThreadRef( (IUnknown *)&ref);
+    hr = pSHSetThreadRef(&ref.IUnknown_iface);
     ok( (hr == S_OK) && (refcount == 1) && (!AddRef_called),
         "got 0x%x with %d, %d (expected S_OK with 1, 0)\n",
         hr, refcount, AddRef_called);
     ok( (hr == S_OK) && (refcount == 1) && (!AddRef_called),
         "got 0x%x with %d, %d (expected S_OK with 1, 0)\n",
         hr, refcount, AddRef_called);
@@ -219,7 +226,7 @@ static void test_SHSetThreadRef(void)
     refcount = 1;
     punk = NULL;
     hr = pSHGetThreadRef(&punk);
     refcount = 1;
     punk = NULL;
     hr = pSHGetThreadRef(&punk);
-    ok( (hr == S_OK) && (punk == (IUnknown *)&ref) && (refcount == 2) && (AddRef_called == 1),
+    ok( (hr == S_OK) && (punk == &ref.IUnknown_iface) && (refcount == 2) && (AddRef_called == 1),
         "got 0x%x and %p with %d, %d (expected S_OK and %p with 2, 1)\n",
         hr, punk, refcount, AddRef_called, &ref);
 
         "got 0x%x and %p with %d, %d (expected S_OK and %p with 2, 1)\n",
         hr, punk, refcount, AddRef_called, &ref);
 
index 8a8f68a..fbc3601 100644 (file)
@@ -56,6 +56,8 @@ static HRESULT (WINAPI *pHashData)(LPBYTE, DWORD, LPBYTE, DWORD);
 static const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923";
 static const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923";
 static const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y";
 static const char* TEST_URL_1 = "http://www.winehq.org/tests?date=10/10/1923";
 static const char* TEST_URL_2 = "http://localhost:8080/tests%2e.html?date=Mon%2010/10/1923";
 static const char* TEST_URL_3 = "http://foo:bar@localhost:21/internal.php?query=x&return=y";
+static const char* TEST_URL_4 = "http://foo:bar@google.*.com:21/internal.php?query=x&return=y";
+
 static const WCHAR winehqW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/',0};
 static const  CHAR winehqA[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/',0};
 
 static const WCHAR winehqW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/',0};
 static const  CHAR winehqA[] = {'h','t','t','p',':','/','/','w','w','w','.','w','i','n','e','h','q','.','o','r','g','/',0};
 
@@ -83,9 +85,18 @@ static const TEST_URL_APPLY TEST_APPLY[] = {
     {"winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"},
     {"winehq.org", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
     {"winehq.org", URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"},
     {"winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"},
     {"winehq.org", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
     {"winehq.org", URL_APPLY_DEFAULT, S_OK, 17, "http://winehq.org"},
+    {"http://www.winehq.org", URL_APPLY_GUESSSCHEME , S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
+    {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_FORCEAPPLY, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
+    {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_FORCEAPPLY | URL_APPLY_DEFAULT, S_OK, 28, "http://http://www.winehq.org"},
+    {"http://www.winehq.org", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
     {"", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 7, "http://"},
     {"", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
     {"", URL_APPLY_GUESSSCHEME | URL_APPLY_DEFAULT, S_OK, 7, "http://"},
     {"", URL_APPLY_GUESSSCHEME, S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
-    {"", URL_APPLY_DEFAULT, S_OK, 7, "http://"}
+    {"", URL_APPLY_DEFAULT, S_OK, 7, "http://"},
+    {"u:\\windows", URL_APPLY_GUESSFILE | URL_APPLY_DEFAULT, S_OK, 18, "file:///u:/windows"},
+    {"u:\\windows", URL_APPLY_GUESSFILE, S_OK, 18, "file:///u:/windows"},
+    {"u:\\windows", URL_APPLY_DEFAULT, S_OK, 17, "http://u:\\windows"},
+    {"file:///c:/windows", URL_APPLY_GUESSFILE , S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
+    {"aa:\\windows", URL_APPLY_GUESSFILE , S_FALSE, TEST_APPLY_MAX_LENGTH, untouchedA},
 };
 
 /* ################ */
 };
 
 /* ################ */
@@ -100,6 +111,8 @@ typedef struct _TEST_URL_CANONICALIZE {
 
 static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/", TRUE},
 
 static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"http://www.winehq.org/tests/../tests/../..", 0, S_OK, "http://www.winehq.org/", TRUE},
+    {"http://www.winehq.org/..", 0, S_OK, "http://www.winehq.org/..", FALSE},
+    {"http://www.winehq.org/tests/tests2/../../tests", 0, S_OK, "http://www.winehq.org/tests", FALSE},
     {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests", FALSE},
     {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE},
     {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE},
     {"http://www.winehq.org/tests/../tests", 0, S_OK, "http://www.winehq.org/tests", FALSE},
     {"http://www.winehq.org/tests\n", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE},
     {"http://www.winehq.org/tests\r", URL_WININET_COMPATIBILITY|URL_ESCAPE_SPACES_ONLY|URL_ESCAPE_UNSAFE, S_OK, "http://www.winehq.org/tests", FALSE},
@@ -112,6 +125,7 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/", FALSE},
     {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE},
     {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE},
     {"http://www.winehq.org/tests/../", 0, S_OK, "http://www.winehq.org/", FALSE},
     {"http://www.winehq.org/tests/..?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE},
     {"http://www.winehq.org/tests/../?query=x&return=y", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE},
+    {"\tht\ttp\t://www\t.w\tineh\t\tq.or\tg\t/\ttests/..\t?\tquer\ty=x\t\t&re\tturn=y\t\t", 0, S_OK, "http://www.winehq.org/?query=x&return=y", FALSE},
     {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example", FALSE},
     {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE},
     {"http://www.winehq.org/tests\\../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE},
     {"http://www.winehq.org/tests/..#example", 0, S_OK, "http://www.winehq.org/#example", FALSE},
     {"http://www.winehq.org/tests/../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE},
     {"http://www.winehq.org/tests\\../#example", 0, S_OK, "http://www.winehq.org/#example", FALSE},
@@ -120,6 +134,9 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example", FALSE},
     {"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", FALSE},
     {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar", FALSE},
     {"http://www.winehq.org/tests/../#example", URL_DONT_SIMPLIFY, S_OK, "http://www.winehq.org/tests/../#example", FALSE},
     {"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", FALSE},
     {"http://www.winehq.org/tests/foo%20bar", URL_UNESCAPE , S_OK, "http://www.winehq.org/tests/foo bar", FALSE},
+    {"http://www.winehq.org", 0, S_OK, "http://www.winehq.org/", FALSE},
+    {"http:///www.winehq.org", 0, S_OK, "http:///www.winehq.org", FALSE},
+    {"http:////www.winehq.org", 0, S_OK, "http:////www.winehq.org", FALSE},
     {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE},
     {"file:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE},
     {"file:///c:/tests/foo%20bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE},
     {"file:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE},
     {"file:///c:/tests\\foo%20bar", URL_UNESCAPE , S_OK, "file:///c:/tests/foo bar", FALSE},
     {"file:///c:/tests/foo%20bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE},
@@ -134,6 +151,24 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar", FALSE},
     {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar", FALSE},
     {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar", FALSE},
     {"file:///c://tests/foo%20bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\\\tests\\foo bar", FALSE},
     {"file:///c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo bar", FALSE},
     {"file:///c:\\tests\\foo bar", URL_DONT_SIMPLIFY, S_OK, "file:///c:/tests/foo bar", FALSE},
+    {"file:///c:\\tests\\foobar", 0, S_OK, "file:///c:/tests/foobar", FALSE},
+    {"file:///c:\\tests\\foobar", URL_WININET_COMPATIBILITY, S_OK, "file://c:\\tests\\foobar", FALSE},
+    {"file://home/user/file", 0, S_OK, "file://home/user/file", FALSE},
+    {"file:///home/user/file", 0, S_OK, "file:///home/user/file", FALSE},
+    {"file:////home/user/file", 0, S_OK, "file://home/user/file", FALSE},
+    {"file://home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\\\home\\user\\file", FALSE},
+    {"file:///home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\home\\user\\file", FALSE},
+    {"file:////home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\\\home\\user\\file", FALSE},
+    {"file://///home/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://\\\\home\\user\\file", FALSE},
+    {"file://C:/user/file", 0, S_OK, "file:///C:/user/file", FALSE},
+    {"file://C:/user/file/../asdf", 0, S_OK, "file:///C:/user/asdf", FALSE},
+    {"file:///C:/user/file", 0, S_OK, "file:///C:/user/file", FALSE},
+    {"file:////C:/user/file", 0, S_OK, "file:///C:/user/file", FALSE},
+    {"file://C:/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://C:\\user\\file", FALSE},
+    {"file:///C:/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://C:\\user\\file", FALSE},
+    {"file:////C:/user/file", URL_WININET_COMPATIBILITY, S_OK, "file://C:\\user\\file", FALSE},
+    {"http:///www.winehq.org", 0, S_OK, "http:///www.winehq.org", FALSE},
+    {"http:///www.winehq.org", URL_WININET_COMPATIBILITY, S_OK, "http:///www.winehq.org", FALSE},
     {"http://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/site/about", FALSE},
     {"file_://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "file_://www.winehq.org/site/about", FALSE},
     {"c:\\dir\\file", 0, S_OK, "file:///c:/dir/file", FALSE},
     {"http://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/site/about", FALSE},
     {"file_://www.winehq.org/site/about", URL_FILE_USE_PATHURL, S_OK, "file_://www.winehq.org/site/about", FALSE},
     {"c:\\dir\\file", 0, S_OK, "file:///c:/dir/file", FALSE},
@@ -141,6 +176,7 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"c:dir\\file", 0, S_OK, "file:///c:dir/file", FALSE},
     {"c:\\tests\\foo bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE},
     {"c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE},
     {"c:dir\\file", 0, S_OK, "file:///c:dir/file", FALSE},
     {"c:\\tests\\foo bar", URL_FILE_USE_PATHURL, S_OK, "file://c:\\tests\\foo bar", FALSE},
     {"c:\\tests\\foo bar", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE},
+    {"c\t:\t\\te\tsts\\fo\to \tbar\t", 0, S_OK, "file:///c:/tests/foo%20bar", FALSE},
     {"res://file", 0, S_OK, "res://file/", FALSE},
     {"res://file", URL_FILE_USE_PATHURL, S_OK, "res://file/", FALSE},
     {"res:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "res:///c:/tests/foo bar", FALSE},
     {"res://file", 0, S_OK, "res://file/", FALSE},
     {"res://file", URL_FILE_USE_PATHURL, S_OK, "res://file/", FALSE},
     {"res:///c:/tests/foo%20bar", URL_UNESCAPE , S_OK, "res:///c:/tests/foo bar", FALSE},
@@ -158,11 +194,19 @@ static const TEST_URL_CANONICALIZE TEST_CANONICALIZE[] = {
     {"res://c:\\tests/res\\foo%20bar/strange\\sth", URL_FILE_USE_PATHURL, S_OK, "res://c:\\tests/res\\foo%20bar/strange\\sth", FALSE},
     {"res://c:\\tests/res\\foo%20bar/strange\\sth", URL_UNESCAPE, S_OK, "res://c:\\tests/res\\foo bar/strange\\sth", FALSE},
     {"A", 0, S_OK, "A", FALSE},
     {"res://c:\\tests/res\\foo%20bar/strange\\sth", URL_FILE_USE_PATHURL, S_OK, "res://c:\\tests/res\\foo%20bar/strange\\sth", FALSE},
     {"res://c:\\tests/res\\foo%20bar/strange\\sth", URL_UNESCAPE, S_OK, "res://c:\\tests/res\\foo bar/strange\\sth", FALSE},
     {"A", 0, S_OK, "A", FALSE},
+    {"../A", 0, S_OK, "../A", FALSE},
+    {"A/../B", 0, S_OK, "B", TRUE},
     {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/, S_OK, "/uri-res/N2R?urn:sha1:B3K", FALSE} /*LimeWire online installer calls this*/,
     {"http:www.winehq.org/dir/../index.html", 0, S_OK, "http:www.winehq.org/index.html"},
     {"http://localhost/test.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/test.html"},
     {"http://localhost/te%20st.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/te%20st.html"},
     {"/uri-res/N2R?urn:sha1:B3K", URL_DONT_ESCAPE_EXTRA_INFO | URL_WININET_COMPATIBILITY /*0x82000000*/, S_OK, "/uri-res/N2R?urn:sha1:B3K", FALSE} /*LimeWire online installer calls this*/,
     {"http:www.winehq.org/dir/../index.html", 0, S_OK, "http:www.winehq.org/index.html"},
     {"http://localhost/test.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/test.html"},
     {"http://localhost/te%20st.html", URL_FILE_USE_PATHURL, S_OK, "http://localhost/te%20st.html"},
-    {"http://www.winehq.org/%E6%A1%9C.html", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/%E6%A1%9C.html"}
+    {"http://www.winehq.org/%E6%A1%9C.html", URL_FILE_USE_PATHURL, S_OK, "http://www.winehq.org/%E6%A1%9C.html"},
+    {"mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"},
+    {"ftp:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "ftp:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"},
+    {"file:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "file:@MSITStore:C:/Program Files/AutoCAD 2008/Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"},
+    {"http:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", 0, S_OK, "http:@MSITStore:C:/Program Files/AutoCAD 2008/Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"},
+    {"http:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", URL_FILE_USE_PATHURL, S_OK, "http:@MSITStore:C:/Program Files/AutoCAD 2008/Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"},
+    {"mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm", URL_FILE_USE_PATHURL, S_OK, "mk:@MSITStore:C:\\Program Files/AutoCAD 2008\\Help/acad_acg.chm::/WSfacf1429558a55de1a7524c1004e616f8b-322b.htm"},
 };
 
 /* ################ */
 };
 
 /* ################ */
@@ -280,6 +324,9 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = {
     {"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"},
     {"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"},
+    {"http://www.winehq.org/test12", "#", 0, S_OK, "http://www.winehq.org/test12#"},
+    {"http://www.winehq.org/test13#aaa", "#bbb", 0, S_OK, "http://www.winehq.org/test13#bbb"},
+    {"http://www.winehq.org/test14#aaa/bbb#ccc", "#", 0, S_OK, "http://www.winehq.org/test14#"},
     {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"},
     {"file:///C:\\dir\\file.txt#hash\\hash", "test.txt", 0, S_OK, "file:///C:/dir/file.txt#hash/test.txt"},
     {"file:///C:\\dir\\file.html#hash\\hash", "test.html", 0, S_OK, "file:///C:/dir/test.html"},
     {"file:///C:\\dir\\file.txt", "test.txt", 0, S_OK, "file:///C:/dir/test.txt"},
     {"file:///C:\\dir\\file.txt#hash\\hash", "test.txt", 0, S_OK, "file:///C:/dir/file.txt#hash/test.txt"},
     {"file:///C:\\dir\\file.html#hash\\hash", "test.html", 0, S_OK, "file:///C:/dir/test.html"},
@@ -296,7 +343,7 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = {
     {"foo:today", "foo:calendar", 0, S_OK, "foo:calendar"},
     {"foo:today", "bar:calendar", 0, S_OK, "bar:calendar"},
     {"foo:/today", "foo:calendar", 0, S_OK, "foo:/calendar"},
     {"foo:today", "foo:calendar", 0, S_OK, "foo:calendar"},
     {"foo:today", "bar:calendar", 0, S_OK, "bar:calendar"},
     {"foo:/today", "foo:calendar", 0, S_OK, "foo:/calendar"},
-    {"foo:/today/", "foo:calendar", 0, S_OK, "foo:/today/calendar"},
+    {"Foo:/today/", "fOo:calendar", 0, S_OK, "foo:/today/calendar"},
     {"mk:@MSITStore:dir/test.chm::dir/index.html", "image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"},
     {"mk:@MSITStore:dir/test.chm::dir/dir2/index.html", "../image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"},
     /* UrlCombine case 2 tests.  Schemes do not match */
     {"mk:@MSITStore:dir/test.chm::dir/index.html", "image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"},
     {"mk:@MSITStore:dir/test.chm::dir/dir2/index.html", "../image.jpg", 0, S_OK, "mk:@MSITStore:dir/test.chm::dir/image.jpg"},
     /* UrlCombine case 2 tests.  Schemes do not match */
@@ -318,7 +365,7 @@ static const TEST_URL_COMBINE TEST_COMBINE[] = {
     {"outbind://xxxxxxxxx/","http:wine16/dir",0, S_OK,"http:wine16/dir"},
     {"http://xxxxxxxxx","outbind:wine17/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"outbind:wine17/dir"},
     {"xxx://xxxxxxxxx","ftp:wine18/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"ftp:wine18/dir"},
     {"outbind://xxxxxxxxx/","http:wine16/dir",0, S_OK,"http:wine16/dir"},
     {"http://xxxxxxxxx","outbind:wine17/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"outbind:wine17/dir"},
     {"xxx://xxxxxxxxx","ftp:wine18/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"ftp:wine18/dir"},
-    {"ftp://xxxxxxxxx/","xxx:wine19/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"xxx:wine19/dir"},
+    {"ftp://xxxxxxxxx/","xXx:wine19/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"xxx:wine19/dir"},
     {"outbind://xxxxxxxxx/","http:wine20/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"http:wine20/dir"},
     {"file:///c:/dir/file.txt","index.html?test=c:/abc",URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,S_OK,"file:///c:/dir/index.html?test=c:/abc"}
 };
     {"outbind://xxxxxxxxx/","http:wine20/dir",URL_PLUGGABLE_PROTOCOL, S_OK,"http:wine20/dir"},
     {"file:///c:/dir/file.txt","index.html?test=c:/abc",URL_ESCAPE_SPACES_ONLY|URL_DONT_ESCAPE_EXTRA_INFO,S_OK,"file:///c:/dir/index.html?test=c:/abc"}
 };
@@ -337,6 +384,7 @@ static const struct {
     {"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},
     {"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},
+    {"file:///c:/foo/bar", "file:///c:/foo/bar", S_FALSE},
 #if 0
     /* The following test fails on native shlwapi as distributed with Win95/98.
      * Wine matches the behaviour of later versions.
 #if 0
     /* The following test fails on native shlwapi as distributed with Win95/98.
      * Wine matches the behaviour of later versions.
@@ -587,6 +635,9 @@ static void test_UrlGetPart(void)
   const char* http_url = "http://user:pass 123@www.wine hq.org";
   const char* res_url = "res://some.dll/find.dlg";
   const char* about_url = "about:blank";
   const char* http_url = "http://user:pass 123@www.wine hq.org";
   const char* res_url = "res://some.dll/find.dlg";
   const char* about_url = "about:blank";
+  const char* excid_url = "x-excid://36C00000/guid:{048B4E89-2E92-496F-A837-33BA02FF6D32}/Message.htm";
+  const char* foo_url = "foo://bar-url/test";
+  const char* short_url = "ascheme:";
 
   CHAR szPart[INTERNET_MAX_URL_LENGTH];
   DWORD dwSize;
 
   CHAR szPart[INTERNET_MAX_URL_LENGTH];
   DWORD dwSize;
@@ -623,6 +674,20 @@ static void test_UrlGetPart(void)
   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
   ok(dwSize == 0, "dwSize = %d\n", dwSize);
 
   ok(szPart[0]==0, "UrlGetPartA(\"hi\") return \"%s\" instead of \"\"\n", szPart);
   ok(dwSize == 0, "dwSize = %d\n", dwSize);
 
+  if(pUrlGetPartW)
+  {
+      const WCHAR hiW[] = {'h','i',0};
+      WCHAR bufW[5];
+
+      /* UrlGetPartW returns S_OK instead of S_FALSE */
+      dwSize = sizeof szPart;
+      bufW[0]='x'; bufW[1]=0;
+      res = pUrlGetPartW(hiW, bufW, &dwSize, URL_PART_SCHEME, 0);
+      todo_wine ok(res==S_OK, "UrlGetPartW(\"hi\") returned %08X\n", res);
+      ok(bufW[0] == 0, "UrlGetPartW(\"hi\") return \"%c\"\n", bufW[0]);
+      ok(dwSize == 0, "dwSize = %d\n", dwSize);
+  }
+
   dwSize = sizeof szPart;
   szPart[0]='x'; szPart[1]=0;
   res = pUrlGetPartA("hi", szPart, &dwSize, URL_PART_QUERY, 0);
   dwSize = sizeof szPart;
   szPart[0]='x'; szPart[1]=0;
   res = pUrlGetPartA("hi", szPart, &dwSize, URL_PART_QUERY, 0);
@@ -637,6 +702,8 @@ static void test_UrlGetPart(void)
   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");
 
   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");
 
+  test_url_part(TEST_URL_4, URL_PART_HOSTNAME, 0, "google.*.com");
+
   test_url_part(file_url, URL_PART_HOSTNAME, 0, "h o s t");
 
   test_url_part(http_url, URL_PART_HOSTNAME, 0, "www.wine hq.org");
   test_url_part(file_url, URL_PART_HOSTNAME, 0, "h o s t");
 
   test_url_part(http_url, URL_PART_HOSTNAME, 0, "www.wine hq.org");
@@ -644,6 +711,10 @@ static void test_UrlGetPart(void)
 
   test_url_part(about_url, URL_PART_SCHEME, 0, "about");
 
 
   test_url_part(about_url, URL_PART_SCHEME, 0, "about");
 
+  test_url_part(excid_url, URL_PART_SCHEME, 0, "x-excid");
+  test_url_part(foo_url, URL_PART_SCHEME, 0, "foo");
+  test_url_part(short_url, URL_PART_SCHEME, 0, "ascheme");
+
   dwSize = sizeof(szPart);
   res = pUrlGetPartA(about_url, szPart, &dwSize, URL_PART_HOSTNAME, 0);
   ok(res==E_FAIL, "returned %08x\n", res);
   dwSize = sizeof(szPart);
   res = pUrlGetPartA(about_url, szPart, &dwSize, URL_PART_HOSTNAME, 0);
   ok(res==E_FAIL, "returned %08x\n", res);
@@ -674,6 +745,34 @@ static void test_UrlGetPart(void)
   szPart[0] = 'x'; szPart[1] = '\0';
   res = pUrlGetPartA("index.htm", szPart, &dwSize, URL_PART_HOSTNAME, 0);
   ok(res==E_FAIL, "returned %08x\n", res);
   szPart[0] = 'x'; szPart[1] = '\0';
   res = pUrlGetPartA("index.htm", szPart, &dwSize, URL_PART_HOSTNAME, 0);
   ok(res==E_FAIL, "returned %08x\n", res);
+
+  dwSize = sizeof(szPart);
+  szPart[0] = 'x'; szPart[1] = '\0';
+  res = pUrlGetPartA(excid_url, szPart, &dwSize, URL_PART_HOSTNAME, 0);
+  ok(res==E_FAIL, "returned %08x\n", res);
+  ok(szPart[0] == 'x', "szPart[0] = %c\n", szPart[0]);
+  ok(dwSize == sizeof(szPart), "dwSize = %d\n", dwSize);
+
+  dwSize = sizeof(szPart);
+  szPart[0] = 'x'; szPart[1] = '\0';
+  res = pUrlGetPartA(excid_url, szPart, &dwSize, URL_PART_QUERY, 0);
+  ok(res==S_FALSE, "returned %08x\n", res);
+  ok(szPart[0] == 0, "szPart[0] = %c\n", szPart[0]);
+  ok(dwSize == 0, "dwSize = %d\n", dwSize);
+
+  dwSize = sizeof(szPart);
+  szPart[0] = 'x'; szPart[1] = '\0';
+  res = pUrlGetPartA(foo_url, szPart, &dwSize, URL_PART_HOSTNAME, 0);
+  ok(res==E_FAIL, "returned %08x\n", res);
+  ok(szPart[0] == 'x', "szPart[0] = %c\n", szPart[0]);
+  ok(dwSize == sizeof(szPart), "dwSize = %d\n", dwSize);
+
+  dwSize = sizeof(szPart);
+  szPart[0] = 'x'; szPart[1] = '\0';
+  res = pUrlGetPartA(foo_url, szPart, &dwSize, URL_PART_QUERY, 0);
+  ok(res==S_FALSE, "returned %08x\n", res);
+  ok(szPart[0] == 0, "szPart[0] = %c\n", szPart[0]);
+  ok(dwSize == 0, "dwSize = %d\n", dwSize);
 }
 
 /* ########################### */
 }
 
 /* ########################### */
@@ -750,10 +849,13 @@ static void test_url_canonicalize(int index, const char *szUrl, DWORD dwFlags, H
 
 static void test_UrlEscape(void)
 {
 
 static void test_UrlEscape(void)
 {
+    static const WCHAR out[] = { 'f','o','o','%','2','0','b','a','r',0 };
+
     DWORD size = 0;
     HRESULT ret;
     unsigned int i;
     char empty_string[] = "";
     DWORD size = 0;
     HRESULT ret;
     unsigned int i;
     char empty_string[] = "";
+    WCHAR overwrite[] = { 'f','o','o',' ','b','a','r',0,0,0 };
 
     if (!pUrlEscapeA) {
         win_skip("UrlEscapeA noz found\n");
 
     if (!pUrlEscapeA) {
         win_skip("UrlEscapeA noz found\n");
@@ -780,9 +882,28 @@ static void test_UrlEscape(void)
     ok(size == 1, "got %d, expected %d\n", size, 1);
 
     size = 1;
     ok(size == 1, "got %d, expected %d\n", size, 1);
 
     size = 1;
+    empty_string[0] = 127;
     ret = pUrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
     ok(ret == E_POINTER, "got %x, expected %x\n", ret, E_POINTER);
     ok(size == 34, "got %d, expected %d\n", size, 34);
     ret = pUrlEscapeA("/woningplan/woonkamer basis.swf", empty_string, &size, URL_ESCAPE_SPACES_ONLY);
     ok(ret == E_POINTER, "got %x, expected %x\n", ret, E_POINTER);
     ok(size == 34, "got %d, expected %d\n", size, 34);
+    ok(empty_string[0] == 127, "String has changed, empty_string[0] = %d\n", empty_string[0]);
+
+    if(pUrlEscapeW) {
+        WCHAR wc;
+
+        size = sizeof(overwrite)/sizeof(WCHAR);
+        ret = pUrlEscapeW(overwrite, overwrite, &size, URL_ESCAPE_SPACES_ONLY);
+        ok(ret == S_OK, "got %x, expected S_OK\n", ret);
+        ok(size == 9, "got %d, expected 9\n", size);
+        ok(!lstrcmpW(overwrite, out), "got %s, expected %s\n", wine_dbgstr_w(overwrite), wine_dbgstr_w(out));
+
+        size = 1;
+        wc = 127;
+        ret = pUrlEscapeW(overwrite, &wc, &size, URL_ESCAPE_SPACES_ONLY);
+        ok(ret == E_POINTER, "got %x, expected %x\n", ret, E_POINTER);
+        ok(size == 10, "got %d, expected 10\n", size);
+        ok(wc == 127, "String has changed, wc = %d\n", wc);
+    }
 
     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
         test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
 
     for(i=0; i<sizeof(TEST_ESCAPE)/sizeof(TEST_ESCAPE[0]); i++) {
         test_url_escape(TEST_ESCAPE[i].url, TEST_ESCAPE[i].flags,
@@ -1385,8 +1506,17 @@ static void test_HashData(void)
 
 START_TEST(url)
 {
 
 START_TEST(url)
 {
+  char *pFunc;
 
   hShlwapi = GetModuleHandleA("shlwapi.dll");
 
   hShlwapi = GetModuleHandleA("shlwapi.dll");
+
+  /* SHCreateStreamOnFileEx was introduced in shlwapi v6.0 */
+  pFunc = (void*)GetProcAddress(hShlwapi, "SHCreateStreamOnFileEx");
+  if(!pFunc){
+      win_skip("Too old shlwapi version\n");
+      return;
+  }
+
   pUrlUnescapeA = (void *) GetProcAddress(hShlwapi, "UrlUnescapeA");
   pUrlUnescapeW = (void *) GetProcAddress(hShlwapi, "UrlUnescapeW");
   pUrlIsA = (void *) GetProcAddress(hShlwapi, "UrlIsA");
   pUrlUnescapeA = (void *) GetProcAddress(hShlwapi, "UrlUnescapeA");
   pUrlUnescapeW = (void *) GetProcAddress(hShlwapi, "UrlUnescapeW");
   pUrlIsA = (void *) GetProcAddress(hShlwapi, "UrlIsA");