[SHELL32_WINETEST] Sync with Wine Staging 4.0. CORE-15682
authorAmine Khaldi <amine.khaldi@reactos.org>
Mon, 4 Feb 2019 12:00:58 +0000 (13:00 +0100)
committerAmine Khaldi <amine.khaldi@reactos.org>
Mon, 4 Feb 2019 12:00:58 +0000 (13:00 +0100)
12 files changed:
modules/rostests/winetests/shell32/autocomplete.c
modules/rostests/winetests/shell32/brsfolder.c
modules/rostests/winetests/shell32/progman_dde.c
modules/rostests/winetests/shell32/shelldispatch.c
modules/rostests/winetests/shell32/shelllink.c
modules/rostests/winetests/shell32/shellole.c
modules/rostests/winetests/shell32/shellpath.c
modules/rostests/winetests/shell32/shlexec.c
modules/rostests/winetests/shell32/shlfileop.c
modules/rostests/winetests/shell32/shlfolder.c
modules/rostests/winetests/shell32/shlview.c
modules/rostests/winetests/shell32/string.c

index 859734c..4ef124c 100644 (file)
@@ -25,8 +25,8 @@
 #include "windows.h"
 #include "shobjidl.h"
 #include "shlguid.h"
-#include "initguid.h"
 #include "shldisp.h"
+#include "shlobj.h"
 
 #include "wine/heap.h"
 #include "wine/test.h"
@@ -141,7 +141,7 @@ if (0)
 static IAutoComplete *test_init(void)
 {
     HRESULT r;
-    IAutoComplete *ac;
+    IAutoComplete *ac, *ac2;
     IUnknown *acSource;
     LONG_PTR user_data;
 
@@ -176,6 +176,15 @@ static IAutoComplete *test_init(void)
     user_data = GetWindowLongPtrA(hEdit, GWLP_USERDATA);
     ok(user_data == 0, "Expected the edit control user data to be zero\n");
 
+    /* bind a different object to the same edit control */
+    r = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER,
+                         &IID_IAutoComplete, (LPVOID*)&ac2);
+    ok(r == S_OK, "no IID_IAutoComplete (0x%08x)\n", r);
+
+    r = IAutoComplete_Init(ac2, hEdit, acSource, NULL, NULL);
+    ok(r == S_OK, "Init returned 0x%08x\n", r);
+    IAutoComplete_Release(ac2);
+
     IUnknown_Release(acSource);
 
     return ac;
@@ -227,13 +236,47 @@ static void createMainWnd(void)
       CW_USEDEFAULT, CW_USEDEFAULT, 130, 105, NULL, NULL, GetModuleHandleA(NULL), 0);
 }
 
+static WNDPROC HijackerWndProc_prev;
+static const WCHAR HijackerWndProc_txt[] = {'H','i','j','a','c','k','e','d',0};
+static LRESULT CALLBACK HijackerWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+    case WM_GETTEXT:
+    {
+        size_t len = min(wParam, ARRAY_SIZE(HijackerWndProc_txt));
+        memcpy((void*)lParam, HijackerWndProc_txt, len * sizeof(WCHAR));
+        return len;
+    }
+    case WM_GETTEXTLENGTH:
+        return ARRAY_SIZE(HijackerWndProc_txt) - 1;
+    }
+    return CallWindowProcW(HijackerWndProc_prev, hWnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK HijackerWndProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+    switch(msg) {
+    case EM_SETSEL:
+        lParam = wParam;
+        break;
+    case WM_SETTEXT:
+        lParam = (LPARAM)HijackerWndProc_txt;
+        break;
+    }
+    return CallWindowProcW(HijackerWndProc_prev, hWnd, msg, wParam, lParam);
+}
+
 struct string_enumerator
 {
     IEnumString IEnumString_iface;
+    IACList IACList_iface;
     LONG ref;
     WCHAR **data;
     int data_len;
     int cur;
+    UINT num_resets;
+    UINT num_expand;
+    WCHAR last_expand[32];
 };
 
 static struct string_enumerator *impl_from_IEnumString(IEnumString *iface)
@@ -243,15 +286,19 @@ static struct string_enumerator *impl_from_IEnumString(IEnumString *iface)
 
 static HRESULT WINAPI string_enumerator_QueryInterface(IEnumString *iface, REFIID riid, void **ppv)
 {
+    struct string_enumerator *this = impl_from_IEnumString(iface);
     if (IsEqualGUID(riid, &IID_IEnumString) || IsEqualGUID(riid, &IID_IUnknown))
+        *ppv = &this->IEnumString_iface;
+    else if (IsEqualGUID(riid, &IID_IACList))
+        *ppv = &this->IACList_iface;
+    else
     {
-        IUnknown_AddRef(iface);
-        *ppv = iface;
-        return S_OK;
+        *ppv = NULL;
+        return E_NOINTERFACE;
     }
 
-    *ppv = NULL;
-    return E_NOINTERFACE;
+    IUnknown_AddRef(&this->IEnumString_iface);
+    return S_OK;
 }
 
 static ULONG WINAPI string_enumerator_AddRef(IEnumString *iface)
@@ -303,6 +350,7 @@ static HRESULT WINAPI string_enumerator_Reset(IEnumString *iface)
     struct string_enumerator *this = impl_from_IEnumString(iface);
 
     this->cur = 0;
+    this->num_resets++;
 
     return S_OK;
 }
@@ -322,7 +370,7 @@ static HRESULT WINAPI string_enumerator_Clone(IEnumString *iface, IEnumString **
     return E_NOTIMPL;
 }
 
-static IEnumStringVtbl string_enumerator_vtlb =
+static IEnumStringVtbl string_enumerator_vtbl =
 {
     string_enumerator_QueryInterface,
     string_enumerator_AddRef,
@@ -333,12 +381,54 @@ static IEnumStringVtbl string_enumerator_vtlb =
     string_enumerator_Clone
 };
 
+static struct string_enumerator *impl_from_IACList(IACList *iface)
+{
+    return CONTAINING_RECORD(iface, struct string_enumerator, IACList_iface);
+}
+
+static HRESULT WINAPI aclist_QueryInterface(IACList *iface, REFIID riid, void **ppv)
+{
+    return string_enumerator_QueryInterface(&impl_from_IACList(iface)->IEnumString_iface, riid, ppv);
+}
+
+static ULONG WINAPI aclist_AddRef(IACList *iface)
+{
+    return string_enumerator_AddRef(&impl_from_IACList(iface)->IEnumString_iface);
+}
+
+static ULONG WINAPI aclist_Release(IACList *iface)
+{
+    return string_enumerator_Release(&impl_from_IACList(iface)->IEnumString_iface);
+}
+
+static HRESULT WINAPI aclist_Expand(IACList *iface, const WCHAR *expand)
+{
+    struct string_enumerator *this = impl_from_IACList(iface);
+
+    /* see what we get called with and how many times,
+       don't actually do any expansion of the strings */
+    memcpy(this->last_expand, expand, min((lstrlenW(expand) + 1)*sizeof(WCHAR), sizeof(this->last_expand)));
+    this->last_expand[ARRAY_SIZE(this->last_expand) - 1] = '\0';
+    this->num_expand++;
+
+    return S_OK;
+}
+
+static IACListVtbl aclist_vtbl =
+{
+    aclist_QueryInterface,
+    aclist_AddRef,
+    aclist_Release,
+    aclist_Expand
+};
+
 static HRESULT string_enumerator_create(void **ppv, WCHAR **suggestions, int count)
 {
     struct string_enumerator *object;
 
     object = heap_alloc_zero(sizeof(*object));
-    object->IEnumString_iface.lpVtbl = &string_enumerator_vtlb;
+    object->IEnumString_iface.lpVtbl = &string_enumerator_vtbl;
+    object->IACList_iface.lpVtbl = &aclist_vtbl;
     object->ref = 1;
     object->data = suggestions;
     object->data_len = count;
@@ -349,18 +439,257 @@ static HRESULT string_enumerator_create(void **ppv, WCHAR **suggestions, int cou
     return S_OK;
 }
 
+static void dispatch_messages(void)
+{
+    MSG msg;
+    Sleep(33);
+    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
+    {
+        TranslateMessage(&msg);
+        DispatchMessageA(&msg);
+    }
+}
+
+#define check_dropdown(acdropdown, hwnd_edit, list, list_num) check_dropdown_(__FILE__, __LINE__, acdropdown, hwnd_edit, list, list_num)
+static void check_dropdown_(const char *file, UINT line, IAutoCompleteDropDown *acdropdown, HWND hwnd_edit, WCHAR **list, UINT list_num)
+{
+    UINT i;
+    DWORD flags = 0;
+    LPWSTR str;
+    HRESULT hr;
+
+    hr = IAutoCompleteDropDown_GetDropDownStatus(acdropdown, &flags, &str);
+    ok_(file, line)(hr == S_OK, "IAutoCompleteDropDown_GetDropDownStatus failed: %x\n", hr);
+    if (hr != S_OK) return;
+    if (list_num) ok_(file, line)(flags & ACDD_VISIBLE, "AutoComplete DropDown not visible\n");
+    else
+    {
+        ok_(file, line)(!(flags & ACDD_VISIBLE), "AutoComplete DropDown visible\n");
+        return;
+    }
+    ok_(file, line)(str == NULL, "Expected (null), got %s\n", wine_dbgstr_w(str));
+    if (str)
+    {
+        CoTaskMemFree(str);
+        return;
+    }
+
+    for (i = 0; i <= list_num; i++)
+    {
+        flags = 0;
+        SendMessageW(hwnd_edit, WM_KEYDOWN, VK_DOWN, 0);
+        SendMessageW(hwnd_edit, WM_KEYUP, VK_DOWN, 0xc0000000);
+        hr = IAutoCompleteDropDown_GetDropDownStatus(acdropdown, &flags, &str);
+        ok_(file, line)(hr == S_OK, "IAutoCompleteDropDown_GetDropDownStatus failed: %x\n", hr);
+        ok_(file, line)(flags & ACDD_VISIBLE, "AutoComplete DropDown not visible\n");
+        if (hr == S_OK)
+        {
+            if (i < list_num)
+                ok_(file, line)(str && !lstrcmpW(list[i], str), "Expected %s, got %s\n",
+                                wine_dbgstr_w(list[i]), wine_dbgstr_w(str));
+            else
+                ok_(file, line)(str == NULL, "Expected (null), got %s\n", wine_dbgstr_w(str));
+        }
+        CoTaskMemFree(str);
+    }
+}
+
+static void test_aclist_expand(HWND hwnd_edit, void *enumerator)
+{
+    struct string_enumerator *obj = (struct string_enumerator*)enumerator;
+    static WCHAR str1[] = {'t','e','s','t',0};
+    static WCHAR str1a[] = {'t','e','s','t','\\',0};
+    static WCHAR str2[] = {'t','e','s','t','\\','f','o','o','\\','b','a','r','\\','b','a',0};
+    static WCHAR str2a[] = {'t','e','s','t','\\','f','o','o','\\','b','a','r','\\',0};
+    static WCHAR str2b[] = {'t','e','s','t','\\','f','o','o','\\','b','a','r','\\','b','a','z','_','b','b','q','\\',0};
+    obj->num_resets = 0;
+
+    ok(obj->num_expand == 0, "Expected 0 expansions, got %u\n", obj->num_expand);
+    SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str1);
+    SendMessageW(hwnd_edit, EM_SETSEL, ARRAY_SIZE(str1) - 1, ARRAY_SIZE(str1) - 1);
+    SendMessageW(hwnd_edit, WM_CHAR, '\\', 1);
+    dispatch_messages();
+    ok(obj->num_expand == 1, "Expected 1 expansion, got %u\n", obj->num_expand);
+    ok(lstrcmpW(obj->last_expand, str1a) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str1a), wine_dbgstr_w(obj->last_expand));
+    ok(obj->num_resets == 1, "Expected 1 reset, got %u\n", obj->num_resets);
+    SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str2);
+    SendMessageW(hwnd_edit, EM_SETSEL, ARRAY_SIZE(str2) - 1, ARRAY_SIZE(str2) - 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'z', 1);
+    dispatch_messages();
+    ok(obj->num_expand == 2, "Expected 2 expansions, got %u\n", obj->num_expand);
+    ok(lstrcmpW(obj->last_expand, str2a) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str2a), wine_dbgstr_w(obj->last_expand));
+    ok(obj->num_resets == 2, "Expected 2 resets, got %u\n", obj->num_resets);
+    SetFocus(hwnd_edit);
+    SendMessageW(hwnd_edit, WM_CHAR, '_', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'b', 1);
+    SetFocus(0);
+    SetFocus(hwnd_edit);
+    SendMessageW(hwnd_edit, WM_CHAR, 'b', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'q', 1);
+    dispatch_messages();
+    ok(obj->num_expand == 2, "Expected 2 expansions, got %u\n", obj->num_expand);
+    ok(obj->num_resets == 2, "Expected 2 resets, got %u\n", obj->num_resets);
+    SendMessageW(hwnd_edit, WM_CHAR, '\\', 1);
+    dispatch_messages();
+    ok(obj->num_expand == 3, "Expected 3 expansions, got %u\n", obj->num_expand);
+    ok(lstrcmpW(obj->last_expand, str2b) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str2b), wine_dbgstr_w(obj->last_expand));
+    ok(obj->num_resets == 3, "Expected 3 resets, got %u\n", obj->num_resets);
+    SendMessageW(hwnd_edit, EM_SETSEL, ARRAY_SIZE(str1a) - 1, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'x', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'y', 1);
+    dispatch_messages();
+    ok(obj->num_expand == 4, "Expected 4 expansions, got %u\n", obj->num_expand);
+    ok(lstrcmpW(obj->last_expand, str1a) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str1a), wine_dbgstr_w(obj->last_expand));
+    ok(obj->num_resets == 4, "Expected 4 resets, got %u\n", obj->num_resets);
+    SendMessageW(hwnd_edit, EM_SETSEL, ARRAY_SIZE(str1) - 1, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'x', 1);
+    dispatch_messages();
+    ok(obj->num_expand == 4, "Expected 4 expansions, got %u\n", obj->num_expand);
+    ok(obj->num_resets == 5, "Expected 5 resets, got %u\n", obj->num_resets);
+}
+
+static void test_prefix_filtering(HWND hwnd_edit)
+{
+    static WCHAR htt[]  = {'h','t','t',0};
+    static WCHAR www[]  = {'w','w','w','.',0};
+    static WCHAR str0[] = {'w','w','w','.','a','x',0};
+    static WCHAR str1[] = {'h','t','t','p','s',':','/','/','w','w','w','.','a','c',0};
+    static WCHAR str2[] = {'a','a',0};
+    static WCHAR str3[] = {'a','b',0};
+    static WCHAR str4[] = {'h','t','t','p',':','/','/','a','0',0};
+    static WCHAR str5[] = {'h','t','t','p','s',':','/','/','h','t','a',0};
+    static WCHAR str6[] = {'h','f','o','o',0};
+    static WCHAR str7[] = {'h','t','t','p',':','/','/','w','w','w','.','a','d','d',0};
+    static WCHAR str8[] = {'w','w','w','.','w','w','w','.','?',0};
+    static WCHAR str9[] = {'h','t','t','p',':','/','/','a','b','c','.','a','a','.','c','o','m',0};
+    static WCHAR str10[]= {'f','t','p',':','/','/','a','b','c',0};
+    static WCHAR str11[]= {'f','i','l','e',':','/','/','a','a',0};
+    static WCHAR str12[]= {'f','t','p',':','/','/','w','w','w','.','a','a',0};
+    static WCHAR *suggestions[] = { str0, str1, str2, str3, str4, str5, str6, str7, str8, str9, str10, str11, str12 };
+    static WCHAR *sorted1[] = { str4, str2, str3, str9, str1, str7, str0 };
+    static WCHAR *sorted2[] = { str3, str9 };
+    static WCHAR *sorted3[] = { str1, str7, str0 };
+    static WCHAR *sorted4[] = { str6, str5 };
+    static WCHAR *sorted5[] = { str5 };
+    static WCHAR *sorted6[] = { str4, str9 };
+    static WCHAR *sorted7[] = { str11, str10, str12 };
+    IUnknown *enumerator;
+    IAutoComplete2 *autocomplete;
+    IAutoCompleteDropDown *acdropdown;
+    WCHAR buffer[20];
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, &IID_IAutoComplete2, (void**)&autocomplete);
+    ok(hr == S_OK, "CoCreateInstance failed: %x\n", hr);
+
+    hr = IAutoComplete2_QueryInterface(autocomplete, &IID_IAutoCompleteDropDown, (LPVOID*)&acdropdown);
+    ok(hr == S_OK, "No IAutoCompleteDropDown interface: %x\n", hr);
+
+    string_enumerator_create((void**)&enumerator, suggestions, ARRAY_SIZE(suggestions));
+
+    hr = IAutoComplete2_SetOptions(autocomplete, ACO_FILTERPREFIXES | ACO_AUTOSUGGEST | ACO_AUTOAPPEND);
+    ok(hr == S_OK, "IAutoComplete2_SetOptions failed: %x\n", hr);
+    hr = IAutoComplete2_Init(autocomplete, hwnd_edit, enumerator, NULL, NULL);
+    ok(hr == S_OK, "IAutoComplete_Init failed: %x\n", hr);
+
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str4 + 7, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str4 + 7), wine_dbgstr_w(buffer));
+    check_dropdown(acdropdown, hwnd_edit, sorted1, ARRAY_SIZE(sorted1));
+
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'b', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str3, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str3), wine_dbgstr_w(buffer));
+    check_dropdown(acdropdown, hwnd_edit, sorted2, ARRAY_SIZE(sorted2));
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'b', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'c', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str9 + 7, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str9 + 7), wine_dbgstr_w(buffer));
+
+    SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)www);
+    SendMessageW(hwnd_edit, EM_SETSEL, ARRAY_SIZE(www) - 1, ARRAY_SIZE(www) - 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str1 + 8, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str1 + 8), wine_dbgstr_w(buffer));
+    check_dropdown(acdropdown, hwnd_edit, sorted3, ARRAY_SIZE(sorted3));
+    SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)www);
+    SendMessageW(hwnd_edit, EM_SETSEL, ARRAY_SIZE(www) - 1, ARRAY_SIZE(www) - 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'w', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str8, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str8), wine_dbgstr_w(buffer));
+
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'h', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str6, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str6), wine_dbgstr_w(buffer));
+    check_dropdown(acdropdown, hwnd_edit, sorted4, ARRAY_SIZE(sorted4));
+    SendMessageW(hwnd_edit, WM_CHAR, 't', 1);
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str5 + 8, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str5 + 8), wine_dbgstr_w(buffer));
+    check_dropdown(acdropdown, hwnd_edit, sorted5, ARRAY_SIZE(sorted5));
+    SendMessageW(hwnd_edit, WM_CHAR, 't', 1);
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(htt, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(htt), wine_dbgstr_w(buffer));
+    check_dropdown(acdropdown, hwnd_edit, NULL, 0);
+    SendMessageW(hwnd_edit, WM_CHAR, 'p', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, ':', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, '/', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, '/', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str4, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str4), wine_dbgstr_w(buffer));
+    check_dropdown(acdropdown, hwnd_edit, sorted6, ARRAY_SIZE(sorted6));
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, 2);
+    SendMessageW(hwnd_edit, WM_CHAR, 'H', 1);
+    dispatch_messages();
+    check_dropdown(acdropdown, hwnd_edit, NULL, 0);
+    SendMessageW(hwnd_edit, WM_CHAR, 't', 1);
+    dispatch_messages();
+    check_dropdown(acdropdown, hwnd_edit, sorted6, ARRAY_SIZE(sorted6));
+
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'F', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    check_dropdown(acdropdown, hwnd_edit, sorted7, ARRAY_SIZE(sorted7));
+    SendMessageW(hwnd_edit, WM_CHAR, 'i', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'L', 1);
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    check_dropdown(acdropdown, hwnd_edit, sorted7, 1);
+
+    IAutoCompleteDropDown_Release(acdropdown);
+    IAutoComplete2_Release(autocomplete);
+    IUnknown_Release(enumerator);
+}
+
 static void test_custom_source(void)
 {
     static WCHAR str_alpha[] = {'t','e','s','t','1',0};
     static WCHAR str_alpha2[] = {'t','e','s','t','2',0};
     static WCHAR str_beta[] = {'a','u','t','o',' ','c','o','m','p','l','e','t','e',0};
+    static WCHAR str_au[] = {'a','u',0};
+    static WCHAR str_aut[] = {'a','u','t',0};
     static WCHAR *suggestions[] = { str_alpha, str_alpha2, str_beta };
+    struct string_enumerator *obj;
     IUnknown *enumerator;
     IAutoComplete2 *autocomplete;
+    IAutoCompleteDropDown *acdropdown;
     HWND hwnd_edit;
+    DWORD flags = 0;
     WCHAR buffer[20];
     HRESULT hr;
-    MSG msg;
 
     ShowWindow(hMainWnd, SW_SHOW);
 
@@ -369,24 +698,100 @@ static void test_custom_source(void)
     hr = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, &IID_IAutoComplete2, (void**)&autocomplete);
     ok(hr == S_OK, "CoCreateInstance failed: %x\n", hr);
 
