From 4d8c4b145dcf2d93080532d369d09344ff9359d9 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Mon, 4 Feb 2019 13:00:58 +0100 Subject: [PATCH] [SHELL32_WINETEST] Sync with Wine Staging 4.0. CORE-15682 --- .../rostests/winetests/shell32/autocomplete.c | 453 +++++- .../rostests/winetests/shell32/brsfolder.c | 10 +- .../rostests/winetests/shell32/progman_dde.c | 2 +- .../winetests/shell32/shelldispatch.c | 42 +- .../rostests/winetests/shell32/shelllink.c | 51 +- modules/rostests/winetests/shell32/shellole.c | 21 +- .../rostests/winetests/shell32/shellpath.c | 1292 +++++++++-------- modules/rostests/winetests/shell32/shlexec.c | 181 +-- .../rostests/winetests/shell32/shlfileop.c | 227 ++- .../rostests/winetests/shell32/shlfolder.c | 259 ++-- modules/rostests/winetests/shell32/shlview.c | 9 +- modules/rostests/winetests/shell32/string.c | 8 +- 12 files changed, 1542 insertions(+), 1013 deletions(-) diff --git a/modules/rostests/winetests/shell32/autocomplete.c b/modules/rostests/winetests/shell32/autocomplete.c index 859734ce590..4ef124c9d2f 100644 --- a/modules/rostests/winetests/shell32/autocomplete.c +++ b/modules/rostests/winetests/shell32/autocomplete.c @@ -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); diff --git a/modules/rostests/winetests/shell32/brsfolder.c b/modules/rostests/winetests/shell32/brsfolder.c index bf29d1169f2..0888cfa4684 100644 --- a/modules/rostests/winetests/shell32/brsfolder.c +++ b/modules/rostests/winetests/shell32/brsfolder.c @@ -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)) diff --git a/modules/rostests/winetests/shell32/progman_dde.c b/modules/rostests/winetests/shell32/progman_dde.c index 62ed413ad00..2d19404a763 100644 --- a/modules/rostests/winetests/shell32/progman_dde.c +++ b/modules/rostests/winetests/shell32/progman_dde.c @@ -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))) { diff --git a/modules/rostests/winetests/shell32/shelldispatch.c b/modules/rostests/winetests/shell32/shelldispatch.c index cc007578400..e9948ae6305 100644 --- a/modules/rostests/winetests/shell32/shelldispatch.c +++ b/modules/rostests/winetests/shell32/shelldispatch.c @@ -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); diff --git a/modules/rostests/winetests/shell32/shelllink.c b/modules/rostests/winetests/shell32/shelllink.c index 444fdcc4177..3a2068cae57 100644 --- a/modules/rostests/winetests/shell32/shelllink.c +++ b/modules/rostests/winetests/shell32/shelllink.c @@ -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) diff --git a/modules/rostests/winetests/shell32/shellole.c b/modules/rostests/winetests/shell32/shellole.c index e79d6666991..27964afcd36 100644 --- a/modules/rostests/winetests/shell32/shellole.c +++ b/modules/rostests/winetests/shell32/shellole.c @@ -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) diff --git a/modules/rostests/winetests/shell32/shellpath.c b/modules/rostests/winetests/shell32/shellpath.c index f6674313f8e..38b56f01d37 100644 --- a/modules/rostests/winetests/shell32/shellpath.c +++ b/modules/rostests/winetests/shell32/shellpath.c @@ -43,10 +43,6 @@ 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; diff --git a/modules/rostests/winetests/shell32/shlexec.c b/modules/rostests/winetests/shell32/shlexec.c index a8aabac734e..b140280a5e0 100644 --- a/modules/rostests/winetests/shell32/shlexec.c +++ b/modules/rostests/winetests/shell32/shlexec.c @@ -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; diff --git a/modules/rostests/winetests/shell32/shlfileop.c b/modules/rostests/winetests/shell32/shlfileop.c index 72ca1e7e36d..9768e18de33 100644 --- a/modules/rostests/winetests/shell32/shlfileop.c +++ b/modules/rostests/winetests/shell32/shlfileop.c @@ -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(); diff --git a/modules/rostests/winetests/shell32/shlfolder.c b/modules/rostests/winetests/shell32/shlfolder.c index 2ee91ef7d68..f2bd6408ab7 100644 --- a/modules/rostests/winetests/shell32/shlfolder.c +++ b/modules/rostests/winetests/shell32/shlfolder.c @@ -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(); } diff --git a/modules/rostests/winetests/shell32/shlview.c b/modules/rostests/winetests/shell32/shlview.c index 36fa7597194..abc3e16826b 100644 --- a/modules/rostests/winetests/shell32/shlview.c +++ b/modules/rostests/winetests/shell32/shlview.c @@ -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); diff --git a/modules/rostests/winetests/shell32/string.c b/modules/rostests/winetests/shell32/string.c index 6cdb386eba6..5fd589300b0 100644 --- a/modules/rostests/winetests/shell32/string.c +++ b/modules/rostests/winetests/shell32/string.c @@ -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); } } -- 2.17.1