-    string_enumerator_create((void**)&enumerator, suggestions, sizeof(suggestions) / sizeof(*suggestions));
+    hr = IAutoComplete2_QueryInterface(autocomplete, &IID_IAutoCompleteDropDown, (LPVOID*)&acdropdown);
+    ok(hr == S_OK, "No IAutoCompleteDropDown interface: %x\n", hr);
+
+    string_enumerator_create((void**)&enumerator, suggestions, ARRAY_SIZE(suggestions));
+    obj = (struct string_enumerator*)enumerator;
 
     hr = IAutoComplete2_SetOptions(autocomplete, ACO_AUTOSUGGEST | ACO_AUTOAPPEND);
     ok(hr == S_OK, "IAutoComplete2_SetOptions failed: %x\n", hr);
+    hr = IAutoCompleteDropDown_ResetEnumerator(acdropdown);
+    ok(hr == S_OK, "IAutoCompleteDropDown_ResetEnumerator failed: %x\n", hr);
     hr = IAutoComplete2_Init(autocomplete, hwnd_edit, enumerator, NULL, NULL);
     ok(hr == S_OK, "IAutoComplete_Init failed: %x\n", hr);
 
+    SetFocus(hwnd_edit);
     SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
-    /* Send a keyup message since wine doesn't handle WM_CHAR yet */
-    SendMessageW(hwnd_edit, WM_KEYUP, 'u', 1);
-    Sleep(100);
-    while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE))
-    {
-        TranslateMessage(&msg);
-        DispatchMessageA(&msg);
-    }
-    SendMessageW(hwnd_edit, WM_GETTEXT, sizeof(buffer) / sizeof(*buffer), (LPARAM)buffer);
+    SendMessageW(hwnd_edit, WM_CHAR, 'u', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str_beta, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str_beta), wine_dbgstr_w(buffer));
+    ok(obj->num_resets == 1, "Expected 1 reset, got %u\n", obj->num_resets);
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, '\b', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(buffer[0] == '\0', "Expected empty string, got %s\n", wine_dbgstr_w(buffer));
+    ok(obj->num_resets == 1, "Expected 1 reset, got %u\n", obj->num_resets);
+    hr = IAutoCompleteDropDown_ResetEnumerator(acdropdown);
+    ok(hr == S_OK, "IAutoCompleteDropDown_ResetEnumerator failed: %x\n", hr);
+    ok(obj->num_resets == 1, "Expected 1 reset, got %u\n", obj->num_resets);
+    obj->num_resets = 0;
+
+    /* hijack the window procedure */
+    HijackerWndProc_prev = (WNDPROC)SetWindowLongPtrW(hwnd_edit, GWLP_WNDPROC, (LONG_PTR)HijackerWndProc);
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(HijackerWndProc_txt, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(HijackerWndProc_txt), wine_dbgstr_w(buffer));
+
+    SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'u', 1);
+    SetWindowLongPtrW(hwnd_edit, GWLP_WNDPROC, (LONG_PTR)HijackerWndProc_prev);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str_au, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str_au), wine_dbgstr_w(buffer));
+    ok(obj->num_resets == 1, "Expected 1 reset, got %u\n", obj->num_resets);
+    SendMessageW(hwnd_edit, EM_SETSEL, 0, -1);
+    SendMessageW(hwnd_edit, WM_CHAR, '\b', 1);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(buffer[0] == '\0', "Expected empty string, got %s\n", wine_dbgstr_w(buffer));
+    hr = IAutoCompleteDropDown_ResetEnumerator(acdropdown);
+    ok(hr == S_OK, "IAutoCompleteDropDown_ResetEnumerator failed: %x\n", hr);
+
+    HijackerWndProc_prev = (WNDPROC)SetWindowLongPtrW(hwnd_edit, GWLP_WNDPROC, (LONG_PTR)HijackerWndProc2);
+    SendMessageW(hwnd_edit, WM_CHAR, 'a', 1);
+    SendMessageW(hwnd_edit, WM_CHAR, 'u', 1);
+    SetWindowLongPtrW(hwnd_edit, GWLP_WNDPROC, (LONG_PTR)HijackerWndProc_prev);
+    dispatch_messages();
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
     ok(lstrcmpW(str_beta, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str_beta), wine_dbgstr_w(buffer));
+    ok(obj->num_resets == 2, "Expected 2 resets, got %u\n", obj->num_resets);
+    /* end of hijacks */
+
+    hr = IAutoCompleteDropDown_GetDropDownStatus(acdropdown, &flags, NULL);
+    ok(hr == S_OK, "IAutoCompleteDropDown_GetDropDownStatus failed: %x\n", hr);
+    ok(flags & ACDD_VISIBLE, "AutoComplete DropDown should be visible\n");
+    SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str_au);
+    dispatch_messages();
+    hr = IAutoCompleteDropDown_GetDropDownStatus(acdropdown, &flags, NULL);
+    ok(hr == S_OK, "IAutoCompleteDropDown_GetDropDownStatus failed: %x\n", hr);
+    ok(!(flags & ACDD_VISIBLE), "AutoComplete DropDown should have been hidden\n");
+    SendMessageW(hwnd_edit, WM_SETTEXT, 0, (LPARAM)str_aut);
+    dispatch_messages();
+    hr = IAutoCompleteDropDown_GetDropDownStatus(acdropdown, &flags, NULL);
+    ok(hr == S_OK, "IAutoCompleteDropDown_GetDropDownStatus failed: %x\n", hr);
+    ok(!(flags & ACDD_VISIBLE), "AutoComplete DropDown should be hidden\n");
+    SendMessageW(hwnd_edit, WM_GETTEXT, ARRAY_SIZE(buffer), (LPARAM)buffer);
+    ok(lstrcmpW(str_aut, buffer) == 0, "Expected %s, got %s\n", wine_dbgstr_w(str_aut), wine_dbgstr_w(buffer));
+
+    test_aclist_expand(hwnd_edit, enumerator);
+    obj->num_resets = 0;
+
+    hr = IAutoCompleteDropDown_ResetEnumerator(acdropdown);
+    ok(hr == S_OK, "IAutoCompleteDropDown_ResetEnumerator failed: %x\n", hr);
+    SendMessageW(hwnd_edit, WM_CHAR, 'x', 1);
+    dispatch_messages();
+    ok(obj->num_resets == 1, "Expected 1 reset, got %u\n", obj->num_resets);
+    SendMessageW(hwnd_edit, WM_CHAR, 'x', 1);
+    dispatch_messages();
+    ok(obj->num_resets == 1, "Expected 1 reset, got %u\n", obj->num_resets);
+
+    IAutoCompleteDropDown_Release(acdropdown);
+    IAutoComplete2_Release(autocomplete);
+    IUnknown_Release(enumerator);
+
+    test_prefix_filtering(hwnd_edit);
 
     ShowWindow(hMainWnd, SW_HIDE);
     DestroyWindow(hwnd_edit);
@@ -397,6 +802,8 @@ START_TEST(autocomplete)
     HRESULT r;
     MSG msg;
     IAutoComplete* ac;
+    RECT win_rect;
+    POINT orig_pos;
 
     r = CoInitialize(NULL);
     ok(r == S_OK, "CoInitialize failed (0x%08x). Tests aborted.\n", r);
@@ -407,6 +814,11 @@ START_TEST(autocomplete)
     ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
     if (!hMainWnd) return;
 
+    /* Move the cursor away from the dropdown listbox */
+    GetWindowRect(hMainWnd, &win_rect);
+    GetCursorPos(&orig_pos);
+    SetCursorPos(win_rect.left, win_rect.top);
+
     test_invalid_init();
     ac = test_init();
     if (!ac)
@@ -424,6 +836,7 @@ START_TEST(autocomplete)
     IAutoComplete_Release(ac);
 
 cleanup:
+    SetCursorPos(orig_pos.x, orig_pos.y);
     DestroyWindow(hEdit);
     DestroyWindow(hMainWnd);
 
index bf29d11..0888cfa 100644 (file)
@@ -44,8 +44,8 @@ static int get_number_of_folders(LPCSTR path)
     WIN32_FIND_DATAA find_data;
     HANDLE find_handle;
 
-    lstrcpynA(path_search_string, path, MAX_PATH);
-    strncat(path_search_string, "*", 1);
+    lstrcpynA(path_search_string, path, MAX_PATH - 1);
+    strcat(path_search_string, "*");
 
     find_handle = FindFirstFileA(path_search_string, &find_data);
     if (find_handle == INVALID_HANDLE_VALUE)
@@ -186,9 +186,9 @@ static void test_click_make_new_folder_button(void)
     {
         skip("GetCurrentDirectoryA failed %u\n", GetLastError());
     }
-    strncat(test_folder_path, "\\", 1);
-    strncat(test_folder_path, title, MAX_PATH-1);
-    strncat(test_folder_path, "\\", 1);
+    strcat(test_folder_path, "\\");
+    strcat(test_folder_path, title);
+    strcat(test_folder_path, "\\");
 
     /* Avoid conflicts by creating a test folder. */
     if (!CreateDirectoryA(title, NULL))
index 62ed413..2d19404 100644 (file)
@@ -166,7 +166,7 @@ static BOOL check_window_exists(const char *name)
 
     for (i = 0; i < 20; i++)
     {
-        Sleep(100);
+        Sleep(100 * i);
         if ((window = FindWindowA("ExplorerWClass", title)) ||
             (window = FindWindowA("CabinetWClass", title)))
         {
index cc00757..e9948ae 100644 (file)
@@ -161,7 +161,7 @@ static void test_namespace(void)
     ok(folder == NULL, "expected NULL, got %p\n", folder);
 
     /* test valid folder ids */
-    for (i = 0; i < sizeof(special_folders)/sizeof(special_folders[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(special_folders); i++)
     {
         V_VT(&var) = VT_I4;
         V_I4(&var) = special_folders[i];
@@ -382,7 +382,7 @@ static void test_items(void)
     FolderItems3 *items3 = NULL;
     FolderItem *item = (FolderItem*)0xdeadbeef, *item2;
     FolderItemVerbs *verbs = (FolderItemVerbs*)0xdeadbeef;
-    VARIANT var, int_index, str_index, str_index2;
+    VARIANT var, var2, int_index, str_index, str_index2;
     IDispatch *disp, *disp2;
     LONG count = -1;
     IUnknown *unk;
@@ -474,7 +474,7 @@ static void test_items(void)
     ok(!item, "item is not null\n");
 
     /* create test files */
-    for (i = 0; i < sizeof(file_defs)/sizeof(file_defs[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(file_defs); i++)
     {
         switch (file_defs[i].type)
         {
@@ -541,15 +541,16 @@ static void test_items(void)
     count = -1;
     r = FolderItems_get_Count(items, &count);
     ok(r == S_OK, "FolderItems::get_Count failed: %08x\n", r);
-    ok(count == sizeof(file_defs)/sizeof(file_defs[0]),
-       "expected %d files, got %d\n", (LONG)(sizeof(file_defs)/sizeof(file_defs[0])), count);
+    ok(count == ARRAY_SIZE(file_defs), "got %d files\n", count);
 
+    /* VT_EMPTY */
     V_VT(&var) = VT_EMPTY;
     item = (FolderItem*)0xdeadbeef;
     r = FolderItems_Item(items, var, &item);
     ok(r == E_NOTIMPL, "expected E_NOTIMPL, got %08x\n", r);
     ok(!item, "item is not null\n");
 
+    /* VT_I2 */
     V_VT(&var) = VT_I2;
     V_I2(&var) = 0;
 
@@ -572,6 +573,20 @@ static void test_items(void)
 
     FolderItem_Release(item);
 
+    /* VT_VARIANT | VT_BYREF */
+    V_VT(&var2) = VT_I2;
+    V_I2(&var2) = 0;
+
+    V_VT(&var) = VT_BYREF | VT_VARIANT;
+    V_VARIANTREF(&var) = &var2;
+
+    item = NULL;
+    r = FolderItems_Item(items, var, &item);
+    ok(r == S_OK, "FolderItems::Item failed: %08x\n", r);
+    ok(!!item, "item is null\n");
+    FolderItem_Release(item);
+
+    /* VT_I4 */
     V_VT(&var) = VT_I4;
     V_I4(&var) = 0;
     item = NULL;
@@ -606,7 +621,7 @@ static void test_items(void)
     V_VT(&int_index) = VT_I4;
 
     /* test the folder item corresponding to each file */
-    for (i = 0; i < sizeof(file_defs)/sizeof(file_defs[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(file_defs); i++)
     {
         VARIANT_BOOL b;
         BSTR name;
@@ -730,7 +745,7 @@ static void test_items(void)
     }
 
     /* test that there are only as many folder items as there were files */
-    V_I4(&int_index) = sizeof(file_defs)/sizeof(file_defs[0]);
+    V_I4(&int_index) = ARRAY_SIZE(file_defs);
     item = (FolderItem*)0xdeadbeef;
     r = FolderItems_Item(items, int_index, &item);
     ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
@@ -976,7 +991,7 @@ if (0) /* crashes on pre-vista */ {
     IShellView_Release(view);
 
     /* Try with some other folder, that's not a desktop */
-    GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
+    GetTempPathW(ARRAY_SIZE(pathW), pathW);
     hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, pathW, NULL, &pidl, NULL);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
@@ -1015,10 +1030,9 @@ static void test_ShellWindows(void)
     if (hr != S_OK)
         return;
 
-if (0) /* NULL out argument - currently crashes on Wine */ {
     hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, NULL);
     ok(hr == HRESULT_FROM_WIN32(RPC_X_NULL_REF_POINTER), "got 0x%08x\n", hr);
-}
+
     hr = IShellWindows_Register(shellwindows, NULL, 0, SWC_EXPLORER, &cookie);
 todo_wine
     ok(hr == E_POINTER, "got 0x%08x\n", hr);
@@ -1096,9 +1110,6 @@ todo_wine {
         IUnknown *unk;
 
         ok(disp != NULL, "got %p\n", disp);
-
-        if (disp == NULL) goto skip_disp_tests;
-
         ok(ret != HandleToUlong(hwnd), "got %d\n", ret);
 
         /* IDispatch-related tests */
@@ -1176,7 +1187,6 @@ if (hr == S_OK) {
         IServiceProvider_Release(sp);
         IDispatch_Release(disp);
     }
-skip_disp_tests:
 
     disp = (void*)0xdeadbeef;
     ret = 0xdead;
@@ -1219,7 +1229,7 @@ static void test_ParseName(void)
         &IID_IShellDispatch, (void**)&sd);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
-    GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
+    GetTempPathW(ARRAY_SIZE(pathW), pathW);
     V_VT(&v) = VT_BSTR;
     V_BSTR(&v) = SysAllocString(pathW);
     hr = IShellDispatch_NameSpace(sd, v, &folder);
@@ -1288,7 +1298,7 @@ static void test_Verbs(void)
         &IID_IShellDispatch, (void**)&sd);
     ok(hr == S_OK, "got 0x%08x\n", hr);
 
-    GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
+    GetTempPathW(ARRAY_SIZE(pathW), pathW);
     V_VT(&v) = VT_BSTR;
     V_BSTR(&v) = SysAllocString(pathW);
     hr = IShellDispatch_NameSpace(sd, v, &folder);
index 444fdcc..3a2068c 100644 (file)
@@ -977,6 +977,7 @@ static void test_shdefextracticon(void)
 
 static void test_GetIconLocation(void)
 {
+    IShellLinkW *slW;
     IShellLinkA *sl;
     const char *str;
     char buffer[INFOTIPSIZE], mypath[MAX_PATH];
@@ -1030,8 +1031,34 @@ static void test_GetIconLocation(void)
     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
     ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
     ok(lstrcmpiA(buffer,str) == 0, "GetIconLocation returned '%s'\n", buffer);
-    ok(i == 0xbabecafe, "GetIconLocation returned %d'\n", i);
+    ok(i == 0xbabecafe, "GetIconLocation returned %#x.\n", i);
 
+    r = IShellLinkA_SetIconLocation(sl, NULL, 0xcafefe);
+    ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
+
+    i = 0xdeadbeef;
+    r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+    ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
+    ok(!*buffer, "GetIconLocation returned '%s'\n", buffer);
+    ok(i == 0xcafefe, "GetIconLocation returned %#x.\n", i);
+
+    r = IShellLinkA_QueryInterface(sl, &IID_IShellLinkW, (void **)&slW);
+    ok(SUCCEEDED(r), "Failed to get IShellLinkW, hr %#x.\n", r);
+
+    str = "c:\\nonexistent\\file";
+    r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
+    ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
+
+    r = IShellLinkA_SetIconLocation(sl, NULL, 0xcafefe);
+    ok(r == S_OK, "SetIconLocation failed (0x%08x)\n", r);
+
+    i = 0xdeadbeef;
+    r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+    ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
+    ok(!*buffer, "GetIconLocation returned '%s'\n", buffer);
+    ok(i == 0xcafefe, "GetIconLocation returned %#x.\n", i);
+
+    IShellLinkW_Release(slW);
     IShellLinkA_Release(sl);
 }
 
@@ -1116,6 +1143,21 @@ static void test_SHGetStockIconInfo(void)
     /* there is a NULL check for the struct  */
     hr = pSHGetStockIconInfo(SIID_FOLDER, SHGSI_ICONLOCATION, NULL);
     ok(hr == E_INVALIDARG, "NULL: got 0x%x\n", hr);
+
+    for(i = 0; i < 140; i++)  /* highest on wvista, i > 140 gives E_INVALIDARG, win7 can go higher */
+    {
+        memset(buffer, 0, sizeof(buffer));
+        sii->cbSize = sizeof(SHSTOCKICONINFO);
+        hr = pSHGetStockIconInfo(i, SHGSI_ICON | SHGSI_SMALLICON, sii);
+        ok(hr == S_OK, "got 0x%x (expected S_OK)\n", hr);
+        ok(sii->hIcon != NULL, "got NULL, expected an icon handle\n");
+        ok(sii->iIcon != 0, "got unexpected 0 for SIID %d\n", i); /* howto find out exact sii->iIcon value??? */
+        ok(sii->iSysImageIndex == -1, "got %d (expected -1)\n", sii->iSysImageIndex);
+        ok(DestroyIcon(sii->hIcon), "DestroyIcon failed\n");
+        if (winetest_debug > 1)
+            trace("%3d: got iSysImageIndex %3d, iIcon %3d and %s\n", i, sii->iSysImageIndex,
+            sii->iIcon, wine_dbgstr_w(sii->szPath));
+    }
 }
 
 static void test_SHExtractIcons(void)
@@ -1291,7 +1333,7 @@ if (0)
     ok(hicon == NULL, "Got icon %p\n", hicon);
 
     /* Create a temporary non-executable file */
-    GetTempPathW(sizeof(pathW)/sizeof(pathW[0]), pathW);
+    GetTempPathW(ARRAY_SIZE(pathW), pathW);
     lstrcatW(pathW, nameW);
     file = CreateFileW(pathW, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     ok(file != INVALID_HANDLE_VALUE, "Failed to create a test file\n");
@@ -1421,9 +1463,8 @@ static void test_SHGetImageList(void)
     for (i = 0; i <= SHIL_LAST; i++)
     {
         hr = SHGetImageList( i, &IID_IImageList, (void **)&list );
-        ok( hr == S_OK ||
-            broken( i == SHIL_JUMBO && hr == E_INVALIDARG ), /* XP and 2003 */
-            "%d: got %08x\n", i, hr );
+        ok( hr == S_OK || broken( i == SHIL_JUMBO && hr == E_INVALIDARG ), /* XP and 2003 */
+                "%d: got %08x\n", i, hr );
         if (FAILED(hr)) continue;
         IImageList_GetIconSize( list, &width, &height );
         switch (i)
index e79d666..27964af 100644 (file)
@@ -864,8 +864,15 @@ static void test_DragQueryFile(void)
 
 static void test_SHCreateSessionKey(void)
 {
+    static const WCHAR session_format[] = {
+                'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
+                'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
+                'E','x','p','l','o','r','e','r','\\','S','e','s','s','i','o','n','I','n','f','o','\\','%','u',0};
     HKEY hkey, hkey2;
     HRESULT hr;
+    DWORD session;
+    WCHAR sessionW[ARRAY_SIZE(session_format) + 16];
+    LONG ret;
 
     if (!pSHCreateSessionKey)
     {
@@ -878,8 +885,8 @@ static void test_SHCreateSessionKey(void)
 
     hkey = (HKEY)0xdeadbeef;
     hr = pSHCreateSessionKey(0, &hkey);
-    todo_wine ok(hr == E_ACCESSDENIED, "got 0x%08x\n", hr);
-    todo_wine ok(hkey == NULL, "got %p\n", hkey);
+    ok(hr == E_ACCESSDENIED, "got 0x%08x\n", hr);
+    ok(hkey == NULL, "got %p\n", hkey);
 
     hr = pSHCreateSessionKey(KEY_READ, &hkey);
     ok(hr == S_OK, "got 0x%08x\n", hr);
@@ -890,6 +897,16 @@ static void test_SHCreateSessionKey(void)
 
     RegCloseKey(hkey);
     RegCloseKey(hkey2);
+
+    /* check the registry */
+    ProcessIdToSessionId( GetCurrentProcessId(), &session);
+    if (session)
+    {
+        wsprintfW(sessionW, session_format, session);
+        ret = RegOpenKeyW(HKEY_CURRENT_USER, sessionW, &hkey);
+        ok(!ret, "key not found\n");
+        RegCloseKey(hkey);
+    }
 }
 
 static void test_dragdrophelper(void)
index f667431..38b56f0 100644 (file)
 
 DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
 
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) ( sizeof(x) / sizeof((x)[0]) )
-#endif
-
 /* from pidl.h, not included here: */
 #ifndef PT_CPL             /* Guess, Win7 uses this for CSIDL_CONTROLS */
 #define PT_CPL        0x01 /* no path */
@@ -118,7 +114,7 @@ static const BYTE printersType[] = { PT_YAGUID, PT_SHELLEXT, 0x71 };
 static const BYTE ieSpecialType[] = { PT_IESPECIAL2 };
 static const BYTE shellExtType[] = { PT_SHELLEXT };
 static const BYTE workgroupType[] = { PT_WORKGRP };
-#define DECLARE_TYPE(x, y) { x, sizeof(y) / sizeof(y[0]), y }
+#define DECLARE_TYPE(x, y) { x, ARRAY_SIZE(y), y }
 static const struct shellExpectedValues requiredShellValues[] = {
  DECLARE_TYPE(CSIDL_BITBUCKET, guidType),
  DECLARE_TYPE(CSIDL_CONTROLS, controlPanelType),
@@ -308,626 +304,41 @@ static const char *getFolderName(int folder)
     }
 }
 
-static void test_parameters(void)
-{
-    LPITEMIDLIST pidl = NULL;
-    char path[MAX_PATH];
-    HRESULT hr;
-
-    if (pSHGetFolderLocation)
-    {
-        /* check a bogus CSIDL: */
-        pidl = NULL;
-        hr = pSHGetFolderLocation(NULL, 0xeeee, NULL, 0, &pidl);
-        ok(hr == E_INVALIDARG, "got 0x%08x, expected E_INVALIDARG\n", hr);
-        if (hr == S_OK) IMalloc_Free(pMalloc, pidl);
-
-        /* check a bogus user token: */
-        pidl = NULL;
-        hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, (HANDLE)2, 0, &pidl);
-        ok(hr == E_FAIL || hr == E_HANDLE, "got 0x%08x, expected E_FAIL or E_HANDLE\n", hr);
-        if (hr == S_OK) IMalloc_Free(pMalloc, pidl);
-
-        /* a NULL pidl pointer crashes, so don't test it */
-    }
-
-    if (pSHGetSpecialFolderLocation)
-    {
-        if (0)
-            /* crashes */
-            SHGetSpecialFolderLocation(NULL, 0, NULL);
-
-        hr = pSHGetSpecialFolderLocation(NULL, 0xeeee, &pidl);
-        ok(hr == E_INVALIDARG, "got returned 0x%08x\n", hr);
-    }
-
-    if (pSHGetFolderPathA)
-    {
-        /* expect 2's a bogus handle, especially since we didn't open it */
-        hr = pSHGetFolderPathA(NULL, CSIDL_DESKTOP, (HANDLE)2, SHGFP_TYPE_DEFAULT, path);
-        ok(hr == E_FAIL || hr == E_HANDLE || /* Vista and 2k8 */
-           broken(hr == S_OK), /* W2k and Me */ "got 0x%08x, expected E_FAIL\n", hr);
-
-        hr = pSHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path);
-        ok(hr == E_INVALIDARG, "got 0x%08x, expected E_INVALIDARG\n", hr);
-    }
-
-    if (pSHGetSpecialFolderPathA)
-    {
-        BOOL ret;
-
-        if (0)
-           pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE);
-
-        /* odd but true: calling with a NULL path still succeeds if it's a real
-         * dir (on some windows platform).  on winME it generates exception.
-         */
-        ret = pSHGetSpecialFolderPathA(NULL, path, CSIDL_PROGRAMS, FALSE);
-        ok(ret, "got %d\n", ret);
-
-        ret = pSHGetSpecialFolderPathA(NULL, path, 0xeeee, FALSE);
-        ok(!ret, "got %d\n", ret);
-    }
-}
-
-/* Returns the folder's PIDL type, or 0xff if one can't be found. */
-static BYTE testSHGetFolderLocation(int folder)
-{
-    LPITEMIDLIST pidl;
-    HRESULT hr;
-    BYTE ret = 0xff;
-
-    /* treat absence of function as success */
-    if (!pSHGetFolderLocation) return TRUE;
-
-    pidl = NULL;
-    hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
-    if (hr == S_OK)
-    {
-        if (pidl)
-        {
-            LPITEMIDLIST pidlLast = pILFindLastID(pidl);
-
-            ok(pidlLast != NULL, "%s: ILFindLastID failed\n",
-             getFolderName(folder));
-            if (pidlLast)
-                ret = pidlLast->mkid.abID[0];
-            IMalloc_Free(pMalloc, pidl);
-        }
-    }
-    return ret;
-}
-
-/* Returns the folder's PIDL type, or 0xff if one can't be found. */
-static BYTE testSHGetSpecialFolderLocation(int folder)
-{
-    LPITEMIDLIST pidl;
-    HRESULT hr;
-    BYTE ret = 0xff;
-
-    /* treat absence of function as success */
-    if (!pSHGetSpecialFolderLocation) return TRUE;
-
-    pidl = NULL;
-    hr = pSHGetSpecialFolderLocation(NULL, folder, &pidl);
-    if (hr == S_OK)
-    {
-        if (pidl)
-        {
-            LPITEMIDLIST pidlLast = pILFindLastID(pidl);
-
-            ok(pidlLast != NULL,
-                "%s: ILFindLastID failed\n", getFolderName(folder));
-            if (pidlLast)
-                ret = pidlLast->mkid.abID[0];
-            IMalloc_Free(pMalloc, pidl);
-        }
-    }
-    return ret;
-}
-
-static void test_SHGetFolderPath(BOOL optional, int folder)
-{
-    char path[MAX_PATH];
-    HRESULT hr;
-
-    if (!pSHGetFolderPathA) return;
-
-    hr = pSHGetFolderPathA(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path);
-    ok(hr == S_OK || optional,
-     "SHGetFolderPathA(NULL, %s, NULL, SHGFP_TYPE_CURRENT, path) failed: 0x%08x\n", getFolderName(folder), hr);
-}
-
-static void test_SHGetSpecialFolderPath(BOOL optional, int folder)
-{
-    char path[MAX_PATH];
-    BOOL ret;
-
-    if (!pSHGetSpecialFolderPathA) return;
-
-    ret = pSHGetSpecialFolderPathA(NULL, path, folder, FALSE);
-    if (ret && winetest_interactive)
-        printf("%s: %s\n", getFolderName(folder), path);
-    ok(ret || optional,
-     "SHGetSpecialFolderPathA(NULL, path, %s, FALSE) failed\n",
-     getFolderName(folder));
-}
-
-static void test_ShellValues(const struct shellExpectedValues testEntries[],
- int numEntries, BOOL optional)
-{
-    int i;
-
-    for (i = 0; i < numEntries; i++)
-    {
-        BYTE type;
-        int j;
-        BOOL foundTypeMatch = FALSE;
-
-        if (pSHGetFolderLocation)
-        {
-            type = testSHGetFolderLocation(testEntries[i].folder);
-            for (j = 0; !foundTypeMatch && j < testEntries[i].numTypes; j++)
-                if (testEntries[i].types[j] == type)
-                    foundTypeMatch = TRUE;
-            ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */,
-             "%s has unexpected type %d (0x%02x)\n",
-             getFolderName(testEntries[i].folder), type, type);
-        }
-        type = testSHGetSpecialFolderLocation(testEntries[i].folder);
-        for (j = 0, foundTypeMatch = FALSE; !foundTypeMatch &&
-         j < testEntries[i].numTypes; j++)
-            if (testEntries[i].types[j] == type)
-                foundTypeMatch = TRUE;
-        ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */,
-         "%s has unexpected type %d (0x%02x)\n",
-         getFolderName(testEntries[i].folder), type, type);
-        switch (type)
-        {
-            case PT_FOLDER:
-            case PT_DRIVE:
-            case PT_DRIVE2:
-            case PT_IESPECIAL2:
-                test_SHGetFolderPath(optional, testEntries[i].folder);
-                test_SHGetSpecialFolderPath(optional, testEntries[i].folder);
-                break;
-        }
-    }
-}
-
-/* Attempts to verify that the folder path corresponding to the folder CSIDL
- * value has the same value as the environment variable with name envVar.
- * Doesn't mind if SHGetSpecialFolderPath fails for folder or if envVar isn't
- * set in this environment; different OS and shell version behave differently.
- * However, if both are present, fails if envVar's value is not the same
- * (byte-for-byte) as what SHGetSpecialFolderPath returns.
- */
-static void matchSpecialFolderPathToEnv(int folder, const char *envVar)
-{
-    char path[MAX_PATH];
-
-    if (!pSHGetSpecialFolderPathA) return;
+/* Standard CSIDL values (and their flags) uses only two less-significant bytes */
+#define NO_CSIDL 0x10000
+#define WINE_ATTRIBUTES_OPTIONAL 0x20000
+#define KNOWN_FOLDER(id, csidl, name, category, parent1, parent2, relative_path, parsing_name, attributes, definitionFlags) \
+    { &id, # id, csidl, # csidl, name, category, {&parent1, &parent2}, relative_path, parsing_name, attributes, definitionFlags, __LINE__ }
 
-    if (pSHGetSpecialFolderPathA(NULL, path, folder, FALSE))
-    {
-        char *envVal = getenv(envVar);
+/* non-published known folders test */
+static const GUID _FOLDERID_CryptoKeys =            {0xB88F4DAA, 0xE7BD, 0x49A9, {0xB7, 0x4D, 0x02, 0x88, 0x5A, 0x5D, 0xC7, 0x65} };
+static const GUID _FOLDERID_DpapiKeys =             {0x10C07CD0, 0xEF91, 0x4567, {0xB8, 0x50, 0x44, 0x8B, 0x77, 0xCB, 0x37, 0xF9} };
+static const GUID _FOLDERID_SystemCertificates =    {0x54EED2E0, 0xE7CA, 0x4FDB, {0x91, 0x48, 0x0F, 0x42, 0x47, 0x29, 0x1C, 0xFA} };
+static const GUID _FOLDERID_CredentialManager =     {0x915221FB, 0x9EFE, 0x4BDA, {0x8F, 0xD7, 0xF7, 0x8D, 0xCA, 0x77, 0x4F, 0x87} };
 
-        ok(!envVal || !lstrcmpiA(envVal, path),
-         "%%%s%% does not match SHGetSpecialFolderPath:\n"
-         "%%%s%% is %s\nSHGetSpecialFolderPath returns %s\n",
-         envVar, envVar, envVal, path);
-    }
-}
+struct knownFolderDef {
+    const KNOWNFOLDERID *folderId;
+    const char *sFolderId;
+    const int csidl;
+    const char *sCsidl;
+    const char *sName;
+    const KF_CATEGORY category;
+    const KNOWNFOLDERID *fidParents[2];
+    const char *sRelativePath;
+    const char *sParsingName;
+    const DWORD attributes;
+    const KF_DEFINITION_FLAGS definitionFlags;
+    const int line;
+};
 
-/* Attempts to match the GUID returned by SHGetFolderLocation for folder with
- * GUID.  Assumes the type of the returned PIDL is in fact a GUID, but doesn't
- * fail if it isn't--that check should already have been done.
- * Fails if the returned PIDL is a GUID whose value does not match guid.
- */
-static void matchGUID(int folder, const GUID *guid, const GUID *guid_alt)
-{
-    LPITEMIDLIST pidl;
-    HRESULT hr;
-
-    if (!pSHGetFolderLocation) return;
-    if (!guid) return;
-
-    pidl = NULL;
-    hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
-    if (hr == S_OK)
-    {
-        LPITEMIDLIST pidlLast = pILFindLastID(pidl);
-
-        if (pidlLast && (pidlLast->mkid.abID[0] == PT_SHELLEXT ||
-         pidlLast->mkid.abID[0] == PT_GUID))
-        {
-            GUID *shellGuid = (GUID *)(pidlLast->mkid.abID + 2);
-
-            if (!guid_alt)
-             ok(IsEqualIID(shellGuid, guid),
-              "%s: got GUID %s, expected %s\n", getFolderName(folder),
-              wine_dbgstr_guid(shellGuid), wine_dbgstr_guid(guid));
-            else
-             ok(IsEqualIID(shellGuid, guid) ||
-              IsEqualIID(shellGuid, guid_alt),
-              "%s: got GUID %s, expected %s or %s\n", getFolderName(folder),
-              wine_dbgstr_guid(shellGuid), wine_dbgstr_guid(guid), wine_dbgstr_guid(guid_alt));
-        }
-        IMalloc_Free(pMalloc, pidl);
-    }
-}
-
-/* Checks the PIDL type of all the known values. */
-static void test_PidlTypes(void)
-{
-    /* Desktop */
-    test_SHGetFolderPath(FALSE, CSIDL_DESKTOP);
-    test_SHGetSpecialFolderPath(FALSE, CSIDL_DESKTOP);
-
-    test_ShellValues(requiredShellValues, ARRAY_SIZE(requiredShellValues), FALSE);
-    test_ShellValues(optionalShellValues, ARRAY_SIZE(optionalShellValues), TRUE);
-}
-
-/* FIXME: Should be in shobjidl.idl */
-DEFINE_GUID(CLSID_NetworkExplorerFolder, 0xF02C1A0D, 0xBE21, 0x4350, 0x88, 0xB0, 0x73, 0x67, 0xFC, 0x96, 0xEF, 0x3C);
-DEFINE_GUID(_CLSID_Documents, 0xA8CDFF1C, 0x4878, 0x43be, 0xB5, 0xFD, 0xF8, 0x09, 0x1C, 0x1C, 0x60, 0xD0);
-
-/* Verifies various shell virtual folders have the correct well-known GUIDs. */
-static void test_GUIDs(void)
-{
-    matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin, NULL);
-    matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel, NULL);
-    matchGUID(CSIDL_DRIVES, &CLSID_MyComputer, NULL);
-    matchGUID(CSIDL_INTERNET, &CLSID_Internet, NULL);
-    matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces, &CLSID_NetworkExplorerFolder); /* Vista and higher */
-    matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments, &_CLSID_Documents /* win8 */);
-    matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments, NULL);
-    matchGUID(CSIDL_PRINTERS, &CLSID_Printers, NULL);
-}
-
-/* Verifies various shell paths match the environment variables to which they
- * correspond.
- */
-static void test_EnvVars(void)
-{
-    matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES, "ProgramFiles");
-    matchSpecialFolderPathToEnv(CSIDL_APPDATA, "APPDATA");
-    matchSpecialFolderPathToEnv(CSIDL_PROFILE, "USERPROFILE");
-    matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "SystemRoot");
-    matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "windir");
-    matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES_COMMON, "CommonProgramFiles");
-    /* this is only set on Wine, but can't hurt to verify it: */
-    matchSpecialFolderPathToEnv(CSIDL_SYSTEM, "winsysdir");
-}
-
-/* Loosely based on PathRemoveBackslashA from dlls/shlwapi/path.c */
-static BOOL myPathIsRootA(LPCSTR lpszPath)
-{
-  if (lpszPath && *lpszPath &&
-      lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
-      return TRUE; /* X:\ */
-  return FALSE;
-}
-static LPSTR myPathRemoveBackslashA( LPSTR lpszPath )
-{
-  LPSTR szTemp = NULL;
-
-  if(lpszPath)
-  {
-    szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath));
-    if (!myPathIsRootA(lpszPath) && *szTemp == '\\')
-      *szTemp = '\0';
-  }
-  return szTemp;
-}
-
-/* Verifies the shell path for CSIDL_WINDOWS matches the return from
- * GetWindowsDirectory.  If SHGetSpecialFolderPath fails, no harm, no foul--not
- * every shell32 version supports CSIDL_WINDOWS.
- */
-static void testWinDir(void)
-{
-    char windowsShellPath[MAX_PATH], windowsDir[MAX_PATH] = { 0 };
-
-    if (!pSHGetSpecialFolderPathA) return;
-
-    if (pSHGetSpecialFolderPathA(NULL, windowsShellPath, CSIDL_WINDOWS, FALSE))
-    {
-        myPathRemoveBackslashA(windowsShellPath);
-        GetWindowsDirectoryA(windowsDir, sizeof(windowsDir));
-        myPathRemoveBackslashA(windowsDir);
-        ok(!lstrcmpiA(windowsDir, windowsShellPath),
-         "GetWindowsDirectory returns %s SHGetSpecialFolderPath returns %s\n",
-         windowsDir, windowsShellPath);
-    }
-}
-
-/* Verifies the shell path for CSIDL_SYSTEM matches the return from
- * GetSystemDirectory.  If SHGetSpecialFolderPath fails, no harm,
- * no foul--not every shell32 version supports CSIDL_SYSTEM.
- */
-static void testSystemDir(void)
-{
-    char systemShellPath[MAX_PATH], systemDir[MAX_PATH], systemDirx86[MAX_PATH];
-
-    if (!pSHGetSpecialFolderPathA) return;
-
-    GetSystemDirectoryA(systemDir, sizeof(systemDir));
-    myPathRemoveBackslashA(systemDir);
-    if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEM, FALSE))
-    {
-        myPathRemoveBackslashA(systemShellPath);
-        ok(!lstrcmpiA(systemDir, systemShellPath),
-         "GetSystemDirectory returns %s SHGetSpecialFolderPath returns %s\n",
-         systemDir, systemShellPath);
-    }
-
-    if (!pGetSystemWow64DirectoryA || !pGetSystemWow64DirectoryA(systemDirx86, sizeof(systemDirx86)))
-        GetSystemDirectoryA(systemDirx86, sizeof(systemDirx86));
-    myPathRemoveBackslashA(systemDirx86);
-    if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEMX86, FALSE))
-    {
-        myPathRemoveBackslashA(systemShellPath);
-        ok(!lstrcmpiA(systemDirx86, systemShellPath) || broken(!lstrcmpiA(systemDir, systemShellPath)),
-         "GetSystemDirectory returns %s SHGetSpecialFolderPath returns %s\n",
-         systemDir, systemShellPath);
-    }
-}
-
-/* Globals used by subprocesses */
-static int    myARGC;
-static char **myARGV;
-static char   base[MAX_PATH];
-static char   selfname[MAX_PATH];
-
-static BOOL init(void)
-{
-    myARGC = winetest_get_mainargs(&myARGV);
-    if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
-    strcpy(selfname, myARGV[0]);
-    return TRUE;
-}
-
-static void doChild(const char *arg)
-{
-    char path[MAX_PATH];
-    HRESULT hr;
-
-    if (arg[0] == '1')
-    {
-        LPITEMIDLIST pidl;
-        char *p;
-
-        /* test what happens when CSIDL_FAVORITES is set to a nonexistent directory */
-
-        /* test some failure cases first: */
-        hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path);
-        ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
-            "SHGetFolderPath returned 0x%08x, expected 0x80070002\n", hr);
-
-        pidl = NULL;
-        hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, NULL, 0, &pidl);
-        ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
-            "SHGetFolderLocation returned 0x%08x\n", hr);
-        if (hr == S_OK && pidl) IMalloc_Free(pMalloc, pidl);
-
-        ok(!pSHGetSpecialFolderPathA(NULL, path, CSIDL_FAVORITES, FALSE),
-            "SHGetSpecialFolderPath succeeded, expected failure\n");
-
-        pidl = NULL;
-        hr = pSHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
-        ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
-            "SHGetFolderLocation returned 0x%08x\n", hr);
-
-        if (hr == S_OK && pidl) IMalloc_Free(pMalloc, pidl);
-
-        /* now test success: */
-        hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
-                               SHGFP_TYPE_CURRENT, path);
-        ok (hr == S_OK, "got 0x%08x\n", hr);
-        if (hr == S_OK)
-        {
-            BOOL ret;
-
-            trace("CSIDL_FAVORITES was changed to %s\n", path);
-            ret = CreateDirectoryA(path, NULL);
-            ok(!ret, "expected failure with ERROR_ALREADY_EXISTS\n");
-            if (!ret)
-                ok(GetLastError() == ERROR_ALREADY_EXISTS,
-                  "got %d, expected ERROR_ALREADY_EXISTS\n", GetLastError());
-
-            p = path + strlen(path);
-            strcpy(p, "\\desktop.ini");
-            DeleteFileA(path);
-            *p = 0;
-            SetFileAttributesA( path, FILE_ATTRIBUTE_NORMAL );
-            ret = RemoveDirectoryA(path);
-            ok( ret, "failed to remove %s error %u\n", path, GetLastError() );
-        }
-    }
-    else if (arg[0] == '2')
-    {
-        /* make sure SHGetFolderPath still succeeds when the
-           original value of CSIDL_FAVORITES is restored. */
-        hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
-            SHGFP_TYPE_CURRENT, path);
-        ok(hr == S_OK, "SHGetFolderPath failed: 0x%08x\n", hr);
-    }
-}
-
-/* Tests the return values from the various shell functions both with and
- * without the use of the CSIDL_FLAG_CREATE flag.  This flag only appeared in
- * version 5 of the shell, so don't test unless it's at least version 5.
- * The test reads a value from the registry, modifies it, calls
- * SHGetFolderPath once with the CSIDL_FLAG_CREATE flag, and immediately
- * afterward without it.  Then it restores the registry and deletes the folder
- * that was created.
- * One oddity with respect to restoration: shell32 caches somehow, so it needs
- * to be reloaded in order to see the correct (restored) value.
- * Some APIs unrelated to the ones under test may fail, but I expect they're
- * covered by other unit tests; I just print out something about failure to
- * help trace what's going on.
- */
-static void test_NonExistentPath(void)
-{
-    static const char userShellFolders[] = 
-     "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
-    char originalPath[MAX_PATH], modifiedPath[MAX_PATH];
-    HKEY key;
-
-    if (!pSHGetFolderPathA) return;
-    if (!pSHGetFolderLocation) return;
-    if (!pSHGetSpecialFolderPathA) return;
-    if (!pSHGetSpecialFolderLocation) return;
-    if (!pSHFileOperationA) return;
-    if (shellVersion.dwMajorVersion < 5) return;
-
-    if (!RegOpenKeyExA(HKEY_CURRENT_USER, userShellFolders, 0, KEY_ALL_ACCESS,
-     &key))
-    {
-        DWORD len, type;
-
-        len = sizeof(originalPath);
-        if (!RegQueryValueExA(key, "Favorites", NULL, &type,
-         (LPBYTE)&originalPath, &len))
-        {
-            size_t len = strlen(originalPath);
-
-            memcpy(modifiedPath, originalPath, len);
-            modifiedPath[len++] = '2';
-            modifiedPath[len++] = '\0';
-            trace("Changing CSIDL_FAVORITES to %s\n", modifiedPath);
-            if (!RegSetValueExA(key, "Favorites", 0, type,
-             (LPBYTE)modifiedPath, len))
-            {
-                char buffer[MAX_PATH+20];
-                STARTUPINFOA startup;
-                PROCESS_INFORMATION info;
-
-                sprintf(buffer, "%s tests/shellpath.c 1", selfname);
-                memset(&startup, 0, sizeof(startup));
-                startup.cb = sizeof(startup);
-                startup.dwFlags = STARTF_USESHOWWINDOW;
-                startup.wShowWindow = SW_SHOWNORMAL;
-                CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
-                 &startup, &info);
-                winetest_wait_child_process( info.hProcess );
-
-                /* restore original values: */
-                trace("Restoring CSIDL_FAVORITES to %s\n", originalPath);
-                RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) originalPath,
-                 strlen(originalPath) + 1);
-                RegFlushKey(key);
-
-                sprintf(buffer, "%s tests/shellpath.c 2", selfname);
-                memset(&startup, 0, sizeof(startup));
-                startup.cb = sizeof(startup);
-                startup.dwFlags = STARTF_USESHOWWINDOW;
-                startup.wShowWindow = SW_SHOWNORMAL;
-                CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
-                 &startup, &info);
-                ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
-                 "child process termination\n");
-            }
-        }
-        else skip("RegQueryValueExA(key, Favorites, ...) failed\n");
-        if (key)
-            RegCloseKey(key);
-    }
-    else skip("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n", userShellFolders);
-}
-
-static void test_SHGetFolderPathEx(void)
-{
-    HRESULT hr;
-    WCHAR buffer[MAX_PATH], *path;
-    DWORD len;
-
-    if (!pSHGetKnownFolderPath || !pSHGetFolderPathEx)
-    {
-        win_skip("SHGetKnownFolderPath or SHGetFolderPathEx not available\n");
-        return;
-    }
-
-if (0) { /* crashes */
-    hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, NULL);
-    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
-}
-    /* non-existent folder id */
-    path = (void *)0xdeadbeef;
-    hr = pSHGetKnownFolderPath(&IID_IOleObject, 0, NULL, &path);
-    ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
-    ok(path == NULL, "got %p\n", path);
-
-    path = NULL;
-    hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, KF_FLAG_DEFAULT_PATH, NULL, &path);
-    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
-    ok(path != NULL, "expected path != NULL\n");
-    CoTaskMemFree(path);
-
-    path = NULL;
-    hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &path);
-    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
-    ok(path != NULL, "expected path != NULL\n");
-
-    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, MAX_PATH);
-    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
-    ok(!lstrcmpiW(path, buffer), "expected equal paths\n");
-    len = lstrlenW(buffer);
-    CoTaskMemFree(path);
-
-    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, 0);
-    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
-
-if (0) { /* crashes */
-    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, NULL, len + 1);
-    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
-
-    hr = pSHGetFolderPathEx(NULL, 0, NULL, buffer, MAX_PATH);
-    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
-}
-    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, len);
-    ok(hr == E_NOT_SUFFICIENT_BUFFER, "expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hr);
-
-    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, len + 1);
-    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
-}
-
-/* Standard CSIDL values (and their flags) uses only two less-significant bytes */
-#define NO_CSIDL 0x10000
-#define WINE_ATTRIBUTES_OPTIONAL 0x20000
-#define KNOWN_FOLDER(id, csidl, name, category, parent1, parent2, relative_path, parsing_name, attributes, definitionFlags) \
-    { &id, # id, csidl, # csidl, name, category, {&parent1, &parent2}, relative_path, parsing_name, attributes, definitionFlags, __LINE__ }
-
-/* non-published known folders test */
-static const GUID _FOLDERID_CryptoKeys =            {0xB88F4DAA, 0xE7BD, 0x49A9, {0xB7, 0x4D, 0x02, 0x88, 0x5A, 0x5D, 0xC7, 0x65} };
-static const GUID _FOLDERID_DpapiKeys =             {0x10C07CD0, 0xEF91, 0x4567, {0xB8, 0x50, 0x44, 0x8B, 0x77, 0xCB, 0x37, 0xF9} };
-static const GUID _FOLDERID_SystemCertificates =    {0x54EED2E0, 0xE7CA, 0x4FDB, {0x91, 0x48, 0x0F, 0x42, 0x47, 0x29, 0x1C, 0xFA} };
-static const GUID _FOLDERID_CredentialManager =     {0x915221FB, 0x9EFE, 0x4BDA, {0x8F, 0xD7, 0xF7, 0x8D, 0xCA, 0x77, 0x4F, 0x87} };
-
-struct knownFolderDef {
-    const KNOWNFOLDERID *folderId;
-    const char *sFolderId;
-    const int csidl;
-    const char *sCsidl;
-    const char *sName;
-    const KF_CATEGORY category;
-    const KNOWNFOLDERID *fidParents[2];
-    const char *sRelativePath;
-    const char *sParsingName;
-    const DWORD attributes;
-    const KF_DEFINITION_FLAGS definitionFlags;
-    const int line;
-};
-
-/* Note: content of parsing name may vary between Windows versions.
- * As a base, values from 6.0 (Vista) were used. Some entries may contain
- * alternative values. In that case, Windows version where the value was
- * found is noted.
- *
- * The list of values for parsing name was encoded as a number of null-
- * terminated strings placed one by one (separated by null byte only).
- * End of list is marked by two consecutive null bytes.
+/* Note: content of parsing name may vary between Windows versions.
+ * As a base, values from 6.0 (Vista) were used. Some entries may contain
+ * alternative values. In that case, Windows version where the value was
+ * found is noted.
+ *
+ * The list of values for parsing name was encoded as a number of null-
+ * terminated strings placed one by one (separated by null byte only).
+ * End of list is marked by two consecutive null bytes.
  */
 static const struct knownFolderDef known_folders[] = {
     KNOWN_FOLDER(FOLDERID_AddNewPrograms,
@@ -1895,10 +1306,630 @@ static const struct knownFolderDef known_folders[] = {
                  NULL,
                  0,
                  0),
-    { 0 }
 };
 #undef KNOWN_FOLDER
-BOOL known_folder_found[ARRAY_SIZE(known_folders)-1];
+BOOL known_folder_found[ARRAY_SIZE(known_folders)];
+
+static void test_parameters(void)
+{
+    LPITEMIDLIST pidl = NULL;
+    char path[MAX_PATH];
+    HRESULT hr;
+
+    if (pSHGetFolderLocation)
+    {
+        /* check a bogus CSIDL: */
+        pidl = NULL;
+        hr = pSHGetFolderLocation(NULL, 0xeeee, NULL, 0, &pidl);
+        ok(hr == E_INVALIDARG, "got 0x%08x, expected E_INVALIDARG\n", hr);
+        if (hr == S_OK) IMalloc_Free(pMalloc, pidl);
+
+        /* check a bogus user token: */
+        pidl = NULL;
+        hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, (HANDLE)2, 0, &pidl);
+        ok(hr == E_FAIL || hr == E_HANDLE, "got 0x%08x, expected E_FAIL or E_HANDLE\n", hr);
+        if (hr == S_OK) IMalloc_Free(pMalloc, pidl);
+
+        /* a NULL pidl pointer crashes, so don't test it */
+    }
+
+    if (pSHGetSpecialFolderLocation)
+    {
+        if (0)
+            /* crashes */
+            SHGetSpecialFolderLocation(NULL, 0, NULL);
+
+        hr = pSHGetSpecialFolderLocation(NULL, 0xeeee, &pidl);
+        ok(hr == E_INVALIDARG, "got returned 0x%08x\n", hr);
+    }
+
+    if (pSHGetFolderPathA)
+    {
+        /* expect 2's a bogus handle, especially since we didn't open it */
+        hr = pSHGetFolderPathA(NULL, CSIDL_DESKTOP, (HANDLE)2, SHGFP_TYPE_DEFAULT, path);
+        ok(hr == E_FAIL || hr == E_HANDLE || /* Vista and 2k8 */
+           broken(hr == S_OK), /* W2k and Me */ "got 0x%08x, expected E_FAIL\n", hr);
+
+        hr = pSHGetFolderPathA(NULL, 0xeeee, NULL, SHGFP_TYPE_DEFAULT, path);
+        ok(hr == E_INVALIDARG, "got 0x%08x, expected E_INVALIDARG\n", hr);
+    }
+
+    if (pSHGetSpecialFolderPathA)
+    {
+        BOOL ret;
+
+        if (0)
+           pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE);
+
+        /* odd but true: calling with a NULL path still succeeds if it's a real
+         * dir (on some windows platform).  on winME it generates exception.
+         */
+        ret = pSHGetSpecialFolderPathA(NULL, path, CSIDL_PROGRAMS, FALSE);
+        ok(ret, "got %d\n", ret);
+
+        ret = pSHGetSpecialFolderPathA(NULL, path, 0xeeee, FALSE);
+        ok(!ret, "got %d\n", ret);
+    }
+}
+
+/* Returns the folder's PIDL type, or 0xff if one can't be found. */
+static BYTE testSHGetFolderLocation(int folder)
+{
+    LPITEMIDLIST pidl;
+    HRESULT hr;
+    BYTE ret = 0xff;
+
+    /* treat absence of function as success */
+    if (!pSHGetFolderLocation) return TRUE;
+
+    pidl = NULL;
+    hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
+    if (hr == S_OK)
+    {
+        if (pidl)
+        {
+            LPITEMIDLIST pidlLast = pILFindLastID(pidl);
+
+            ok(pidlLast != NULL, "%s: ILFindLastID failed\n",
+             getFolderName(folder));
+            if (pidlLast)
+                ret = pidlLast->mkid.abID[0];
+            IMalloc_Free(pMalloc, pidl);
+        }
+    }
+    return ret;
+}
+
+/* Returns the folder's PIDL type, or 0xff if one can't be found. */
+static BYTE testSHGetSpecialFolderLocation(int folder)
+{
+    LPITEMIDLIST pidl;
+    HRESULT hr;
+    BYTE ret = 0xff;
+
+    /* treat absence of function as success */
+    if (!pSHGetSpecialFolderLocation) return TRUE;
+
+    pidl = NULL;
+    hr = pSHGetSpecialFolderLocation(NULL, folder, &pidl);
+    if (hr == S_OK)
+    {
+        if (pidl)
+        {
+            LPITEMIDLIST pidlLast = pILFindLastID(pidl);
+
+            ok(pidlLast != NULL,
+                "%s: ILFindLastID failed\n", getFolderName(folder));
+            if (pidlLast)
+                ret = pidlLast->mkid.abID[0];
+            IMalloc_Free(pMalloc, pidl);
+        }
+    }
+    return ret;
+}
+
+static void test_SHGetFolderPath(BOOL optional, int folder)
+{
+    char path[MAX_PATH];
+    HRESULT hr;
+
+    if (!pSHGetFolderPathA) return;
+
+    hr = pSHGetFolderPathA(NULL, folder, NULL, SHGFP_TYPE_CURRENT, path);
+    ok(hr == S_OK || optional,
+     "SHGetFolderPathA(NULL, %s, NULL, SHGFP_TYPE_CURRENT, path) failed: 0x%08x\n", getFolderName(folder), hr);
+}
+
+static void test_SHGetSpecialFolderPath(BOOL optional, int folder)
+{
+    char path[MAX_PATH];
+    BOOL ret;
+
+    if (!pSHGetSpecialFolderPathA) return;
+
+    ret = pSHGetSpecialFolderPathA(NULL, path, folder, FALSE);
+    if (ret && winetest_interactive)
+        printf("%s: %s\n", getFolderName(folder), path);
+    ok(ret || optional,
+     "SHGetSpecialFolderPathA(NULL, path, %s, FALSE) failed\n",
+     getFolderName(folder));
+}
+
+static void test_ShellValues(const struct shellExpectedValues testEntries[],
+ int numEntries, BOOL optional)
+{
+    int i;
+
+    for (i = 0; i < numEntries; i++)
+    {
+        BYTE type;
+        int j;
+        BOOL foundTypeMatch = FALSE;
+
+        if (pSHGetFolderLocation)
+        {
+            type = testSHGetFolderLocation(testEntries[i].folder);
+            for (j = 0; !foundTypeMatch && j < testEntries[i].numTypes; j++)
+                if (testEntries[i].types[j] == type)
+                    foundTypeMatch = TRUE;
+            ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */,
+             "%s has unexpected type %d (0x%02x)\n",
+             getFolderName(testEntries[i].folder), type, type);
+        }
+        type = testSHGetSpecialFolderLocation(testEntries[i].folder);
+        for (j = 0, foundTypeMatch = FALSE; !foundTypeMatch &&
+         j < testEntries[i].numTypes; j++)
+            if (testEntries[i].types[j] == type)
+                foundTypeMatch = TRUE;
+        ok(foundTypeMatch || optional || broken(type == 0xff) /* Win9x */,
+         "%s has unexpected type %d (0x%02x)\n",
+         getFolderName(testEntries[i].folder), type, type);
+        switch (type)
+        {
+            case PT_FOLDER:
+            case PT_DRIVE:
+            case PT_DRIVE2:
+            case PT_IESPECIAL2:
+                test_SHGetFolderPath(optional, testEntries[i].folder);
+                test_SHGetSpecialFolderPath(optional, testEntries[i].folder);
+                break;
+        }
+    }
+}
+
+/* Attempts to verify that the folder path corresponding to the folder CSIDL
+ * value has the same value as the environment variable with name envVar.
+ * Doesn't mind if SHGetSpecialFolderPath fails for folder or if envVar isn't
+ * set in this environment; different OS and shell version behave differently.
+ * However, if both are present, fails if envVar's value is not the same
+ * (byte-for-byte) as what SHGetSpecialFolderPath returns.
+ */
+static void matchSpecialFolderPathToEnv(int folder, const char *envVar)
+{
+    char path[MAX_PATH];
+
+    if (!pSHGetSpecialFolderPathA) return;
+
+    if (pSHGetSpecialFolderPathA(NULL, path, folder, FALSE))
+    {
+        char *envVal = getenv(envVar);
+
+        ok(!envVal || !lstrcmpiA(envVal, path),
+         "%%%s%% does not match SHGetSpecialFolderPath:\n"
+         "%%%s%% is %s\nSHGetSpecialFolderPath returns %s\n",
+         envVar, envVar, envVal, path);
+    }
+}
+
+/* Attempts to match the GUID returned by SHGetFolderLocation for folder with
+ * GUID.  Assumes the type of the returned PIDL is in fact a GUID, but doesn't
+ * fail if it isn't--that check should already have been done.
+ * Fails if the returned PIDL is a GUID whose value does not match guid.
+ */
+static void matchGUID(int folder, const GUID *guid, const GUID *guid_alt)
+{
+    LPITEMIDLIST pidl;
+    HRESULT hr;
+
+    if (!pSHGetFolderLocation) return;
+    if (!guid) return;
+
+    pidl = NULL;
+    hr = pSHGetFolderLocation(NULL, folder, NULL, 0, &pidl);
+    if (hr == S_OK)
+    {
+        LPITEMIDLIST pidlLast = pILFindLastID(pidl);
+
+        if (pidlLast && (pidlLast->mkid.abID[0] == PT_SHELLEXT ||
+         pidlLast->mkid.abID[0] == PT_GUID))
+        {
+            GUID *shellGuid = (GUID *)(pidlLast->mkid.abID + 2);
+
+            if (!guid_alt)
+             ok(IsEqualIID(shellGuid, guid),
+              "%s: got GUID %s, expected %s\n", getFolderName(folder),
+              wine_dbgstr_guid(shellGuid), wine_dbgstr_guid(guid));
+            else
+             ok(IsEqualIID(shellGuid, guid) ||
+              IsEqualIID(shellGuid, guid_alt),
+              "%s: got GUID %s, expected %s or %s\n", getFolderName(folder),
+              wine_dbgstr_guid(shellGuid), wine_dbgstr_guid(guid), wine_dbgstr_guid(guid_alt));
+        }
+        IMalloc_Free(pMalloc, pidl);
+    }
+}
+
+/* Checks the PIDL type of all the known values. */
+static void test_PidlTypes(void)
+{
+    /* Desktop */
+    test_SHGetFolderPath(FALSE, CSIDL_DESKTOP);
+    test_SHGetSpecialFolderPath(FALSE, CSIDL_DESKTOP);
+
+    test_ShellValues(requiredShellValues, ARRAY_SIZE(requiredShellValues), FALSE);
+    test_ShellValues(optionalShellValues, ARRAY_SIZE(optionalShellValues), TRUE);
+}
+
+/* FIXME: Should be in shobjidl.idl */
+DEFINE_GUID(CLSID_NetworkExplorerFolder, 0xF02C1A0D, 0xBE21, 0x4350, 0x88, 0xB0, 0x73, 0x67, 0xFC, 0x96, 0xEF, 0x3C);
+DEFINE_GUID(_CLSID_Documents, 0xA8CDFF1C, 0x4878, 0x43be, 0xB5, 0xFD, 0xF8, 0x09, 0x1C, 0x1C, 0x60, 0xD0);
+
+/* Verifies various shell virtual folders have the correct well-known GUIDs. */
+static void test_GUIDs(void)
+{
+    matchGUID(CSIDL_BITBUCKET, &CLSID_RecycleBin, NULL);
+    matchGUID(CSIDL_CONTROLS, &CLSID_ControlPanel, NULL);
+    matchGUID(CSIDL_DRIVES, &CLSID_MyComputer, NULL);
+    matchGUID(CSIDL_INTERNET, &CLSID_Internet, NULL);
+    matchGUID(CSIDL_NETWORK, &CLSID_NetworkPlaces, &CLSID_NetworkExplorerFolder); /* Vista and higher */
+    matchGUID(CSIDL_PERSONAL, &CLSID_MyDocuments, &_CLSID_Documents /* win8 */);
+    matchGUID(CSIDL_COMMON_DOCUMENTS, &CLSID_CommonDocuments, NULL);
+    matchGUID(CSIDL_PRINTERS, &CLSID_Printers, NULL);
+}
+
+/* Verifies various shell paths match the environment variables to which they
+ * correspond.
+ */
+static void test_EnvVars(void)
+{
+    matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES, "ProgramFiles");
+    matchSpecialFolderPathToEnv(CSIDL_APPDATA, "APPDATA");
+    matchSpecialFolderPathToEnv(CSIDL_PROFILE, "USERPROFILE");
+    matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "SystemRoot");
+    matchSpecialFolderPathToEnv(CSIDL_WINDOWS, "windir");
+    matchSpecialFolderPathToEnv(CSIDL_PROGRAM_FILES_COMMON, "CommonProgramFiles");
+    /* this is only set on Wine, but can't hurt to verify it: */
+    matchSpecialFolderPathToEnv(CSIDL_SYSTEM, "winsysdir");
+}
+
+/* Loosely based on PathRemoveBackslashA from dlls/shlwapi/path.c */
+static BOOL myPathIsRootA(LPCSTR lpszPath)
+{
+  if (lpszPath && *lpszPath &&
+      lpszPath[1] == ':' && lpszPath[2] == '\\' && lpszPath[3] == '\0')
+      return TRUE; /* X:\ */
+  return FALSE;
+}
+static LPSTR myPathRemoveBackslashA( LPSTR lpszPath )
+{
+  LPSTR szTemp = NULL;
+
+  if(lpszPath)
+  {
+    szTemp = CharPrevA(lpszPath, lpszPath + strlen(lpszPath));
+    if (!myPathIsRootA(lpszPath) && *szTemp == '\\')
+      *szTemp = '\0';
+  }
+  return szTemp;
+}
+
+/* Verifies the shell path for CSIDL_WINDOWS matches the return from
+ * GetWindowsDirectory.  If SHGetSpecialFolderPath fails, no harm, no foul--not
+ * every shell32 version supports CSIDL_WINDOWS.
+ */
+static void testWinDir(void)
+{
+    char windowsShellPath[MAX_PATH], windowsDir[MAX_PATH] = { 0 };
+
+    if (!pSHGetSpecialFolderPathA) return;
+
+    if (pSHGetSpecialFolderPathA(NULL, windowsShellPath, CSIDL_WINDOWS, FALSE))
+    {
+        myPathRemoveBackslashA(windowsShellPath);
+        GetWindowsDirectoryA(windowsDir, sizeof(windowsDir));
+        myPathRemoveBackslashA(windowsDir);
+        ok(!lstrcmpiA(windowsDir, windowsShellPath),
+         "GetWindowsDirectory returns %s SHGetSpecialFolderPath returns %s\n",
+         windowsDir, windowsShellPath);
+    }
+}
+
+/* Verifies the shell path for CSIDL_SYSTEM matches the return from
+ * GetSystemDirectory.  If SHGetSpecialFolderPath fails, no harm,
+ * no foul--not every shell32 version supports CSIDL_SYSTEM.
+ */
+static void testSystemDir(void)
+{
+    char systemShellPath[MAX_PATH], systemDir[MAX_PATH], systemDirx86[MAX_PATH];
+
+    if (!pSHGetSpecialFolderPathA) return;
+
+    GetSystemDirectoryA(systemDir, sizeof(systemDir));
+    myPathRemoveBackslashA(systemDir);
+    if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEM, FALSE))
+    {
+        myPathRemoveBackslashA(systemShellPath);
+        ok(!lstrcmpiA(systemDir, systemShellPath),
+         "GetSystemDirectory returns %s SHGetSpecialFolderPath returns %s\n",
+         systemDir, systemShellPath);
+    }
+
+    if (!pGetSystemWow64DirectoryA || !pGetSystemWow64DirectoryA(systemDirx86, sizeof(systemDirx86)))
+        GetSystemDirectoryA(systemDirx86, sizeof(systemDirx86));
+    myPathRemoveBackslashA(systemDirx86);
+    if (pSHGetSpecialFolderPathA(NULL, systemShellPath, CSIDL_SYSTEMX86, FALSE))
+    {
+        myPathRemoveBackslashA(systemShellPath);
+        ok(!lstrcmpiA(systemDirx86, systemShellPath) || broken(!lstrcmpiA(systemDir, systemShellPath)),
+         "GetSystemDirectory returns %s SHGetSpecialFolderPath returns %s\n",
+         systemDir, systemShellPath);
+    }
+}
+
+/* Globals used by subprocesses */
+static int    myARGC;
+static char **myARGV;
+static char   base[MAX_PATH];
+static char   selfname[MAX_PATH];
+
+static BOOL init(void)
+{
+    myARGC = winetest_get_mainargs(&myARGV);
+    if (!GetCurrentDirectoryA(sizeof(base), base)) return FALSE;
+    strcpy(selfname, myARGV[0]);
+    return TRUE;
+}
+
+static void doChild(const char *arg)
+{
+    char path[MAX_PATH];
+    HRESULT hr;
+
+    if (arg[0] == '1')
+    {
+        LPITEMIDLIST pidl;
+        char *p;
+
+        /* test what happens when CSIDL_FAVORITES is set to a nonexistent directory */
+
+        /* test some failure cases first: */
+        hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path);
+        ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            "SHGetFolderPath returned 0x%08x, expected 0x80070002\n", hr);
+
+        pidl = NULL;
+        hr = pSHGetFolderLocation(NULL, CSIDL_FAVORITES, NULL, 0, &pidl);
+        ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            "SHGetFolderLocation returned 0x%08x\n", hr);
+        if (hr == S_OK && pidl) IMalloc_Free(pMalloc, pidl);
+
+        ok(!pSHGetSpecialFolderPathA(NULL, path, CSIDL_FAVORITES, FALSE),
+            "SHGetSpecialFolderPath succeeded, expected failure\n");
+
+        pidl = NULL;
+        hr = pSHGetSpecialFolderLocation(NULL, CSIDL_FAVORITES, &pidl);
+        ok(hr == E_FAIL || hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+            "SHGetFolderLocation returned 0x%08x\n", hr);
+
+        if (hr == S_OK && pidl) IMalloc_Free(pMalloc, pidl);
+
+        /* now test success: */
+        hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
+                               SHGFP_TYPE_CURRENT, path);
+        ok (hr == S_OK, "got 0x%08x\n", hr);
+        if (hr == S_OK)
+        {
+            BOOL ret;
+
+            trace("CSIDL_FAVORITES was changed to %s\n", path);
+            ret = CreateDirectoryA(path, NULL);
+            ok(!ret, "expected failure with ERROR_ALREADY_EXISTS\n");
+            if (!ret)
+                ok(GetLastError() == ERROR_ALREADY_EXISTS,
+                  "got %d, expected ERROR_ALREADY_EXISTS\n", GetLastError());
+
+            p = path + strlen(path);
+            strcpy(p, "\\desktop.ini");
+            DeleteFileA(path);
+            *p = 0;
+            SetFileAttributesA( path, FILE_ATTRIBUTE_NORMAL );
+            ret = RemoveDirectoryA(path);
+            ok( ret, "failed to remove %s error %u\n", path, GetLastError() );
+        }
+    }
+    else if (arg[0] == '2')
+    {
+        /* make sure SHGetFolderPath still succeeds when the
+           original value of CSIDL_FAVORITES is restored. */
+        hr = pSHGetFolderPathA(NULL, CSIDL_FAVORITES | CSIDL_FLAG_CREATE, NULL,
+            SHGFP_TYPE_CURRENT, path);
+        ok(hr == S_OK, "SHGetFolderPath failed: 0x%08x\n", hr);
+    }
+}
+
+/* Tests the return values from the various shell functions both with and
+ * without the use of the CSIDL_FLAG_CREATE flag.  This flag only appeared in
+ * version 5 of the shell, so don't test unless it's at least version 5.
+ * The test reads a value from the registry, modifies it, calls
+ * SHGetFolderPath once with the CSIDL_FLAG_CREATE flag, and immediately
+ * afterward without it.  Then it restores the registry and deletes the folder
+ * that was created.
+ * One oddity with respect to restoration: shell32 caches somehow, so it needs
+ * to be reloaded in order to see the correct (restored) value.
+ * Some APIs unrelated to the ones under test may fail, but I expect they're
+ * covered by other unit tests; I just print out something about failure to
+ * help trace what's going on.
+ */
+static void test_NonExistentPath(void)
+{
+    static const char userShellFolders[] =
+     "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders";
+    char originalPath[MAX_PATH], modifiedPath[MAX_PATH];
+    HKEY key;
+
+    if (!pSHGetFolderPathA) return;
+    if (!pSHGetFolderLocation) return;
+    if (!pSHGetSpecialFolderPathA) return;
+    if (!pSHGetSpecialFolderLocation) return;
+    if (!pSHFileOperationA) return;
+    if (shellVersion.dwMajorVersion < 5) return;
+
+    if (!RegOpenKeyExA(HKEY_CURRENT_USER, userShellFolders, 0, KEY_ALL_ACCESS,
+     &key))
+    {
+        DWORD len, type;
+
+        len = sizeof(originalPath);
+        if (!RegQueryValueExA(key, "Favorites", NULL, &type,
+         (LPBYTE)&originalPath, &len))
+        {
+            size_t len = strlen(originalPath);
+
+            memcpy(modifiedPath, originalPath, len);
+            modifiedPath[len++] = '2';
+            modifiedPath[len++] = '\0';
+            trace("Changing CSIDL_FAVORITES to %s\n", modifiedPath);
+            if (!RegSetValueExA(key, "Favorites", 0, type,
+             (LPBYTE)modifiedPath, len))
+            {
+                char buffer[MAX_PATH+20];
+                STARTUPINFOA startup;
+                PROCESS_INFORMATION info;
+
+                sprintf(buffer, "%s tests/shellpath.c 1", selfname);
+                memset(&startup, 0, sizeof(startup));
+                startup.cb = sizeof(startup);
+                startup.dwFlags = STARTF_USESHOWWINDOW;
+                startup.wShowWindow = SW_SHOWNORMAL;
+                CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
+                 &startup, &info);
+                winetest_wait_child_process( info.hProcess );
+
+                /* restore original values: */
+                trace("Restoring CSIDL_FAVORITES to %s\n", originalPath);
+                RegSetValueExA(key, "Favorites", 0, type, (LPBYTE) originalPath,
+                 strlen(originalPath) + 1);
+                RegFlushKey(key);
+
+                sprintf(buffer, "%s tests/shellpath.c 2", selfname);
+                memset(&startup, 0, sizeof(startup));
+                startup.cb = sizeof(startup);
+                startup.dwFlags = STARTF_USESHOWWINDOW;
+                startup.wShowWindow = SW_SHOWNORMAL;
+                CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0L, NULL, NULL,
+                 &startup, &info);
+                ok(WaitForSingleObject(info.hProcess, 30000) == WAIT_OBJECT_0,
+                 "child process termination\n");
+            }
+        }
+        else skip("RegQueryValueExA(key, Favorites, ...) failed\n");
+        if (key)
+            RegCloseKey(key);
+    }
+    else skip("RegOpenKeyExA(HKEY_CURRENT_USER, %s, ...) failed\n", userShellFolders);
+}
+
+static void test_SHGetFolderPathEx(void)
+{
+    WCHAR buffer[MAX_PATH], *path, *path2;
+    unsigned int i;
+    HRESULT hr;
+    DWORD len;
+
+    if (!pSHGetKnownFolderPath || !pSHGetFolderPathEx)
+    {
+        win_skip("SHGetKnownFolderPath or SHGetFolderPathEx not available\n");
+        return;
+    }
+
+if (0) { /* crashes */
+    hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, NULL);
+    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
+}
+    /* non-existent folder id */
+    path = (void *)0xdeadbeef;
+    hr = pSHGetKnownFolderPath(&IID_IOleObject, 0, NULL, &path);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "got 0x%08x\n", hr);
+    ok(path == NULL, "got %p\n", path);
+
+    path = NULL;
+    hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, KF_FLAG_DEFAULT_PATH, NULL, &path);
+    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+    ok(path != NULL, "expected path != NULL\n");
+    CoTaskMemFree(path);
+
+    for (i = 0; i < ARRAY_SIZE(known_folders); ++i)
+    {
+        const KNOWNFOLDERID *folder_id = known_folders[i].folderId;
+
+        path = NULL;
+        hr = pSHGetKnownFolderPath(folder_id, KF_FLAG_DEFAULT, NULL, &path);
+        if (FAILED(hr))
+            continue;
+        ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+        ok(path != NULL, "expected path != NULL\n");
+
+        path2 = NULL;
+        hr = pSHGetKnownFolderPath(folder_id, KF_FLAG_SIMPLE_IDLIST, NULL, &path2);
+        ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+        ok(path2 != NULL, "expected path != NULL\n");
+        ok(!lstrcmpiW(path, path2), "expected equal paths: %s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(path2));
+        CoTaskMemFree(path2);
+
+        path2 = NULL;
+        hr = pSHGetKnownFolderPath(folder_id, KF_FLAG_DONT_UNEXPAND, NULL, &path2);
+        ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+        ok(path2 != NULL, "expected path != NULL\n");
+        ok(!lstrcmpiW(path, path2), "expected equal paths: %s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(path2));
+        CoTaskMemFree(path2);
+
+        path2 = NULL;
+        hr = pSHGetKnownFolderPath(folder_id, KF_FLAG_SIMPLE_IDLIST | KF_FLAG_DONT_UNEXPAND, NULL, &path2);
+        ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+        ok(path2 != NULL, "expected path != NULL\n");
+        ok(!lstrcmpiW(path, path2), "expected equal paths: %s, %s\n", wine_dbgstr_w(path), wine_dbgstr_w(path2));
+        CoTaskMemFree(path2);
+
+        CoTaskMemFree(path);
+    }
+
+    path = NULL;
+    hr = pSHGetKnownFolderPath(&FOLDERID_Desktop, 0, NULL, &path);
+    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+    ok(path != NULL, "expected path != NULL\n");
+
+    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, MAX_PATH);
+    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+    ok(!lstrcmpiW(path, buffer), "expected equal paths\n");
+    len = lstrlenW(buffer);
+    CoTaskMemFree(path);
+
+    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, 0);
+    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
+
+if (0) { /* crashes */
+    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, NULL, len + 1);
+    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
+
+    hr = pSHGetFolderPathEx(NULL, 0, NULL, buffer, MAX_PATH);
+    ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
+}
+    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, len);
+    ok(hr == E_NOT_SUFFICIENT_BUFFER, "expected E_NOT_SUFFICIENT_BUFFER, got 0x%08x\n", hr);
+
+    hr = pSHGetFolderPathEx(&FOLDERID_Desktop, 0, NULL, buffer, len + 1);
+    ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
+}
 
 static BOOL is_in_strarray(const WCHAR *needle, const char *hay)
 {
@@ -1933,19 +1964,20 @@ static BOOL is_in_strarray(const WCHAR *needle, const char *hay)
 static void check_known_folder(IKnownFolderManager *mgr, KNOWNFOLDERID *folderId)
 {
     HRESULT hr;
-    const struct knownFolderDef *known_folder = &known_folders[0];
     int csidl, expectedCsidl, ret;
     KNOWNFOLDER_DEFINITION kfd;
     IKnownFolder *folder;
     WCHAR sName[1024];
-    BOOL *current_known_folder_found = &known_folder_found[0];
     BOOL found = FALSE;
+    unsigned int i;
 
-    while(known_folder->folderId != NULL)
+    for (i = 0; i < ARRAY_SIZE(known_folders); ++i)
     {
+        const struct knownFolderDef *known_folder = &known_folders[i];
+
         if(IsEqualGUID(known_folder->folderId, folderId))
         {
-            *current_known_folder_found = TRUE;
+            known_folder_found[i] = TRUE;
             found = TRUE;
             /* verify CSIDL */
             if(!(known_folder->csidl & NO_CSIDL))
@@ -1997,8 +2029,6 @@ static void check_known_folder(IKnownFolderManager *mgr, KNOWNFOLDERID *folderId
 
             break;
         }
-        known_folder++;
-        current_known_folder_found++;
     }
 
     if(!found)
@@ -2549,7 +2579,7 @@ static void test_DoEnvironmentSubst(void)
                             "%HOMEDRIVE%%HOMEPATH%",
                             "%OS% %windir%"}; /* always the last entry in the table */
 
-    for (i = 0; i < (sizeof(names)/sizeof(LPSTR)); i++)
+    for (i = 0; i < (ARRAY_SIZE(names)); i++)
     {
         memset(bufferA, '#', MAX_PATH - 1);
         bufferA[MAX_PATH - 1] = 0;
index a8aabac..b140280 100644 (file)
@@ -760,7 +760,7 @@ static LSTATUS myRegDeleteTreeA(HKEY hKey, LPCSTR lpszSubKey)
     dwMaxSubkeyLen++;
     dwMaxValueLen++;
     dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
-    if (dwMaxLen > sizeof(szNameBuf)/sizeof(CHAR))
+    if (dwMaxLen > ARRAY_SIZE(szNameBuf))
     {
         /* Name too big: alloc a buffer for it */
         if (!(lpszName = heap_alloc(dwMaxLen*sizeof(CHAR))))
@@ -1331,7 +1331,7 @@ static BOOL test_one_cmdline(const cmdline_tests_t* test)
     int i, count;
 
     /* trace("----- cmd='%s'\n", test->cmd); */
-    MultiByteToWideChar(CP_ACP, 0, test->cmd, -1, cmdW, sizeof(cmdW)/sizeof(*cmdW));
+    MultiByteToWideChar(CP_ACP, 0, test->cmd, -1, cmdW, ARRAY_SIZE(cmdW));
     argsW = cl2a = CommandLineToArgvW(cmdW, &cl2a_count);
     if (argsW == NULL && cl2a_count == -1)
     {
@@ -1351,7 +1351,7 @@ static BOOL test_one_cmdline(const cmdline_tests_t* test)
     {
         if (i < count)
         {
-            MultiByteToWideChar(CP_ACP, 0, test->args[i], -1, argW, sizeof(argW)/sizeof(*argW));
+            MultiByteToWideChar(CP_ACP, 0, test->args[i], -1, argW, ARRAY_SIZE(argW));
             todo_wine_if(test->todo & (1 << (i+4)))
                 ok(!lstrcmpW(*argsW, argW), "%s: arg[%d] expected %s but got %s\n", test->cmd, i, wine_dbgstr_w(argW), wine_dbgstr_w(*argsW));
         }
@@ -1397,7 +1397,7 @@ static void test_commandline2argv(void)
        "expected NULL-terminated list of commandline arguments\n");
     if (numargs == 1)
     {
-        GetModuleFileNameW(NULL, strW, sizeof(strW)/sizeof(*strW));
+        GetModuleFileNameW(NULL, strW, ARRAY_SIZE(strW));
         ok(!lstrcmpW(args[0], strW), "wrong path to the current executable: %s instead of %s\n", wine_dbgstr_w(args[0]), wine_dbgstr_w(strW));
     }
     if (args) LocalFree(args);
@@ -1420,8 +1420,8 @@ typedef struct
     const char* verb;
     const char* params;
     int todo;
-    cmdline_tests_t cmd;
-    cmdline_tests_t broken;
+    const char *cmd;
+    const char *broken;
 } argify_tests_t;
 
 static const argify_tests_t argify_tests[] =
@@ -1431,33 +1431,28 @@ static const argify_tests_t argify_tests[] =
      * parameters string, including the trailing spaces, no matter what
      * arguments have already been used.
      */
-    {"Params232S", "p2 p3 p4 ", 0xc2,
-     {" p2 p3 \"p2\" \"p2 p3 p4 \"",
-      {"", "p2", "p3", "p2", "p2 p3 p4 ", NULL}, 0}},
+    {"Params232S", "p2 p3 p4 ", TRUE,
+     " p2 p3 \"p2\" \"p2 p3 p4 \""},
 
     /* Unquoted argument references like %2 don't automatically quote their
      * argument. Similarly, when they are quoted they don't escape the quotes
      * that their argument may contain.
      */
-    {"Params232S", "\"p two\" p3 p4  ", 0x3f3,
-     {" p two p3 \"p two\" \"\"p two\" p3 p4  \"",
-      {"", "p", "two", "p3", "p two", "p", "two p3 p4  ", NULL}, 0}},
+    {"Params232S", "\"p two\" p3 p4  ", TRUE,
+     " p two p3 \"p two\" \"\"p two\" p3 p4  \""},
 
     /* Only single digits are supported so only %1 to %9. Shown here with %20
      * because %10 is a pain.
      */
-    {"Params20", "p", 0,
-     {" \"p0\"",
-      {"", "p0", NULL}, 0}},
+    {"Params20", "p", FALSE,
+     " \"p0\""},
 
     /* Only (double-)quotes have a special meaning. */
-    {"Params23456", "'p2 p3` p4\\ $even", 0x40,
-     {" \"'p2\" \"p3`\" \"p4\\\" \"$even\" \"\"",
-      {"", "'p2", "p3`", "p4\" $even \"", NULL}, 0}},
+    {"Params23456", "'p2 p3` p4\\ $even", FALSE,
+     " \"'p2\" \"p3`\" \"p4\\\" \"$even\" \"\""},
 
-    {"Params23456", "p=2 p-3 p4\tp4\rp4\np4", 0x1c2,
-     {" \"p=2\" \"p-3\" \"p4\tp4\rp4\np4\" \"\" \"\"",
-      {"", "p=2", "p-3", "p4\tp4\rp4\np4", "", "", NULL}, 0}},
+    {"Params23456", "p=2 p-3 p4\tp4\rp4\np4", TRUE,
+     " \"p=2\" \"p-3\" \"p4\tp4\rp4\np4\" \"\" \"\""},
 
     /* In unquoted strings, quotes are treated are a parameter separator just
      * like spaces! However they can be doubled to get a literal quote.
@@ -1465,125 +1460,102 @@ static const argify_tests_t argify_tests[] =
      * 2n   quotes -> n quotes
      * 2n+1 quotes -> n quotes and a parameter separator
      */
-    {"Params23456789", "one\"quote \"p four\" one\"quote p7", 0xff3,
-     {" \"one\" \"quote\" \"p four\" \"one\" \"quote\" \"p7\" \"\" \"\"",
-      {"", "one", "quote", "p four", "one", "quote", "p7", "", "", NULL}, 0}},
+    {"Params23456789", "one\"quote \"p four\" one\"quote p7", TRUE,
+     " \"one\" \"quote\" \"p four\" \"one\" \"quote\" \"p7\" \"\" \"\""},
 
-    {"Params23456789", "two\"\"quotes \"p three\" two\"\"quotes p5", 0xf2,
-     {" \"two\"quotes\" \"p three\" \"two\"quotes\" \"p5\" \"\" \"\" \"\" \"\"",
-      {"", "twoquotes p", "three twoquotes", "p5", "", "", "", "", NULL}, 0}},
+    {"Params23456789", "two\"\"quotes \"p three\" two\"\"quotes p5", TRUE,
+     " \"two\"quotes\" \"p three\" \"two\"quotes\" \"p5\" \"\" \"\" \"\" \"\""},
 
-    {"Params23456789", "three\"\"\"quotes \"p four\" three\"\"\"quotes p6", 0xff3,
-     {" \"three\"\" \"quotes\" \"p four\" \"three\"\" \"quotes\" \"p6\" \"\" \"\"",
-      {"", "three\"", "quotes", "p four", "three\"", "quotes", "p6", "", "", NULL}, 0}},
+    {"Params23456789", "three\"\"\"quotes \"p four\" three\"\"\"quotes p6", TRUE,
+     " \"three\"\" \"quotes\" \"p four\" \"three\"\" \"quotes\" \"p6\" \"\" \"\""},
 
-    {"Params23456789", "four\"\"\"\"quotes \"p three\" four\"\"\"\"quotes p5", 0xf3,
-     {" \"four\"\"quotes\" \"p three\" \"four\"\"quotes\" \"p5\" \"\" \"\" \"\" \"\"",
-      {"", "four\"quotes p", "three fourquotes p5 \"", "", "", "", NULL}, 0}},
+    {"Params23456789", "four\"\"\"\"quotes \"p three\" four\"\"\"\"quotes p5", TRUE,
+     " \"four\"\"quotes\" \"p three\" \"four\"\"quotes\" \"p5\" \"\" \"\" \"\" \"\""},
 
     /* Quoted strings cannot be continued by tacking on a non space character
      * either.
      */
-    {"Params23456", "\"p two\"p3 \"p four\"p5 p6", 0x1f3,
-     {" \"p two\" \"p3\" \"p four\" \"p5\" \"p6\"",
-      {"", "p two", "p3", "p four", "p5", "p6", NULL}, 0}},
+    {"Params23456", "\"p two\"p3 \"p four\"p5 p6", TRUE,
+     " \"p two\" \"p3\" \"p four\" \"p5\" \"p6\""},
 
     /* In quoted strings, the quotes are halved and an odd number closes the
      * string. Specifically:
      * 2n   quotes -> n quotes
      * 2n+1 quotes -> n quotes and closes the string and hence the parameter
      */
-    {"Params23456789", "\"one q\"uote \"p four\" \"one q\"uote p7", 0xff3,
-     {" \"one q\" \"uote\" \"p four\" \"one q\" \"uote\" \"p7\" \"\" \"\"",
-      {"", "one q", "uote", "p four", "one q", "uote", "p7", "", "", NULL}, 0}},
+    {"Params23456789", "\"one q\"uote \"p four\" \"one q\"uote p7", TRUE,
+     " \"one q\" \"uote\" \"p four\" \"one q\" \"uote\" \"p7\" \"\" \"\""},
 
-    {"Params23456789", "\"two \"\" quotes\" \"p three\" \"two \"\" quotes\" p5", 0x1ff3,
-     {" \"two \" quotes\" \"p three\" \"two \" quotes\" \"p5\" \"\" \"\" \"\" \"\"",
-      {"", "two ", "quotes p", "three two", " quotes", "p5", "", "", "", "", NULL}, 0}},
+    {"Params23456789", "\"two \"\" quotes\" \"p three\" \"two \"\" quotes\" p5", TRUE,
+     " \"two \" quotes\" \"p three\" \"two \" quotes\" \"p5\" \"\" \"\" \"\" \"\""},
 
-    {"Params23456789", "\"three q\"\"\"uotes \"p four\" \"three q\"\"\"uotes p7", 0xff3,
-     {" \"three q\"\" \"uotes\" \"p four\" \"three q\"\" \"uotes\" \"p7\" \"\" \"\"",
-      {"", "three q\"", "uotes", "p four", "three q\"", "uotes", "p7", "", "", NULL}, 0}},
+    {"Params23456789", "\"three q\"\"\"uotes \"p four\" \"three q\"\"\"uotes p7", TRUE,
+     " \"three q\"\" \"uotes\" \"p four\" \"three q\"\" \"uotes\" \"p7\" \"\" \"\""},
 
-    {"Params23456789", "\"four \"\"\"\" quotes\" \"p three\" \"four \"\"\"\" quotes\" p5", 0xff3,
-     {" \"four \"\" quotes\" \"p three\" \"four \"\" quotes\" \"p5\" \"\" \"\" \"\" \"\"",
-      {"", "four \"", "quotes p", "three four", "", "quotes p5 \"", "", "", "", NULL}, 0}},
+    {"Params23456789", "\"four \"\"\"\" quotes\" \"p three\" \"four \"\"\"\" quotes\" p5", TRUE,
+     " \"four \"\" quotes\" \"p three\" \"four \"\" quotes\" \"p5\" \"\" \"\" \"\" \"\""},
 
     /* The quoted string rules also apply to consecutive quotes at the start
      * of a parameter but don't count the opening quote!
      */
-    {"Params23456789", "\"\"twoquotes \"p four\" \"\"twoquotes p7", 0xbf3,
-     {" \"\" \"twoquotes\" \"p four\" \"\" \"twoquotes\" \"p7\" \"\" \"\"",
-      {"", "", "twoquotes", "p four", "", "twoquotes", "p7", "", "", NULL}, 0}},
+    {"Params23456789", "\"\"twoquotes \"p four\" \"\"twoquotes p7", TRUE,
+     " \"\" \"twoquotes\" \"p four\" \"\" \"twoquotes\" \"p7\" \"\" \"\""},
 
-    {"Params23456789", "\"\"\"three quotes\" \"p three\" \"\"\"three quotes\" p5", 0x6f3,
-     {" \"\"three quotes\" \"p three\" \"\"three quotes\" \"p5\" \"\" \"\" \"\" \"\"",
-      {"", "three", "quotes p", "three \"three", "quotes p5 \"", "", "", "", NULL}, 0}},
+    {"Params23456789", "\"\"\"three quotes\" \"p three\" \"\"\"three quotes\" p5", TRUE,
+     " \"\"three quotes\" \"p three\" \"\"three quotes\" \"p5\" \"\" \"\" \"\" \"\""},
 
-    {"Params23456789", "\"\"\"\"fourquotes \"p four\" \"\"\"\"fourquotes p7", 0xbf3,
-     {" \"\"\" \"fourquotes\" \"p four\" \"\"\" \"fourquotes\" \"p7\" \"\" \"\"",
-      {"", "\"", "fourquotes", "p four", "\"", "fourquotes", "p7", "", "", NULL}, 0}},
+    {"Params23456789", "\"\"\"\"fourquotes \"p four\" \"\"\"\"fourquotes p7", TRUE,
+     " \"\"\" \"fourquotes\" \"p four\" \"\"\" \"fourquotes\" \"p7\" \"\" \"\""},
 
     /* An unclosed quoted string gets lost! */
-    {"Params23456", "p2 \"p3\" \"p4 is lost", 0x1c3,
-     {" \"p2\" \"p3\" \"\" \"\" \"\"",
-      {"", "p2", "p3", "", "", "", NULL}, 0},
-     {" \"p2\" \"p3\" \"p3\" \"\" \"\"",
-       {"", "p2", "p3", "p3", "", "", NULL}, 0}},
+    {"Params23456", "p2 \"p3\" \"p4 is lost", TRUE,
+     " \"p2\" \"p3\" \"\" \"\" \"\"",
+     " \"p2\" \"p3\" \"p3\" \"\" \"\""},    /* NT4/2k */
 
     /* Backslashes have no special meaning even when preceding quotes. All
      * they do is start an unquoted string.
      */
-    {"Params23456", "\\\"p\\three \"pfour\\\" pfive", 0x73,
-     {" \"\\\" \"p\\three\" \"pfour\\\" \"pfive\" \"\"",
-      {"", "\" p\\three pfour\"", "pfive", "", NULL}, 0}},
+    {"Params23456", "\\\"p\\three \"pfour\\\" pfive", TRUE,
+     " \"\\\" \"p\\three\" \"pfour\\\" \"pfive\" \"\""},
 
     /* Environment variables are left untouched. */
-    {"Params23456", "%TMPDIR% %t %c", 0,
-     {" \"%TMPDIR%\" \"%t\" \"%c\" \"\" \"\"",
-      {"", "%TMPDIR%", "%t", "%c", "", "", NULL}, 0}},
+    {"Params23456", "%TMPDIR% %t %c", FALSE,
+     " \"%TMPDIR%\" \"%t\" \"%c\" \"\" \"\""},
 
     /* %~2 is equivalent to %*. However %~3 and higher include the spaces
      * before the parameter!
      * (but not the previous parameter's closing quote fortunately)
      */
-    {"Params2345Etc", "p2  p3 \"p4\"  p5 p6 ", 0x3f3,
-     {" ~2=\"p2  p3 \"p4\"  p5 p6 \" ~3=\"  p3 \"p4\"  p5 p6 \" ~4=\" \"p4\"  p5 p6 \" ~5=  p5 p6 ",
-      {"", "~2=p2  p3 p4  p5 p6 ", "~3=  p3 p4  p5 p6 ", "~4= p4  p5 p6 ", "~5=", "p5", "p6", NULL}, 0}},
+    {"Params2345Etc", "p2  p3 \"p4\"  p5 p6 ", TRUE,
+     " ~2=\"p2  p3 \"p4\"  p5 p6 \" ~3=\"  p3 \"p4\"  p5 p6 \" ~4=\" \"p4\"  p5 p6 \" ~5=  p5 p6 "},
 
     /* %~n works even if there is no nth parameter. */
-    {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8   ", 0x12,
-     {" ~9=\"   \"",
-      {"", "~9=   ", NULL}, 0}},
+    {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8   ", TRUE,
+     " ~9=\"   \""},
 
-    {"Params9Etc", "p2 p3 p4 p5 p6 p7   ", 0x12,
-     {" ~9=\"\"",
-      {"", "~9=", NULL}, 0}},
+    {"Params9Etc", "p2 p3 p4 p5 p6 p7   ", TRUE,
+     " ~9=\"\""},
 
     /* The %~n directives also transmit the tenth parameter and beyond. */
-    {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 and beyond!", 0x12,
-     {" ~9=\" p9 p10 p11 and beyond!\"",
-      {"", "~9= p9 p10 p11 and beyond!", NULL}, 0}},
+    {"Params9Etc", "p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 and beyond!", TRUE,
+     " ~9=\" p9 p10 p11 and beyond!\""},
 
     /* Bad formatting directives lose their % sign, except those followed by
      * a tilde! Environment variables are not expanded but lose their % sign.
      */
-    {"ParamsBad", "p2 p3 p4 p5", 0x12,
-     {" \"% - %~ %~0 %~1 %~a %~* a b c TMPDIR\"",
-      {"", "% - %~ %~0 %~1 %~a %~* a b c TMPDIR", NULL}, 0}},
+    {"ParamsBad", "p2 p3 p4 p5", TRUE,
+     " \"% - %~ %~0 %~1 %~a %~* a b c TMPDIR\""},
 
-    {NULL, NULL, 0, {NULL, {NULL}, 0}}
+    {0}
 };
 
 static void test_argify(void)
 {
-    BOOL has_cl2a = TRUE;
     char fileA[MAX_PATH], params[2*MAX_PATH+12];
     INT_PTR rc;
     const argify_tests_t* test;
-    const cmdline_tests_t *bad;
+    const char *bad;
     const char* cmd;
-    unsigned i, count;
 
     /* Test with a long parameter */
     for (rc = 0; rc < MAX_PATH; rc++)
@@ -1616,21 +1588,11 @@ static void test_argify(void)
     test = argify_tests;
     while (test->params)
     {
-        bad = test->broken.cmd ? &test->broken : &test->cmd;
+        bad = test->broken ? test->broken : test->cmd;
 
-        /* trace("***** verb='%s' params='%s'\n", test->verb, test->params); */
         rc = shell_execute_ex(SEE_MASK_DOENVSUBST, test->verb, fileA, test->params, NULL, NULL);
         okShell(rc > 32, "failed: rc=%lu\n", rc);
 
-        count = 0;
-        while (test->cmd.args[count])
-            count++;
-        /* +4 for the shlexec arguments, -1 because of the added ""
-         * argument for the CommandLineToArgvW() tests.
-         */
-        todo_wine_if(test->todo & 0x1)
-            okChildInt("argcA", 4 + count - 1);
-
         cmd = getChildString("Child", "cmdlineA");
         /* Our commands are such that the verb immediately precedes the
          * part we are interested in.
@@ -1638,20 +1600,9 @@ static void test_argify(void)
         if (cmd) cmd = strstr(cmd, test->verb);
         if (cmd) cmd += strlen(test->verb);
         if (!cmd) cmd = "(null)";
-        todo_wine_if(test->todo & 0x2)
-            okShell(!strcmp(cmd, test->cmd.cmd) || broken(!strcmp(cmd, bad->cmd)),
-                    "the cmdline is '%s' instead of '%s'\n", cmd, test->cmd.cmd);
-
-        for (i = 0; i < count - 1; i++)
-        {
-            char argname[18];
-            sprintf(argname, "argvA%d", 4 + i);
-            todo_wine_if(test->todo & (1 << (i+4)))
-                okChildStringBroken(argname, test->cmd.args[i+1], bad->args[i+1]);
-        }
-
-        if (has_cl2a)
-            has_cl2a = test_one_cmdline(&(test->cmd));
+        todo_wine_if(test->todo)
+            okShell(!strcmp(cmd, test->cmd) || broken(!strcmp(cmd, bad)),
+                    "expected '%s', got '%s'\n", cmd, test->cmd);
         test++;
     }
 }
@@ -1861,7 +1812,7 @@ static void test_fileurls(void)
         return;
     }
 
-    get_long_path_name(tmpdir, longtmpdir, sizeof(longtmpdir)/sizeof(*longtmpdir));
+    get_long_path_name(tmpdir, longtmpdir, ARRAY_SIZE(longtmpdir));
     SetEnvironmentVariableA("urlprefix", "file:///");
 
     test=fileurl_tests;
@@ -2781,7 +2732,7 @@ static void init_test(void)
 
     /* Setup the test shortcuts */
     sprintf(filename, "%s\\test_shortcut_shlexec.lnk", tmpdir);
-    MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, sizeof(lnkfile)/sizeof(*lnkfile));
+    MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, ARRAY_SIZE(lnkfile));
     desc.description=NULL;
     desc.workdir=NULL;
     sprintf(filename, "%s\\test file.shlexec", tmpdir);
@@ -2795,7 +2746,7 @@ static void init_test(void)
     create_lnk(lnkfile, &desc, 0);
 
     sprintf(filename, "%s\\test_shortcut_exe.lnk", tmpdir);
-    MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, sizeof(lnkfile)/sizeof(*lnkfile));
+    MultiByteToWideChar(CP_ACP, 0, filename, -1, lnkfile, ARRAY_SIZE(lnkfile));
     desc.description=NULL;
     desc.workdir=NULL;
     desc.path=argv0;
index 72ca1e7..9768e18 100644 (file)
@@ -60,25 +60,6 @@ static const WCHAR UNICODE_PATH[] = {'c',':','\\',0x00ae,'\0','\0'};
     /* "c:\®" can be used in all codepages */
     /* Double-null termination needed for pFrom field of SHFILEOPSTRUCT */
 
-static HMODULE hshell32;
-static int (WINAPI *pSHCreateDirectoryExA)(HWND, LPCSTR, LPSECURITY_ATTRIBUTES);
-static int (WINAPI *pSHCreateDirectoryExW)(HWND, LPCWSTR, LPSECURITY_ATTRIBUTES);
-static int (WINAPI *pSHFileOperationW)(LPSHFILEOPSTRUCTW);
-static DWORD_PTR (WINAPI *pSHGetFileInfoW)(LPCWSTR, DWORD , SHFILEINFOW*, UINT, UINT);
-static int (WINAPI *pSHPathPrepareForWriteA)(HWND, IUnknown*, LPCSTR, DWORD);
-static int (WINAPI *pSHPathPrepareForWriteW)(HWND, IUnknown*, LPCWSTR, DWORD);
-
-static void InitFunctionPointers(void)
-{
-    hshell32 = GetModuleHandleA("shell32.dll");
-    pSHCreateDirectoryExA = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExA");
-    pSHCreateDirectoryExW = (void*)GetProcAddress(hshell32, "SHCreateDirectoryExW");
-    pSHFileOperationW = (void*)GetProcAddress(hshell32, "SHFileOperationW");
-    pSHGetFileInfoW = (void*)GetProcAddress(hshell32, "SHGetFileInfoW");
-    pSHPathPrepareForWriteA = (void*)GetProcAddress(hshell32, "SHPathPrepareForWriteA");
-    pSHPathPrepareForWriteW = (void*)GetProcAddress(hshell32, "SHPathPrepareForWriteW");
-}
-
 /* creates a file with the specified name for tests */
 static void createTestFile(const CHAR *name)
 {
@@ -196,6 +177,7 @@ static void test_get_file_info(void)
     SHFILEINFOA shfi, shfi2;
     SHFILEINFOW shfiw;
     char notepad[MAX_PATH];
+    HANDLE unset_icon;
 
     /* Test whether fields of SHFILEINFOA are always cleared */
     memset(&shfi, 0xcf, sizeof(shfi));
@@ -211,23 +193,15 @@ static void test_get_file_info(void)
        broken(shfi.dwAttributes != 0xcfcfcfcf), /* NT4 doesn't clear but sets this field */
        "SHGetFileInfoA('' | 0) should not clear dwAttributes\n");
 
-    if (pSHGetFileInfoW)
-    {
-        HANDLE unset_icon;
-        /* Test whether fields of SHFILEINFOW are always cleared */
-        memset(&shfiw, 0xcf, sizeof(shfiw));
-        memset(&unset_icon, 0xcf, sizeof(unset_icon));
-        rc=pSHGetFileInfoW(NULL, 0, &shfiw, sizeof(shfiw), 0);
-        ok(!rc, "SHGetFileInfoW(NULL | 0) should fail\n");
-        ok(shfiw.hIcon == unset_icon, "SHGetFileInfoW(NULL | 0) should not clear hIcon\n");
-        ok(shfiw.szDisplayName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szDisplayName[0]\n");
-        ok(shfiw.szTypeName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szTypeName[0]\n");
-        ok(shfiw.iIcon == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear iIcon\n");
-        ok(shfiw.dwAttributes == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear dwAttributes\n");
-    }
-    else
-        win_skip("SHGetFileInfoW is not available\n");
-
+    memset(&shfiw, 0xcf, sizeof(shfiw));
+    memset(&unset_icon, 0xcf, sizeof(unset_icon));
+    rc = SHGetFileInfoW(NULL, 0, &shfiw, sizeof(shfiw), 0);
+    ok(!rc, "SHGetFileInfoW(NULL | 0) should fail\n");
+    ok(shfiw.hIcon == unset_icon, "SHGetFileInfoW(NULL | 0) should not clear hIcon\n");
+    ok(shfiw.szDisplayName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szDisplayName[0]\n");
+    ok(shfiw.szTypeName[0] == 0xcfcf, "SHGetFileInfoW(NULL | 0) should not clear szTypeName[0]\n");
+    ok(shfiw.iIcon == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear iIcon\n");
+    ok(shfiw.dwAttributes == 0xcfcfcfcf, "SHGetFileInfoW(NULL | 0) should not clear dwAttributes\n");
 
     /* Test some flag combinations that MSDN claims are not allowed,
      * but which work anyway
@@ -396,22 +370,9 @@ static void test_get_file_info_iconlist(void)
        "SHGetFileInfoA(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL), unexpected dwAttributes\n");
     /* Don't release hSysImageList here (and in similar places below) because of the broken reference behaviour of XP and 2003. */
 
-    if (!pSHGetFileInfoW)
-    {
-        win_skip("SHGetFileInfoW is not available\n");
-        ILFree(pidList);
-        return;
-    }
-
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST) pSHGetFileInfoW((const WCHAR *)pidList, 0,
-            &shInfow, sizeof(shInfow),
-           SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_PIDL);
-    if (!hSysImageList)
-    {
-        win_skip("SHGetFileInfoW is not implemented\n");
-        return;
-    }
+    hSysImageList = (HIMAGELIST) SHGetFileInfoW((const WCHAR *)pidList, 0,
+        &shInfow, sizeof(shInfow), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_PIDL);
     ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
     todo_wine ok(shInfow.hIcon == 0, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear hIcon\n");
     ok(shInfow.szTypeName[0] == 0, "SHGetFileInfoW(CSIDL_DESKTOP, SHGFI_SYSICONINDEX|SHGFI_SMALLICON|SHGFI_PIDL) did not clear szTypeName[0]\n");
@@ -422,7 +383,7 @@ static void test_get_file_info_iconlist(void)
 
     /* Various suposidly invalid flag testing */
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
     ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
     ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
@@ -431,7 +392,7 @@ static void test_get_file_info_iconlist(void)
        "unexpected dwAttributes\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
     ok(hr != 0, " SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
     ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
@@ -440,7 +401,7 @@ static void test_get_file_info_iconlist(void)
     todo_wine ok(shInfow.dwAttributes==0,"dwAttributes not set\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON);
     ok(hr != 0, "SHGFI_ICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON Failed\n");
     ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
@@ -449,7 +410,7 @@ static void test_get_file_info_iconlist(void)
     todo_wine ok(shInfow.dwAttributes==0,"dwAttributes not set\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_LARGEICON);
     ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, small_list);
     ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
@@ -458,28 +419,28 @@ static void test_get_file_info_iconlist(void)
        "unexpected dwAttributes\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_OPENICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
     ok(hr != 0, "SHGFI_OPENICON|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
     todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
     ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
     ok(hr != 0, "SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
     todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
     ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON);
     ok(hr != 0, "SHGFI_SHELLICONSIZE|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON Failed\n");
     todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
     ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|
         SHGFI_ATTRIBUTES);
     ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
@@ -487,7 +448,7 @@ static void test_get_file_info_iconlist(void)
     ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|
         SHGFI_EXETYPE);
     todo_wine ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
@@ -497,21 +458,21 @@ static void test_get_file_info_iconlist(void)
        "unexpected dwAttributes\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
         SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_EXETYPE);
     todo_wine ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_EXETYPE Failed\n");
     todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
     ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
         SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_ATTRIBUTES);
     ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_ATTRIBUTES Failed\n");
     todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
     ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|
         SHGFI_ATTRIBUTES);
     ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, large_list);
@@ -520,7 +481,7 @@ static void test_get_file_info_iconlist(void)
     ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
         SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE);
     todo_wine ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, large_list);
     ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
@@ -529,21 +490,21 @@ static void test_get_file_info_iconlist(void)
        "unexpected dwAttributes\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
         SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE);
     todo_wine ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_EXETYPE Failed\n");
     todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
     ok(shInfow.dwAttributes==0xcfcfcfcf,"dwAttributes modified\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hr = pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hr = SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
         SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES);
     ok(hr != 0, "SHGFI_USEFILEATTRIBUTES|SHGFI_PIDL|SHGFI_ATTRIBUTES Failed\n");
     todo_wine ok(shInfow.iIcon==0xcfcfcfcf, "Icon Index Modified\n");
     ok(shInfow.dwAttributes!=0xcfcfcfcf,"dwAttributes not set\n");
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SYSICONINDEX|SHGFI_PIDL|SHGFI_SMALLICON|SHGFI_SHELLICONSIZE|SHGFI_ICON);
     ok(hSysImageList == (HIMAGELIST)small_list, "got %p expect %p\n", hSysImageList, small_list);
     ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
@@ -551,7 +512,7 @@ static void test_get_file_info_iconlist(void)
     DestroyIcon( shInfow.hIcon );
 
     memset(&shInfow, 0xcf, sizeof(shInfow));
-    hSysImageList = (HIMAGELIST)pSHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
+    hSysImageList = (HIMAGELIST)SHGetFileInfoW((const WCHAR *)pidList, 0, &shInfow, sizeof(shInfow),
            SHGFI_SYSICONINDEX|SHGFI_PIDL|SHGFI_SHELLICONSIZE|SHGFI_ICON);
     ok(hSysImageList == (HIMAGELIST)large_list, "got %p expect %p\n", hSysImageList, small_list);
     ok(shInfow.iIcon!=0xcfcfcfcf, "Icon Index Missing\n");
@@ -1912,6 +1873,28 @@ static void test_copy(void)
     ok(retval != ERROR_SUCCESS, "Unexpected ERROR_SUCCESS\n");
     ok(!shfo.fAnyOperationsAborted, "Didn't expect aborted operations\n");
     ok(GetLastError() == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", GetLastError());
+
+    /* test with / */
+    CreateDirectoryA("dir", NULL);
+    CreateDirectoryA("dir\\subdir", NULL);
+    createTestFile("dir\\subdir\\aa.txt");
+    shfo.pFrom = "dir/subdir/aa.txt\0";
+    shfo.pTo = "dir\\destdir/aa.txt\0";
+    shfo.fFlags = FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_SILENT | FOF_NOERRORUI;
+    retval = SHFileOperationA(&shfo);
+    if (dir_exists("dir\\destdir"))
+    {
+        ok(retval == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", retval);
+        ok(DeleteFileA("dir\\destdir\\aa.txt"), "Expected file to exist\n");
+        ok(RemoveDirectoryA("dir\\destdir"), "Expected dir to exist\n");
+    }
+    else
+    {
+        expect_retval(ERROR_CANCELLED, DE_OPCANCELLED /* WinXp, Win2k */);
+    }
+    ok(DeleteFileA("dir\\subdir\\aa.txt"), "Expected file to exist\n");
+    ok(RemoveDirectoryA("dir\\subdir"), "Expected dir to exist\n");
+    ok(RemoveDirectoryA("dir"), "Expected dir to exist\n");
 }
 
 /* tests the FO_MOVE action */
@@ -1964,6 +1947,30 @@ static void test_move(void)
     clean_after_shfo_tests();
     init_shfo_tests();
 
+    /* same tests above, but with / */
+    set_curr_dir_path(from, "testdir2/*.*\0");
+    set_curr_dir_path(to, "test4.txt\0");
+    retval = SHFileOperationA(&shfo);
+    ok(retval == ERROR_SUCCESS ||
+       broken(retval == ERROR_FILE_NOT_FOUND), /* WinXp, Win2k3 */
+       "Expected ERROR_SUCCESS, got %d\n", retval);
+    if (retval == ERROR_SUCCESS)
+    {
+        ok(!shfo.fAnyOperationsAborted, "fAnyOperationsAborted %d\n", shfo.fAnyOperationsAborted);
+
+        ok(dir_exists("testdir2"), "dir should not be moved\n");
+        ok(!file_exists("testdir2\\one.txt"), "file should be moved\n");
+        ok(!dir_exists("testdir2\\nested"), "dir should be moved\n");
+        ok(!file_exists("testdir2\\nested\\two.txt"), "file should be moved\n");
+
+        ok(file_exists("test4.txt\\one.txt"), "file should exist\n");
+        ok(dir_exists("test4.txt\\nested"), "dir should exist\n");
+        ok(file_exists("test4.txt\\nested\\two.txt"), "file should exist\n");
+    }
+
+    clean_after_shfo_tests();
+    init_shfo_tests();
+
     shfo.hwnd = NULL;
     shfo.wFunc = FO_MOVE;
     shfo.pFrom = from;
@@ -2343,22 +2350,16 @@ static void test_sh_create_dir(void)
     CHAR path[MAX_PATH];
     int ret;
 
-    if(!pSHCreateDirectoryExA)
-    {
-        win_skip("skipping SHCreateDirectoryExA tests\n");
-        return;
-    }
-
     set_curr_dir_path(path, "testdir2\\test4.txt\0");
-    ret = pSHCreateDirectoryExA(NULL, path, NULL);
+    ret = SHCreateDirectoryExA(NULL, path, NULL);
     ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory recursively, ret = %d\n", ret);
     ok(file_exists("testdir2"), "The first directory is not created\n");
     ok(file_exists("testdir2\\test4.txt"), "The second directory is not created\n");
 
-    ret = pSHCreateDirectoryExA(NULL, path, NULL);
+    ret = SHCreateDirectoryExA(NULL, path, NULL);
     ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
 
-    ret = pSHCreateDirectoryExA(NULL, "c:\\testdir3", NULL);
+    ret = SHCreateDirectoryExA(NULL, "c:\\testdir3", NULL);
     ok(ERROR_SUCCESS == ret, "SHCreateDirectoryEx failed to create directory, ret = %d\n", ret);
     ok(file_exists("c:\\testdir3"), "The directory is not created\n");
 }
@@ -2370,43 +2371,37 @@ static void test_sh_path_prepare(void)
     CHAR UNICODE_PATH_A[MAX_PATH];
     BOOL UsedDefaultChar;
 
-    if(!pSHPathPrepareForWriteA)
-    {
-       win_skip("skipping SHPathPrepareForWriteA tests\n");
-       return;
-    }
-
     /* directory exists, SHPPFW_NONE */
     set_curr_dir_path(path, "testdir2\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
     ok(res == S_OK, "res == 0x%08x, expected S_OK\n", res);
 
     /* directory exists, SHPPFW_IGNOREFILENAME */
     set_curr_dir_path(path, "testdir2\\test4.txt\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME);
     ok(res == S_OK, "res == 0x%08x, expected S_OK\n", res);
 
     /* directory exists, SHPPFW_DIRCREATE */
     set_curr_dir_path(path, "testdir2\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
     ok(res == S_OK, "res == 0x%08x, expected S_OK\n", res);
 
     /* directory exists, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE */
     set_curr_dir_path(path, "testdir2\\test4.txt\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE);
     ok(res == S_OK, "res == 0x%08x, expected S_OK\n", res);
     ok(!file_exists("nonexistent\\"), "nonexistent\\ exists but shouldn't\n");
 
     /* file exists, SHPPFW_NONE */
     set_curr_dir_path(path, "test1.txt\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
     ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) ||
        res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */
        res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */
        "Unexpected result : 0x%08x\n", res);
 
     /* file exists, SHPPFW_DIRCREATE */
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
     ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) ||
        res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */
        res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */
@@ -2414,53 +2409,47 @@ static void test_sh_path_prepare(void)
 
     /* file exists, SHPPFW_NONE, trailing \ */
     set_curr_dir_path(path, "test1.txt\\\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
     ok(res == HRESULT_FROM_WIN32(ERROR_DIRECTORY) ||
        res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) || /* WinMe */
        res == HRESULT_FROM_WIN32(ERROR_INVALID_NAME), /* Vista */
        "Unexpected result : 0x%08x\n", res);
 
     /* relative path exists, SHPPFW_DIRCREATE */
-    res = pSHPathPrepareForWriteA(0, 0, ".\\testdir2", SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteA(0, 0, ".\\testdir2", SHPPFW_DIRCREATE);
     ok(res == S_OK, "res == 0x%08x, expected S_OK\n", res);
 
     /* relative path doesn't exist, SHPPFW_DIRCREATE -- Windows does not create the directory in this case */
-    res = pSHPathPrepareForWriteA(0, 0, ".\\testdir2\\test4.txt", SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteA(0, 0, ".\\testdir2\\test4.txt", SHPPFW_DIRCREATE);
     ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == 0x%08x, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
     ok(!file_exists(".\\testdir2\\test4.txt\\"), ".\\testdir2\\test4.txt\\ exists but shouldn't\n");
 
     /* directory doesn't exist, SHPPFW_NONE */
     set_curr_dir_path(path, "nonexistent\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_NONE);
     ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == 0x%08x, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
 
     /* directory doesn't exist, SHPPFW_IGNOREFILENAME */
     set_curr_dir_path(path, "nonexistent\\notreal\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME);
     ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == 0x%08x, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
     ok(!file_exists("nonexistent\\notreal"), "nonexistent\\notreal exists but shouldn't\n");
     ok(!file_exists("nonexistent\\"), "nonexistent\\ exists but shouldn't\n");
 
     /* directory doesn't exist, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE */
     set_curr_dir_path(path, "testdir2\\test4.txt\\\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_IGNOREFILENAME|SHPPFW_DIRCREATE);
     ok(res == S_OK, "res == 0x%08x, expected S_OK\n", res);
     ok(file_exists("testdir2\\test4.txt\\"), "testdir2\\test4.txt doesn't exist but should\n");
 
     /* nested directory doesn't exist, SHPPFW_DIRCREATE */
     set_curr_dir_path(path, "nonexistent\\notreal\0");
-    res = pSHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteA(0, 0, path, SHPPFW_DIRCREATE);
     ok(res == S_OK, "res == 0x%08x, expected S_OK\n", res);
     ok(file_exists("nonexistent\\notreal"), "nonexistent\\notreal doesn't exist but should\n");
 
     /* SHPPFW_ASKDIRCREATE, SHPPFW_NOWRITECHECK, and SHPPFW_MEDIACHECKONLY are untested */
 
-    if(!pSHPathPrepareForWriteW)
-    {
-        win_skip("Skipping SHPathPrepareForWriteW tests\n");
-        return;
-    }
-
     SetLastError(0xdeadbeef);
     UsedDefaultChar = FALSE;
     if (WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, UNICODE_PATH, -1, UNICODE_PATH_A, sizeof(UNICODE_PATH_A), NULL, &UsedDefaultChar) == 0)
@@ -2476,22 +2465,22 @@ static void test_sh_path_prepare(void)
 
     /* unicode directory doesn't exist, SHPPFW_NONE */
     RemoveDirectoryA(UNICODE_PATH_A);
-    res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE);
+    res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE);
     ok(res == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), "res == %08x, expected HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)\n", res);
     ok(!file_exists(UNICODE_PATH_A), "unicode path was created but shouldn't be\n");
     RemoveDirectoryA(UNICODE_PATH_A);
 
     /* unicode directory doesn't exist, SHPPFW_DIRCREATE */
-    res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE);
     ok(res == S_OK, "res == %08x, expected S_OK\n", res);
     ok(file_exists(UNICODE_PATH_A), "unicode path should've been created\n");
 
     /* unicode directory exists, SHPPFW_NONE */
-    res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE);
+    res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_NONE);
     ok(res == S_OK, "ret == %08x, expected S_OK\n", res);
 
     /* unicode directory exists, SHPPFW_DIRCREATE */
-    res = pSHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE);
+    res = SHPathPrepareForWriteW(0, 0, UNICODE_PATH, SHPPFW_DIRCREATE);
     ok(res == S_OK, "ret == %08x, expected S_OK\n", res);
     RemoveDirectoryA(UNICODE_PATH_A);
 }
@@ -2559,12 +2548,6 @@ static void test_unicode(void)
     HANDLE file;
     static const WCHAR UNICODE_PATH_TO[] = {'c',':','\\',0x00ae,0x00ae,'\0'};
 
-    if (!pSHFileOperationW)
-    {
-        skip("SHFileOperationW() is missing\n");
-        return;
-    }
-
     shfoW.hwnd = NULL;
     shfoW.wFunc = FO_DELETE;
     shfoW.pFrom = UNICODE_PATH;
@@ -2594,7 +2577,7 @@ static void test_unicode(void)
 
     /* Try to delete a file with unicode filename */
     ok(file_existsW(UNICODE_PATH), "The file does not exist\n");
-    ret = pSHFileOperationW(&shfoW);
+    ret = SHFileOperationW(&shfoW);
     ok(!ret, "File is not removed, ErrorCode: %d\n", ret);
     ok(!file_existsW(UNICODE_PATH), "The file should have been removed\n");
 
@@ -2602,31 +2585,25 @@ static void test_unicode(void)
     createTestFileW(UNICODE_PATH);
     shfoW.fFlags |= FOF_ALLOWUNDO;
     ok(file_existsW(UNICODE_PATH), "The file does not exist\n");
-    ret = pSHFileOperationW(&shfoW);
+    ret = SHFileOperationW(&shfoW);
     ok(!ret, "File is not removed, ErrorCode: %d\n", ret);
     ok(!file_existsW(UNICODE_PATH), "The file should have been removed\n");
 
-    if(!pSHCreateDirectoryExW)
-    {
-        skip("Skipping SHCreateDirectoryExW tests\n");
-        return;
-    }
-
     /* Try to delete a directory with unicode filename */
-    ret = pSHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
+    ret = SHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
     ok(!ret, "SHCreateDirectoryExW returned %d\n", ret);
     ok(file_existsW(UNICODE_PATH), "The directory is not created\n");
     shfoW.fFlags &= ~FOF_ALLOWUNDO;
-    ret = pSHFileOperationW(&shfoW);
+    ret = SHFileOperationW(&shfoW);
     ok(!ret, "Directory is not removed, ErrorCode: %d\n", ret);
     ok(!file_existsW(UNICODE_PATH), "The directory should have been removed\n");
 
     /* Try to trash a directory with unicode filename */
-    ret = pSHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
+    ret = SHCreateDirectoryExW(NULL, UNICODE_PATH, NULL);
     ok(!ret, "SHCreateDirectoryExW returned %d\n", ret);
     ok(file_existsW(UNICODE_PATH), "The directory was not created\n");
     shfoW.fFlags |= FOF_ALLOWUNDO;
-    ret = pSHFileOperationW(&shfoW);
+    ret = SHFileOperationW(&shfoW);
     ok(!ret, "Directory is not removed, ErrorCode: %d\n", ret);
     ok(!file_existsW(UNICODE_PATH), "The directory should have been removed\n");
 
@@ -2711,8 +2688,6 @@ static BOOL is_old_shell32(void)
 
 START_TEST(shlfileop)
 {
-    InitFunctionPointers();
-
     clean_after_shfo_tests();
 
     init_shfo_tests();
index 2ee91ef..f2bd640 100644 (file)
@@ -63,6 +63,10 @@ static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
 static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
 static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
 static BOOL (WINAPI *pSHGetPathFromIDListEx)(PCIDLIST_ABSOLUTE,WCHAR*,DWORD,GPFIDL_FLAGS);
+#ifdef __REACTOS__
+typedef SHFOLDERCUSTOMSETTINGSW SHFOLDERCUSTOMSETTINGS, *LPSHFOLDERCUSTOMSETTINGS;
+#endif
+static HRESULT (WINAPI *pSHGetSetFolderCustomSettings)(LPSHFOLDERCUSTOMSETTINGS,PCWSTR,DWORD);
 
 static WCHAR *make_wstr(const char *str)
 {
@@ -116,6 +120,7 @@ static void init_function_pointers(void)
     MAKEFUNC(SHGetItemFromObject);
     MAKEFUNC(SHCreateDefaultContextMenu);
     MAKEFUNC(SHGetPathFromIDListEx);
+    MAKEFUNC(SHGetSetFolderCustomSettings);
 #undef MAKEFUNC
 
     /* test named exports */
@@ -172,108 +177,103 @@ static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
   return lpszPath;
 }
 
+static struct
+{
+    WCHAR path[MAX_PATH];
+    HRESULT hr;
+    int todo;
+} parse_tests[] = {
+    {{'c',':','\\',0}, S_OK},
+    {{'c',':','\\','\\',0}, E_INVALIDARG, 1},
+    {{'c',':','\\','f','a','k','e',0}, 0x80070002}, /* ERROR_FILE_NOT_FOUND */
+    {{'c',':','f','a','k','e',0}, E_INVALIDARG, 1},
+    {{'c',':','/',0}, E_INVALIDARG, 1},
+    {{'c',':','\\','w','i','n','d','o','w','s',0}, S_OK},
+    {{'c',':','\\','w','i','n','d','o','w','s','\\',0}, S_OK},
+    {{'c',':','\\','w','i','n','d','o','w','s','\\','.',0}, E_INVALIDARG, 1},
+    {{'c',':','\\','w','i','n','d','o','w','s','\\','.','.',0}, E_INVALIDARG, 1},
+    {{'.',0}, E_INVALIDARG, 1},
+    {{'.','.',0}, E_INVALIDARG, 1},
+    {{'t','e','s','t',0}, 0x80070002},
+    {{'t','e','s','t','\\',0}, 0x80070002},
+    {{'s','u','b','\\','d','i','r',0}, 0x80070002},
+    {{'s','u','b','/','d','i','r',0}, E_INVALIDARG, 1},
+    {{'h','t','t','p',':',0}, S_OK, 1},
+    {{'h','t','t','p',':','t','e','s','t',0}, S_OK, 1},
+    {{'h','t','t','p',':','\\','t','e','s','t',0}, S_OK, 1},
+    {{'x','x',':',0}, S_OK, 1},
+};
+
 static void test_ParseDisplayName(void)
 {
+    static WCHAR testdirW[] = {'p','a','r','s','e','t','e','s','t',0};
+    static WCHAR backslashW[] = {'\\',0};
+    WCHAR buffer[MAX_PATH], buffer2[MAX_PATH];
+    IShellFolder *desktop;
+    ITEMIDLIST *pidl;
     HRESULT hr;
-    IShellFolder *IDesktopFolder;
-    static const char *cNonExistDir1A = "c:\\nonexist_subdir";
-    static const char *cNonExistDir2A = "c:\\\\nonexist_subdir";
-    static const char *cInetTestA = "http:\\yyy";
-    static const char *cInetTest2A = "xx:yyy";
-    DWORD res;
-    WCHAR cTestDirW [MAX_PATH] = {0};
-    ITEMIDLIST *newPIDL;
     BOOL bRes;
+    int i;
 
-    hr = SHGetDesktopFolder(&IDesktopFolder);
+    hr = SHGetDesktopFolder(&desktop);
     ok(hr == S_OK, "Expected SHGetDesktopFolder to return S_OK, got 0x%08x\n", hr);
-    if(hr != S_OK) return;
-
-    if (pSHCreateShellItem)
-    {
-        if (0)
-        {
-            /* null name and pidl, crashes on Windows 8 */
-            hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL,
-                                               NULL, NULL, NULL, 0);
-            ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
-        }
-
-        /* null name */
-        newPIDL = (ITEMIDLIST*)0xdeadbeef;
-        hr = IShellFolder_ParseDisplayName(IDesktopFolder,
-            NULL, NULL, NULL, NULL, &newPIDL, 0);
-        ok(newPIDL == 0, "expected null, got %p\n", newPIDL);
-        ok(hr == E_INVALIDARG, "returned %08x, expected E_INVALIDARG\n", hr);
-    }
-    else
-        win_skip("SHCreateShellItem requires XP SP1 or later\n");
-
-    MultiByteToWideChar(CP_ACP, 0, cInetTestA, -1, cTestDirW, MAX_PATH);
-    hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
-    todo_wine ok(hr == S_OK, "ParseDisplayName returned %08x, expected SUCCESS\n", hr);
-    if (hr == S_OK)
-    {
-        ok(ILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
-           "PT_IESPECIAL1, but is: %02x\n", ILFindLastID(newPIDL)->mkid.abID[0]);
-        IMalloc_Free(ppM, newPIDL);
-    }
 
-    MultiByteToWideChar(CP_ACP, 0, cInetTest2A, -1, cTestDirW, MAX_PATH);
-    hr = IShellFolder_ParseDisplayName(IDesktopFolder,
-        NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
-    todo_wine ok(hr == S_OK, "ParseDisplayName returned %08x, expected SUCCESS\n", hr);
-    if (hr == S_OK)
-    {
-        ok(ILFindLastID(newPIDL)->mkid.abID[0] == 0x61, "Last pidl should be of type "
-           "PT_IESPECIAL1, but is: %02x\n", ILFindLastID(newPIDL)->mkid.abID[0]);
-        IMalloc_Free(ppM, newPIDL);
-    }
+    hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, NULL, NULL, &pidl, NULL);
+    ok(hr == E_INVALIDARG, "got %#x\n", hr);
 
-    res = GetFileAttributesA(cNonExistDir1A);
-    if(res != INVALID_FILE_ATTRIBUTES)
+    for (i = 0; i < ARRAY_SIZE(parse_tests); i++)
     {
-        skip("Test directory unexpectedly exists\n");
-        goto finished;
+        hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, parse_tests[i].path, NULL, &pidl, NULL);
+todo_wine_if(parse_tests[i].todo)
+        ok(hr == parse_tests[i].hr, "%s: expected %#x, got %#x\n",
+            wine_dbgstr_w(parse_tests[i].path), parse_tests[i].hr, hr);
+        if (SUCCEEDED(hr))
+            CoTaskMemFree(pidl);
     }
 
-    MultiByteToWideChar(CP_ACP, 0, cNonExistDir1A, -1, cTestDirW, MAX_PATH);
-    hr = IShellFolder_ParseDisplayName(IDesktopFolder,
-        NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
-    ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
-        "ParseDisplayName returned %08x, expected 0x80070002\n", hr);
-
-    res = GetFileAttributesA(cNonExistDir2A);
-    if(res != INVALID_FILE_ATTRIBUTES)
-    {
-        skip("Test directory unexpectedly exists\n");
-        goto finished;
-    }
-
-    MultiByteToWideChar(CP_ACP, 0, cNonExistDir2A, -1, cTestDirW, MAX_PATH);
-    hr = IShellFolder_ParseDisplayName(IDesktopFolder,
-        NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
-    todo_wine ok(hr == E_INVALIDARG, "ParseDisplayName returned %08x, expected E_INVALIDARG\n", hr);
-
     /* I thought that perhaps the DesktopFolder's ParseDisplayName would recognize the
      * path corresponding to CSIDL_PERSONAL and return a CLSID_MyDocuments PIDL. Turns
      * out it doesn't. The magic seems to happen in the file dialogs, then. */
 
-    bRes = SHGetSpecialFolderPathW(NULL, cTestDirW, CSIDL_PERSONAL, FALSE);
+    bRes = SHGetSpecialFolderPathW(NULL, buffer, CSIDL_PERSONAL, FALSE);
     ok(bRes, "SHGetSpecialFolderPath(CSIDL_PERSONAL) failed! %u\n", GetLastError());
-    if (!bRes) goto finished;
 
-    hr = IShellFolder_ParseDisplayName(IDesktopFolder, NULL, NULL, cTestDirW, NULL, &newPIDL, 0);
+    hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, buffer, NULL, &pidl, 0);
     ok(hr == S_OK, "DesktopFolder->ParseDisplayName failed. hr = %08x.\n", hr);
-    if (hr != S_OK) goto finished;
 
-    ok(ILFindLastID(newPIDL)->mkid.abID[0] == 0x31,
+    ok(ILFindLastID(pidl)->mkid.abID[0] == 0x31,
        "Last pidl should be of type PT_FOLDER, but is: %02x\n",
-       ILFindLastID(newPIDL)->mkid.abID[0]);
-    IMalloc_Free(ppM, newPIDL);
+       ILFindLastID(pidl)->mkid.abID[0]);
+    CoTaskMemFree(pidl);
 
-finished:
-    IShellFolder_Release(IDesktopFolder);
+    /* Relative paths are interpreted relative to the desktop. */
+    GetTempPathW(ARRAY_SIZE(buffer), buffer);
+    GetLongPathNameW(buffer, buffer, ARRAY_SIZE(buffer));
+    SetCurrentDirectoryW(buffer);
+    CreateDirectoryW(testdirW, NULL);
+
+    hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
+    ok(hr == 0x80070002, "got %#x\n", hr);
+
+    RemoveDirectoryW(testdirW);
+
+    hr = SHGetSpecialFolderPathW(NULL, buffer, CSIDL_DESKTOP, FALSE);
+    ok(hr == S_FALSE, "got %#x\n", hr);
+    SetCurrentDirectoryW(buffer);
+    CreateDirectoryW(testdirW, NULL);
+
+    hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, testdirW, NULL, &pidl, NULL);
+    ok(hr == S_OK, "got %#x\n", hr);
+
+    ok(SHGetPathFromIDListW(pidl, buffer2), "SHGetPathFromIDList failed\n");
+    lstrcatW(buffer, backslashW);
+    lstrcatW(buffer, testdirW);
+    ok(!lstrcmpW(buffer, buffer2), "expected %s, got %s\n", wine_dbgstr_w(buffer), wine_dbgstr_w(buffer2));
+
+    RemoveDirectoryW(testdirW);
+    CoTaskMemFree(pidl);
+
+    IShellFolder_Release(desktop);
 }
 
 /* creates a file with the specified name for tests */
@@ -1962,7 +1962,7 @@ static void test_LocalizedNames(void)
     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER, &strret);
     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
 
-    hr = StrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
+    hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
     ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
     todo_wine
     ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
@@ -1971,7 +1971,7 @@ static void test_LocalizedNames(void)
     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FOREDITING, &strret);
     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
 
-    hr = StrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
+    hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
     ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
     todo_wine
     ok (!lstrcmpiW(tempbufW, folderdisplayW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
@@ -1980,7 +1980,7 @@ static void test_LocalizedNames(void)
     hr = IShellFolder_GetDisplayNameOf(testIShellFolder, newPIDL, SHGDN_INFOLDER|SHGDN_FORPARSING, &strret);
     ok(hr == S_OK, "GetDisplayNameOf failed %08x\n", hr);
 
-    hr = StrRetToBufW(&strret, newPIDL, tempbufW, sizeof(tempbufW)/sizeof(WCHAR));
+    hr = StrRetToBufW(&strret, newPIDL, tempbufW, ARRAY_SIZE(tempbufW));
     ok (hr == S_OK, "StrRetToBufW failed! hr = %08x\n", hr);
     ok (!lstrcmpiW(tempbufW, foldernameW), "GetDisplayNameOf returned %s\n", wine_dbgstr_w(tempbufW));
 
@@ -4978,7 +4978,8 @@ static void test_SHChangeNotify(BOOL test_new_delivery)
             SHCNE_ALLEVENTS, WM_USER_NOTIFY, 1, entries);
     ok(notifyID != 0, "Failed to register a window for change notifications\n");
 
-    for(i = 0; i < sizeof(chnotify_tests) / sizeof(*chnotify_tests); ++i){
+    for (i = 0; i < ARRAY_SIZE(chnotify_tests); ++i)
+    {
         exp_data = chnotify_tests + i;
 
         exp_data->missing_events = exp_data->notify_count;
@@ -5170,7 +5171,7 @@ static void test_GetDefaultColumn(void)
 
     CoInitialize(NULL);
 
-    for (i = 0; i < sizeof(folders)/sizeof(folders[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(folders); i++)
     {
         IShellFolder2 *folder;
         ULONG sort, display;
@@ -5199,6 +5200,8 @@ static void test_GetDefaultColumn(void)
         hr = IShellFolder2_GetDefaultColumn(folder, 0, &sort, NULL);
         ok(hr == E_NOTIMPL, "Unexpected hr %#x.\n", hr);
         ok(sort == 123, "Unexpected default column.\n");
+
+        IShellFolder2_Release(folder);
     }
 
     CoUninitialize();
@@ -5221,7 +5224,7 @@ static void test_GetDefaultSearchGUID(void)
 
     CoInitialize(NULL);
 
-    for (i = 0; i < sizeof(folders)/sizeof(folders[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(folders); i++)
     {
         IShellFolder2 *folder;
         GUID guid;
@@ -5252,6 +5255,86 @@ static void test_GetDefaultSearchGUID(void)
     CoUninitialize();
 }
 
+static void test_SHLimitInputEdit(void)
+{
+    IShellFolder *desktop;
+    HRESULT hr;
+    HWND hwnd;
+
+    hr = SHGetDesktopFolder(&desktop);
+    ok(hr == S_OK, "Failed to get desktop folder, hr %#x.\n", hr);
+
+    hr = SHLimitInputEdit(NULL, desktop);
+todo_wine
+    ok(hr == E_FAIL, "Unexpected hr %#x.\n", hr);
+
+    hwnd = CreateWindowA("EDIT", NULL, WS_VISIBLE, 0, 0, 100, 30, NULL, NULL, NULL, NULL);
+    ok(hwnd != NULL, "Failed to create Edit control.\n");
+
+    hr = SHLimitInputEdit(hwnd, desktop);
+todo_wine
+    ok(hr == S_OK, "Failed to set input limits, hr %#x.\n", hr);
+
+    hr = SHLimitInputEdit(hwnd, desktop);
+todo_wine
+    ok(hr == S_OK, "Failed to set input limits, hr %#x.\n", hr);
+
+    DestroyWindow(hwnd);
+    IShellFolder_Release(desktop);
+}
+
+static void test_SHGetSetFolderCustomSettings(void)
+{
+    HRESULT hr;
+    SHFOLDERCUSTOMSETTINGS fcs;
+    WCHAR pathW[MAX_PATH];
+    WCHAR bufferW[MAX_PATH];
+    WCHAR iconpathW[MAX_PATH];
+    static const WCHAR somedirW[] = {'s','o','m','e','_','d','i','r',0};
+    static const WCHAR iconW[] = {'\\','s','o','m','e','_','i','c','o','n','.','i','c','o',0};
+    static const WCHAR desktop_iniW[] = {'\\','D','e','s','k','t','o','p','.','i','n','i',0};
+
+    if (!pSHGetSetFolderCustomSettings)
+    {
+        win_skip("SHGetSetFolderCustomSetting not exported by name (only by ordinal) for version XP/win2003\n");
+        return;
+    }
+
+    GetTempPathW(MAX_PATH, pathW);
+    lstrcatW(pathW, somedirW);
+    CreateDirectoryW(pathW, NULL);
+
+    lstrcpyW(iconpathW, pathW);
+    lstrcatW(iconpathW, iconW);
+
+    memset(&fcs, 0, sizeof(fcs));
+    fcs.dwSize = sizeof(fcs);
+    fcs.dwMask = FCSM_ICONFILE;
+    fcs.pszIconFile = iconpathW;
+
+    hr = pSHGetSetFolderCustomSettings(&fcs, pathW, FCS_FORCEWRITE); /*creates and writes to a Desktop.ini*/
+    ok(hr == S_OK, "Expected S_OK, got %#x\n", hr);
+
+    memset(&fcs, 0, sizeof(fcs));
+    fcs.dwSize = sizeof(fcs);
+    fcs.dwMask = FCSM_ICONFILE;
+    fcs.cchIconFile = MAX_PATH;
+    fcs.pszIconFile = bufferW;
+    bufferW[0] = 0;
+
+    hr = pSHGetSetFolderCustomSettings(&fcs, pathW, FCS_READ);
+    todo_wine ok(hr == S_OK, "Expected S_OK, got %#x\n", hr);
+    todo_wine ok(!lstrcmpiW(iconpathW, fcs.pszIconFile), "Expected %s, got %s\n", wine_dbgstr_w(iconpathW), wine_dbgstr_w(fcs.pszIconFile));
+
+    hr = pSHGetSetFolderCustomSettings(&fcs, NULL, FCS_READ);
+    ok(hr == E_FAIL, "Expected E_FAIL, got %#x\n", hr);
+
+    lstrcpyW(bufferW, pathW);
+    lstrcatW(bufferW, desktop_iniW);
+    DeleteFileW(bufferW);
+    RemoveDirectoryW(pathW);
+}
+
 START_TEST(shlfolder)
 {
     init_function_pointers();
@@ -5293,6 +5376,8 @@ START_TEST(shlfolder)
     test_DataObject();
     test_GetDefaultColumn();
     test_GetDefaultSearchGUID();
+    test_SHLimitInputEdit();
+    test_SHGetSetFolderCustomSettings();
 
     OleUninitialize();
 }
index 36fa759..abc3e16 100644 (file)
@@ -1483,7 +1483,6 @@ static void test_newmenu(void)
     HRESULT hr;
 
     hr = CoCreateInstance(&CLSID_NewMenu, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
-todo_wine
     ok(hr == S_OK, "Failed to create NewMenu object, hr %#x.\n", hr);
     if (hr != S_OK)
     {
@@ -1495,6 +1494,14 @@ todo_wine
     ok(hr == S_OK, "Failed to get IShellExtInit, hr %#x.\n", hr);
     IUnknown_Release(unk2);
 
+    hr = IUnknown_QueryInterface(unk, &IID_IContextMenu, (void **)&unk2);
+    ok(hr == S_OK, "Failed to get IContextMenu, hr %#x.\n", hr);
+    IUnknown_Release(unk2);
+
+    hr = IUnknown_QueryInterface(unk, &IID_IContextMenu2, (void **)&unk2);
+    ok(hr == S_OK, "Failed to get IContextMenu2, hr %#x.\n", hr);
+    IUnknown_Release(unk2);
+
     hr = IUnknown_QueryInterface(unk, &IID_IContextMenu3, (void **)&unk2);
     ok(hr == S_OK, "Failed to get IContextMenu3, hr %#x.\n", hr);
     IUnknown_Release(unk2);
index 6cdb386..5fd5893 100644 (file)
@@ -67,14 +67,14 @@ static void test_StrRetToStringNW(void)
     strret.uType = STRRET_WSTR;
     U(strret).pOleStr = CoDupStrW("Test");
     memset(buff, 0xff, sizeof(buff));
-    ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
+    ret = pStrRetToStrNAW(buff, ARRAY_SIZE(buff), &strret, NULL);
     ok(ret == TRUE && !strcmpW(buff, szTestW),
        "STRRET_WSTR: dup failed, ret=%d\n", ret);
 
     strret.uType = STRRET_CSTR;
     lstrcpyA(U(strret).cStr, "Test");
     memset(buff, 0xff, sizeof(buff));
-    ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
+    ret = pStrRetToStrNAW(buff, ARRAY_SIZE(buff), &strret, NULL);
     ok(ret == TRUE && !strcmpW(buff, szTestW),
        "STRRET_CSTR: dup failed, ret=%d\n", ret);
 
@@ -82,7 +82,7 @@ static void test_StrRetToStringNW(void)
     U(strret).uOffset = 1;
     strcpy((char*)&iidl, " Test");
     memset(buff, 0xff, sizeof(buff));
-    ret = pStrRetToStrNAW(buff, sizeof(buff)/sizeof(WCHAR), &strret, iidl);
+    ret = pStrRetToStrNAW(buff, ARRAY_SIZE(buff), &strret, iidl);
     ok(ret == TRUE && !strcmpW(buff, szTestW),
        "STRRET_OFFSET: dup failed, ret=%d\n", ret);
 
@@ -92,7 +92,7 @@ if (0)
     /* Invalid dest - should return FALSE, except NT4 does not, so we don't check. */
     strret.uType = STRRET_WSTR;
     U(strret).pOleStr = CoDupStrW("Test");
-    pStrRetToStrNAW(NULL, sizeof(buff)/sizeof(WCHAR), &strret, NULL);
+    pStrRetToStrNAW(NULL, ARRAY_SIZE(buff), &strret, NULL);
     trace("NULL dest: ret=%d\n", ret);
 }
 }