From b1df00f897ea73f7427f444c80f5bac6bfaa94f2 Mon Sep 17 00:00:00 2001
From: Amine Khaldi <amine.khaldi@reactos.org>
Date: Fri, 23 Sep 2011 23:14:50 +0000
Subject: [PATCH] [SHELL32_WINETEST] * Sync to Wine 1.3.29.

svn path=/trunk/; revision=53821
---
 rostests/winetests/shell32/CMakeLists.txt   |    9 +-
 rostests/winetests/shell32/autocomplete.c   |  121 +-
 rostests/winetests/shell32/brsfolder.c      |  365 +++
 rostests/winetests/shell32/ebrowser.c       | 1799 +++++++++++++
 rostests/winetests/shell32/progman_dde.c    |   16 +-
 rostests/winetests/shell32/recyclebin.c     |  107 +
 rostests/winetests/shell32/shell32.rbuild   |    7 +-
 rostests/winetests/shell32/shell32_test.h   |    2 +-
 rostests/winetests/shell32/shelldispatch.c  |  319 +++
 rostests/winetests/shell32/shelllink.c      |  154 +-
 rostests/winetests/shell32/shellole.c       |  437 ++++
 rostests/winetests/shell32/shellpath.c      | 1659 +++++++++++-
 rostests/winetests/shell32/shfldr_special.c |    9 +-
 rostests/winetests/shell32/shlexec.c        |   97 +-
 rostests/winetests/shell32/shlfileop.c      |   29 +-
 rostests/winetests/shell32/shlfolder.c      | 2555 ++++++++++++++++++-
 rostests/winetests/shell32/shlview.c        |  496 +++-
 rostests/winetests/shell32/systray.c        |   24 +-
 rostests/winetests/shell32/testlist.c       |   22 +-
 19 files changed, 8076 insertions(+), 151 deletions(-)
 create mode 100644 rostests/winetests/shell32/brsfolder.c
 create mode 100644 rostests/winetests/shell32/ebrowser.c
 create mode 100644 rostests/winetests/shell32/recyclebin.c
 create mode 100644 rostests/winetests/shell32/shelldispatch.c
 create mode 100644 rostests/winetests/shell32/shellole.c

diff --git a/rostests/winetests/shell32/CMakeLists.txt b/rostests/winetests/shell32/CMakeLists.txt
index 0433f2a7cdf..e69d17b2a6c 100644
--- a/rostests/winetests/shell32/CMakeLists.txt
+++ b/rostests/winetests/shell32/CMakeLists.txt
@@ -8,10 +8,16 @@ add_definitions(
 list(APPEND SOURCE
     appbar.c
     autocomplete.c
+    brsfolder.c
+    ebrowser.c
     generated.c
     progman_dde.c
+    recyclebin.c
+    shelldispatch.c
     shelllink.c
+    shellole.c
     shellpath.c
+    shfldr_special.c
     shlexec.c
     shlfileop.c
     shlfolder.c
@@ -19,11 +25,10 @@ list(APPEND SOURCE
     string.c
     systray.c
     testlist.c
-    shfldr_special.c
     rsrc.rc)
 
 add_executable(shell32_winetest ${SOURCE})
 target_link_libraries(shell32_winetest wine uuid)
 set_module_type(shell32_winetest win32cui)
-add_importlibs(shell32_winetest shlwapi gdi32 shell32 ole32 oleaut32 user32 advapi32 msvcrt kernel32 ntdll)
+add_importlibs(shell32_winetest shell32 ole32 oleaut32 user32 advapi32 msvcrt kernel32 ntdll)
 add_cd_file(TARGET shell32_winetest DESTINATION reactos/bin FOR all)
diff --git a/rostests/winetests/shell32/autocomplete.c b/rostests/winetests/shell32/autocomplete.c
index d4a84aeeeba..5ff88479c1a 100644
--- a/rostests/winetests/shell32/autocomplete.c
+++ b/rostests/winetests/shell32/autocomplete.c
@@ -33,11 +33,115 @@ static HWND hMainWnd, hEdit;
 static HINSTANCE hinst;
 static int killfocus_count;
 
+static void test_invalid_init(void)
+{
+    HRESULT hr;
+    IAutoComplete *ac;
+    IUnknown *acSource;
+    HWND edit_control;
+
+    /* AutoComplete instance */
+    hr = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER,
+                         &IID_IAutoComplete, (void **)&ac);
+    if (hr == REGDB_E_CLASSNOTREG)
+    {
+        win_skip("CLSID_AutoComplete is not registered\n");
+        return;
+    }
+    ok(hr == S_OK, "no IID_IAutoComplete (0x%08x)\n", hr);
+
+    /* AutoComplete source */
+    hr = CoCreateInstance(&CLSID_ACLMulti, NULL, CLSCTX_INPROC_SERVER,
+                        &IID_IACList, (void **)&acSource);
+    if (hr == REGDB_E_CLASSNOTREG)
+    {
+        win_skip("CLSID_ACLMulti is not registered\n");
+        IAutoComplete_Release(ac);
+        return;
+    }
+    ok(hr == S_OK, "no IID_IACList (0x%08x)\n", hr);
+
+    edit_control = CreateWindowExA(0, "EDIT", "Some text", 0, 10, 10, 300, 300,
+                       hMainWnd, NULL, hinst, NULL);
+    ok(edit_control != NULL, "Can't create edit control\n");
+
+    /* The refcount of acSource would be incremented on older Windows. */
+    hr = IAutoComplete_Init(ac, NULL, acSource, NULL, NULL);
+    ok(hr == E_INVALIDARG ||
+       broken(hr == S_OK), /* Win2k/XP/Win2k3 */
+       "Init returned 0x%08x\n", hr);
+    if (hr == E_INVALIDARG)
+    {
+        LONG ref;
+
+        IUnknown_AddRef(acSource);
+        ref = IUnknown_Release(acSource);
+        ok(ref == 1, "Expected AutoComplete source refcount to be 1, got %d\n", ref);
+    }
+
+if (0)
+{
+    /* Older Windows versions never check the window handle, while newer
+     * versions only check for NULL. Subsequent attempts to initialize the
+     * object after this call succeeds would fail, because initialization
+     * state is determined by whether a non-NULL window handle is stored. */
+    hr = IAutoComplete_Init(ac, (HWND)0xdeadbeef, acSource, NULL, NULL);
+    ok(hr == S_OK, "Init returned 0x%08x\n", hr);
+
+    /* Tests crash on older Windows. */
+    hr = IAutoComplete_Init(ac, NULL, NULL, NULL, NULL);
+    ok(hr == E_INVALIDARG, "Init returned 0x%08x\n", hr);
+
+    hr = IAutoComplete_Init(ac, edit_control, NULL, NULL, NULL);
+    ok(hr == E_INVALIDARG, "Init returned 0x%08x\n", hr);
+}
+
+    /* bind to edit control */
+    hr = IAutoComplete_Init(ac, edit_control, acSource, NULL, NULL);
+    ok(hr == S_OK, "Init returned 0x%08x\n", hr);
+
+    /* try invalid parameters after successful initialization .*/
+    hr = IAutoComplete_Init(ac, NULL, NULL, NULL, NULL);
+    ok(hr == E_INVALIDARG ||
+       hr == E_FAIL, /* Win2k/XP/Win2k3 */
+       "Init returned 0x%08x\n", hr);
+
+    hr = IAutoComplete_Init(ac, NULL, acSource, NULL, NULL);
+    ok(hr == E_INVALIDARG ||
+       hr == E_FAIL, /* Win2k/XP/Win2k3 */
+       "Init returned 0x%08x\n", hr);
+
+    hr = IAutoComplete_Init(ac, edit_control, NULL, NULL, NULL);
+    ok(hr == E_INVALIDARG ||
+       hr == E_FAIL, /* Win2k/XP/Win2k3 */
+       "Init returned 0x%08x\n", hr);
+
+    /* try initializing twice on the same control */
+    hr = IAutoComplete_Init(ac, edit_control, acSource, NULL, NULL);
+    ok(hr == E_FAIL, "Init returned 0x%08x\n", hr);
+
+    /* try initializing with a different control */
+    hr = IAutoComplete_Init(ac, hEdit, acSource, NULL, NULL);
+    ok(hr == E_FAIL, "Init returned 0x%08x\n", hr);
+
+    DestroyWindow(edit_control);
+
+    /* try initializing with a different control after
+     * destroying the original initialization control */
+    hr = IAutoComplete_Init(ac, hEdit, acSource, NULL, NULL);
+    ok(hr == E_UNEXPECTED ||
+       hr == E_FAIL, /* Win2k/XP/Win2k3 */
+       "Init returned 0x%08x\n", hr);
+
+    IUnknown_Release(acSource);
+    IAutoComplete_Release(ac);
+}
 static IAutoComplete *test_init(void)
 {
     HRESULT r;
-    IAutoComplete* ac;
+    IAutoComplete *ac;
     IUnknown *acSource;
+    LONG_PTR user_data;
 
     /* AutoComplete instance */
     r = CoCreateInstance(&CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER,
@@ -55,18 +159,20 @@ static IAutoComplete *test_init(void)
     if (r == REGDB_E_CLASSNOTREG)
     {
         win_skip("CLSID_ACLMulti is not registered\n");
+        IAutoComplete_Release(ac);
         return NULL;
     }
     ok(r == S_OK, "no IID_IACList (0x%08x)\n", r);
 
-if (0)
-{
-    /* crashes on native */
-    r = IAutoComplete_Init(ac, hEdit, NULL, NULL, NULL);
-}
+    user_data = GetWindowLongPtrA(hEdit, GWLP_USERDATA);
+    ok(user_data == 0, "Expected the edit control user data to be zero\n");
+
     /* bind to edit control */
     r = IAutoComplete_Init(ac, hEdit, acSource, NULL, NULL);
-    ok(r == S_OK, "Init failed (0x%08x)\n", r);
+    ok(r == S_OK, "Init returned 0x%08x\n", r);
+
+    user_data = GetWindowLongPtrA(hEdit, GWLP_USERDATA);
+    ok(user_data == 0, "Expected the edit control user data to be zero\n");
 
     IUnknown_Release(acSource);
 
@@ -134,6 +240,7 @@ START_TEST(autocomplete)
     ok(hMainWnd != NULL, "Failed to create parent window. Tests aborted.\n");
     if (!hMainWnd) return;
 
+    test_invalid_init();
     ac = test_init();
     if (!ac)
         goto cleanup;
diff --git a/rostests/winetests/shell32/brsfolder.c b/rostests/winetests/shell32/brsfolder.c
new file mode 100644
index 00000000000..7b87967f46b
--- /dev/null
+++ b/rostests/winetests/shell32/brsfolder.c
@@ -0,0 +1,365 @@
+/*
+ * Unit test of the SHBrowseForFolder function.
+ *
+ * Copyright 2009-2010 Michael Mc Donnell
+ * Copyright 2011 André Hentschel
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include <windows.h>
+#include <shlobj.h>
+#include <shobjidl.h>
+#include <string.h>
+
+#include "wine/test.h"
+#define IDD_MAKENEWFOLDER 0x3746 /* From "../shresdef.h" */
+#define TIMER_WAIT_MS 50 /* Should be long enough for slow systems */
+
+static const char new_folder_name[] = "foo";
+static LPITEMIDLIST selected_folder_pidl;
+
+/*
+ * Returns the number of folders in a folder.
+ */
+static int get_number_of_folders(LPCSTR path)
+{
+    int number_of_folders = 0;
+    char path_search_string[MAX_PATH];
+    WIN32_FIND_DATA find_data;
+    HANDLE find_handle;
+
+    strncpy(path_search_string, path, MAX_PATH);
+    strncat(path_search_string, "*", 1);
+
+    find_handle = FindFirstFile(path_search_string, &find_data);
+    if (find_handle == INVALID_HANDLE_VALUE)
+        return -1;
+
+    do
+    {
+        if ((find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+            strcmp(find_data.cFileName, ".") != 0 &&
+            strcmp(find_data.cFileName, "..") != 0)
+        {
+            number_of_folders++;
+        }
+    }
+    while (FindNextFile(find_handle, &find_data) != 0);
+
+    FindClose(find_handle);
+    return number_of_folders;
+}
+
+static BOOL does_folder_or_file_exist(LPCSTR folder_path)
+{
+    DWORD file_attributes = GetFileAttributesA(folder_path);
+    return !(file_attributes == INVALID_FILE_ATTRIBUTES);
+}
+
+/*
+ * Timer callback used by test_click_make_new_folder_button. It simulates a user
+ * making a new folder and calling it "foo".
+ */
+static void CALLBACK make_new_folder_timer_callback(HWND hwnd, UINT uMsg,
+                                                    UINT_PTR idEvent, DWORD dwTime)
+{
+    static int step = 0;
+
+    switch (step++)
+    {
+    case 0:
+        /* Click "Make New Folder" button */
+        PostMessage(hwnd, WM_COMMAND, IDD_MAKENEWFOLDER, 0);
+        break;
+    case 1:
+        /* Set the new folder name to foo by replacing text in edit control */
+        SendMessage(GetFocus(), EM_REPLACESEL, 0, (LPARAM) new_folder_name);
+        SetFocus(hwnd);
+        break;
+    case 2:
+        /*
+         * The test does not trigger the correct state on Windows. This results
+         * in the new folder pidl not being returned. The result is as
+         * expected if the same steps are done manually.
+         * Sending the down key selects the new folder again which sets the
+         * correct state. This ensures that the correct pidl is returned.
+         */
+        keybd_event(VK_DOWN, 0, 0, 0);
+        break;
+    case 3:
+        keybd_event(VK_DOWN, 0, KEYEVENTF_KEYUP, 0);
+        break;
+    case 4:
+        KillTimer(hwnd, idEvent);
+        /* Close dialog box */
+        SendMessage(hwnd, WM_COMMAND, IDOK, 0);
+        break;
+    default:
+        break;
+    }
+}
+
+/*
+ * Callback used by test_click_make_new_folder_button. It sets up a timer to
+ * simulate user input.
+ */
+static int CALLBACK create_new_folder_callback(HWND hwnd, UINT uMsg,
+                                               LPARAM lParam, LPARAM lpData)
+{
+    switch (uMsg)
+    {
+    case BFFM_INITIALIZED:
+        /* User input is simulated in timer callback */
+        SetTimer(hwnd, 0, TIMER_WAIT_MS, make_new_folder_timer_callback);
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
+/*
+ * Tests if clicking the "Make New Folder" button in a SHBrowseForFolder
+ * dialog box creates a new folder. (Bug 17986).
+ *
+ * Here follows a description of what happens on W2K,Vista, W2K8, W7:
+ * When the "Make New Folder" button is clicked a new folder is created and
+ * inserted into the tree. The folder is given a default name that depends on
+ * the locale (e.g. "New Folder"). The folder name is selected and the dialog
+ * waits for the user to type in a new name. The folder is renamed when the user
+ * types in a name and presses enter.
+ *
+ * Note that XP and W2K3 do not select the folder name or wait for the user
+ * to type in a new folder name. This behavior is considered broken as most
+ * users would like to give the folder a name after creating it. The fact that
+ * it originally waited for the user to type in a new folder name(W2K), and then
+ * again was changed back wait for the new folder name(Vista, W2K8, W7),
+ * indicates that MS also believes that it was broken in XP and W2K3.
+ */
+static void test_click_make_new_folder_button(void)
+{
+    HRESULT resCoInit, hr;
+    BROWSEINFO bi;
+    LPITEMIDLIST pidl = NULL;
+    LPITEMIDLIST test_folder_pidl;
+    IShellFolder *test_folder_object;
+    char test_folder_path[MAX_PATH];
+    WCHAR test_folder_pathW[MAX_PATH];
+    CHAR new_folder_path[MAX_PATH];
+    CHAR new_folder_pidl_path[MAX_PATH];
+    char selected_folder[MAX_PATH];
+    const CHAR title[] = "test_click_make_new_folder_button";
+    int number_of_folders = -1;
+    SHFILEOPSTRUCT shfileop;
+
+    if (does_folder_or_file_exist(title))
+    {
+        skip("The test folder already exists.\n");
+        return;
+    }
+
+    /* Must initialize COM if using the NEWDIAlOGSTYLE according to MSDN. */
+    resCoInit = CoInitialize(NULL);
+    if(!(resCoInit == S_OK || resCoInit == S_FALSE))
+    {
+        skip("COM could not be initialized %u\n", GetLastError());
+        return;
+    }
+
+    /* Leave room for concatenating title, two backslashes, and an extra NULL. */
+    if (!GetCurrentDirectoryA(MAX_PATH-strlen(title)-3, test_folder_path))
+    {
+        skip("GetCurrentDirectoryA failed %u\n", GetLastError());
+    }
+    strncat(test_folder_path, "\\", 1);
+    strncat(test_folder_path, title, MAX_PATH-1);
+    strncat(test_folder_path, "\\", 1);
+
+    /* Avoid conflicts by creating a test folder. */
+    if (!CreateDirectoryA(title, NULL))
+    {
+        skip("CreateDirectoryA failed %u\n", GetLastError());
+        return;
+    }
+
+    /* Initialize browse info struct for SHBrowseForFolder */
+    bi.hwndOwner = NULL;
+    bi.pszDisplayName = (LPTSTR) &selected_folder;
+    bi.lpszTitle = (LPTSTR) title;
+    bi.ulFlags = BIF_NEWDIALOGSTYLE;
+    bi.lpfn = create_new_folder_callback;
+    /* Use test folder as the root folder for dialog box */
+    MultiByteToWideChar(CP_UTF8, 0, test_folder_path, MAX_PATH,
+        test_folder_pathW, MAX_PATH);
+    hr = SHGetDesktopFolder(&test_folder_object);
+    ok (SUCCEEDED(hr), "SHGetDesktopFolder failed with hr 0x%08x\n", hr);
+    if (FAILED(hr)) {
+        skip("SHGetDesktopFolder failed - skipping\n");
+        return;
+    }
+    test_folder_object->lpVtbl->ParseDisplayName(test_folder_object, NULL, NULL,
+        test_folder_pathW, 0UL, &test_folder_pidl, 0UL);
+    bi.pidlRoot = test_folder_pidl;
+
+    /* Display dialog box and let callback click the buttons */
+    pidl = SHBrowseForFolder(&bi);
+
+    number_of_folders = get_number_of_folders(test_folder_path);
+    ok(number_of_folders == 1 || broken(number_of_folders == 0) /* W95, W98 */,
+        "Clicking \"Make New Folder\" button did not result in a new folder.\n");
+
+    /* There should be a new folder foo inside the test folder */
+    strcpy(new_folder_path, test_folder_path);
+    strcat(new_folder_path, new_folder_name);
+    ok(does_folder_or_file_exist(new_folder_path)
+        || broken(!does_folder_or_file_exist(new_folder_path)) /* W95, W98, XP, W2K3 */,
+        "The new folder did not get the name %s\n", new_folder_name);
+
+    /* Dialog should return a pidl pointing to the new folder */
+    ok(SHGetPathFromIDListA(pidl, new_folder_pidl_path),
+        "SHGetPathFromIDList failed for new folder.\n");
+    ok(strcmp(new_folder_path, new_folder_pidl_path) == 0
+        || broken(strcmp(new_folder_path, new_folder_pidl_path) != 0) /* earlier than Vista */,
+        "SHBrowseForFolder did not return the pidl for the new folder. "
+        "Expected '%s' got '%s'\n", new_folder_path, new_folder_pidl_path);
+
+    /* Remove test folder and any subfolders created in this test */
+    shfileop.hwnd = NULL;
+    shfileop.wFunc = FO_DELETE;
+    /* Path must be double NULL terminated */
+    test_folder_path[strlen(test_folder_path)+1] = '\0';
+    shfileop.pFrom = test_folder_path;
+    shfileop.pTo = NULL;
+    shfileop.fFlags = FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT;
+    SHFileOperation(&shfileop);
+
+    if (pidl)
+        CoTaskMemFree(pidl);
+    if (test_folder_pidl)
+        CoTaskMemFree(test_folder_pidl);
+    test_folder_object->lpVtbl->Release(test_folder_object);
+
+    CoUninitialize();
+}
+
+
+/*
+ * Callback used by test_selection.
+ */
+static int CALLBACK selection_callback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+    DWORD ret;
+
+    switch (uMsg)
+    {
+    case BFFM_INITIALIZED:
+        /* test with zero values */
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONA, 0, 0);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONW, 0, 0);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONA, 1, 0);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+
+        if(0)
+        {
+            /* Crashes on NT4 */
+            ret = SendMessage(hwnd, BFFM_SETSELECTIONW, 1, 0);
+            ok(!ret, "SendMessage returned: %u\n", ret);
+        }
+
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONA, 0, (LPARAM)selected_folder_pidl);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONW, 0, (LPARAM)selected_folder_pidl);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONA, 1, (LPARAM)selected_folder_pidl);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)selected_folder_pidl);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONA, 1, (LPARAM)new_folder_name);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+        ret = SendMessage(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)new_folder_name);
+        ok(!ret, "SendMessage returned: %u\n", ret);
+
+        SendMessage(hwnd, WM_COMMAND, IDOK, 0);
+        return TRUE;
+    default:
+        return FALSE;
+    }
+}
+
+static void test_selection(void)
+{
+    HRESULT resCoInit, hr;
+    BROWSEINFO bi;
+    LPITEMIDLIST pidl = NULL;
+    IShellFolder *desktop_object;
+    WCHAR selected_folderW[MAX_PATH];
+    const CHAR title[] = "test_selection";
+
+    resCoInit = CoInitialize(NULL);
+    if(!(resCoInit == S_OK || resCoInit == S_FALSE))
+    {
+        skip("COM could not be initialized %u\n", GetLastError());
+        return;
+    }
+
+    if (!GetCurrentDirectoryW(MAX_PATH, selected_folderW))
+    {
+        skip("GetCurrentDirectoryW failed %u\n", GetLastError());
+    }
+
+    /* Initialize browse info struct for SHBrowseForFolder */
+    bi.hwndOwner = NULL;
+    bi.pszDisplayName = NULL;
+    bi.lpszTitle = (LPTSTR) title;
+    bi.lpfn = selection_callback;
+
+    hr = SHGetDesktopFolder(&desktop_object);
+    ok (SUCCEEDED(hr), "SHGetDesktopFolder failed with hr 0x%08x\n", hr);
+    if (FAILED(hr)) {
+        skip("SHGetDesktopFolder failed - skipping\n");
+        return;
+    }
+    desktop_object->lpVtbl->ParseDisplayName(desktop_object, NULL, NULL,
+        selected_folderW, 0UL, &selected_folder_pidl, 0UL);
+    bi.pidlRoot = selected_folder_pidl;
+
+    /* test without flags */
+    bi.ulFlags = 0;
+    pidl = SHBrowseForFolder(&bi);
+
+    if (pidl)
+        CoTaskMemFree(pidl);
+
+    /* test with flag */
+    bi.ulFlags = BIF_NEWDIALOGSTYLE;
+    pidl = SHBrowseForFolder(&bi);
+
+    if (pidl)
+        CoTaskMemFree(pidl);
+
+    desktop_object->lpVtbl->Release(desktop_object);
+
+    CoUninitialize();
+}
+
+START_TEST(brsfolder)
+{
+    test_click_make_new_folder_button();
+    test_selection();
+}
diff --git a/rostests/winetests/shell32/ebrowser.c b/rostests/winetests/shell32/ebrowser.c
new file mode 100644
index 00000000000..8149f8f95a4
--- /dev/null
+++ b/rostests/winetests/shell32/ebrowser.c
@@ -0,0 +1,1799 @@
+/*
+ *    Unit tests for the Explorer Browser control
+ *
+ * Copyright 2010 David Hedberg
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdio.h>
+
+#define COBJMACROS
+#define CONST_VTABLE
+
+#include "shlobj.h"
+#include "shlwapi.h"
+
+#include "wine/test.h"
+
+#include "initguid.h"
+#include "mshtml.h"
+
+/**********************************************************************
+ * Some IIDs for test_SetSite.
+ */
+DEFINE_GUID(IID_IBrowserSettings,     0xDD1E21CC, 0xE2C7, 0x402C, 0xBF,0x05, 0x10,0x32,0x8D,0x3F,0x6B,0xAD);
+DEFINE_GUID(IID_IShellBrowserService, 0xDFBC7E30, 0xF9E5, 0x455F, 0x88,0xF8, 0xFA,0x98,0xC1,0xE4,0x94,0xCA);
+DEFINE_GUID(IID_IShellTaskScheduler,  0x6CCB7BE0, 0x6807, 0x11D0, 0xB8,0x10, 0x00,0xC0,0x4F,0xD7,0x06,0xEC);
+DEFINE_GUID(IID_IBrowserWithActivationNotification,
+                                      0x6DB89131, 0x7B4C, 0x4E1C, 0x8B,0x01, 0x5D,0x31,0x2C,0x9C,0x73,0x88);
+DEFINE_GUID(IID_ILayoutModifier,      0x90B4135A, 0x95BA, 0x46EA, 0x8C,0xAA, 0xE0,0x5B,0x45,0xCD,0x80,0x1E);
+DEFINE_GUID(CLSID_Desktop,            0x00021400, 0x0000, 0x0000, 0xC0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
+DEFINE_GUID(IID_IFileDialogPrivate,   0xAC92FFC5, 0xF0E9, 0x455A, 0x90,0x6B, 0x4A,0x83,0xE7,0x4A,0x80,0x3B);
+DEFINE_GUID(IID_IWebbrowserApp,       0x0002df05, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46);
+DEFINE_GUID(IID_IBrowserSettings_Vista, 0xF81B80BC, 0x29D1, 0x4734, 0xB5,0x15, 0x77,0x24,0xBF,0xF1,0x60,0x01);
+DEFINE_GUID(IID_IFolderTypeModifier,    0x04BA120E, 0xAD52, 0x4A2D, 0x98,0x07, 0x2D,0xA1,0x78,0xD0,0xC3,0xE1);
+DEFINE_GUID(IID_IShellBrowserService_Vista, 0xF5A24314, 0x5B8B, 0x44FA, 0xBC,0x2E, 0x31,0x28,0x55,0x44,0xB5,0x20);
+DEFINE_GUID(IID_IFileDialogPrivate_Vista, 0x2539E31C, 0x857F, 0x43C4, 0x88,0x72, 0x45,0xBD,0x6A,0x02,0x48,0x92);
+DEFINE_GUID(SID_SMenuBandParent,      0x8C278EEC, 0x3EAB, 0x11D1, 0x8C,0xB0 ,0x00,0xC0,0x4F,0xD9,0x18,0xD0);
+DEFINE_GUID(SID_SMenuPopup,           0xD1E7AFEB, 0x6A2E, 0x11D0, 0x8C,0x78, 0x00,0xC0,0x4F,0xD9,0x18,0xB4);
+DEFINE_GUID(IID_IShellMenu,           0xEE1F7637, 0xE138, 0x11D1, 0x83,0x79, 0x00,0xC0,0x4F,0xD9,0x18,0xD0);
+
+DEFINE_GUID(IID_UnknownInterface1,    0x3934E4C2, 0x8143, 0x4E4C, 0xA1,0xDC, 0x71,0x8F,0x85,0x63,0xF3,0x37);
+DEFINE_GUID(IID_UnknownInterface2,    0x3E24A11C, 0x15B2, 0x4F71, 0xB8,0x1E, 0x00,0x8F,0x77,0x99,0x8E,0x9F);
+DEFINE_GUID(IID_UnknownInterface3,    0xE38FE0F3, 0x3DB0, 0x47EE, 0xA3,0x14, 0x25,0xCF,0x7F,0x4B,0xF5,0x21);
+DEFINE_GUID(IID_UnknownInterface4,    0xFAD451C2, 0xAF58, 0x4161, 0xB9,0xFF, 0x57,0xAF,0xBB,0xED,0x0A,0xD2);
+DEFINE_GUID(IID_UnknownInterface5,    0xF80C2137, 0x5829, 0x4CE9, 0x9F,0x81, 0xA9,0x5E,0x15,0x9D,0xD8,0xD5);
+DEFINE_GUID(IID_UnknownInterface6,    0xD7F81F62, 0x491F, 0x49BC, 0x89,0x1D, 0x56,0x65,0x08,0x5D,0xF9,0x69);
+DEFINE_GUID(IID_UnknownInterface7,    0x68A4FDBA, 0xA48A, 0x4A86, 0xA3,0x29, 0x1B,0x69,0xB9,0xB1,0x9E,0x89);
+DEFINE_GUID(IID_UnknownInterface8,    0xD3B1CAF5, 0xEC4F, 0x4B2E, 0xBC,0xB0, 0x60,0xD7,0x15,0xC9,0x3C,0xB2);
+DEFINE_GUID(IID_UnknownInterface9,    0x9536CA39, 0x1ACB, 0x4AE6, 0xAD,0x27, 0x24,0x03,0xD0,0x4C,0xA2,0x8F);
+DEFINE_GUID(IID_UnknownInterface10,   0xB722BE00, 0x4E68, 0x101B, 0xA2,0xBC, 0x00,0xAA,0x00,0x40,0x47,0x70);
+
+static HWND hwnd;
+
+static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
+static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
+
+static void init_function_pointers(void)
+{
+    HMODULE hmod;
+
+    hmod = GetModuleHandleA("shell32.dll");
+    pSHCreateShellItem = (void*)GetProcAddress(hmod, "SHCreateShellItem");
+    pSHParseDisplayName = (void*)GetProcAddress(hmod, "SHParseDisplayName");
+}
+
+/*********************************************************************
+ * Some simple helpers
+ */
+static HRESULT ebrowser_instantiate(IExplorerBrowser **peb)
+{
+    return CoCreateInstance(&CLSID_ExplorerBrowser, NULL, CLSCTX_INPROC_SERVER,
+                            &IID_IExplorerBrowser, (void**)peb);
+}
+
+static HRESULT ebrowser_initialize(IExplorerBrowser *peb)
+{
+    RECT rc;
+    rc.top = rc.left = 0; rc.bottom = rc.right = 500;
+    return IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+}
+
+static HRESULT ebrowser_browse_to_desktop(IExplorerBrowser *peb)
+{
+    LPITEMIDLIST pidl_desktop;
+    HRESULT hr;
+    SHGetSpecialFolderLocation (hwnd, CSIDL_DESKTOP, &pidl_desktop);
+    hr = IExplorerBrowser_BrowseToIDList(peb, pidl_desktop, 0);
+    ILFree(pidl_desktop);
+    return hr;
+}
+
+/* Process some messages */
+static void process_msgs(void)
+{
+    MSG msg;
+    while(PeekMessage( &msg, NULL, 0, 0, PM_REMOVE))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+}
+
+static void dbg_print_guid(const GUID *guid) {
+    WCHAR buf[MAX_PATH];
+
+    StringFromGUID2(guid, buf, MAX_PATH);
+    printf("guid:[%s]\n", wine_dbgstr_wn(buf, lstrlenW(buf)));
+}
+
+/*********************************************************************
+ * IExplorerBrowserEvents implementation
+ */
+typedef struct {
+    IExplorerBrowserEvents IExplorerBrowserEvents_iface;
+    LONG ref;
+    UINT pending, created, completed, failed;
+} IExplorerBrowserEventsImpl;
+
+static IExplorerBrowserEventsImpl ebev;
+
+static inline IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
+{
+    return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
+}
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnQueryInterface(IExplorerBrowserEvents *iface,
+                                                              REFIID riid, void **ppvObj)
+{
+    ok(0, "Never called.\n");
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IExplorerBrowserEvents_fnAddRef(IExplorerBrowserEvents *iface)
+{
+    IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IExplorerBrowserEvents_fnRelease(IExplorerBrowserEvents *iface)
+{
+    IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
+    return InterlockedDecrement(&This->ref);
+}
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationPending(IExplorerBrowserEvents *iface,
+                                                                   PCIDLIST_ABSOLUTE pidlFolder)
+{
+    IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
+    This->pending++;
+    return S_OK;
+}
+
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationComplete(IExplorerBrowserEvents *iface,
+                                                                    PCIDLIST_ABSOLUTE pidlFolder)
+{
+    IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
+    This->completed++;
+    return S_OK;
+}
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnNavigationFailed(IExplorerBrowserEvents *iface,
+                                                                  PCIDLIST_ABSOLUTE pidlFolder)
+{
+    IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
+    This->failed++;
+    return S_OK;
+}
+static HRESULT WINAPI IExplorerBrowserEvents_fnOnViewCreated(IExplorerBrowserEvents *iface,
+                                                             IShellView *psv)
+{
+    IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
+    This->created++;
+    return S_OK;
+}
+
+static const IExplorerBrowserEventsVtbl ebevents =
+{
+    IExplorerBrowserEvents_fnQueryInterface,
+    IExplorerBrowserEvents_fnAddRef,
+    IExplorerBrowserEvents_fnRelease,
+    IExplorerBrowserEvents_fnOnNavigationPending,
+    IExplorerBrowserEvents_fnOnViewCreated,
+    IExplorerBrowserEvents_fnOnNavigationComplete,
+    IExplorerBrowserEvents_fnOnNavigationFailed
+};
+
+/*********************************************************************
+ * IExplorerPaneVisibility implementation
+ */
+typedef struct
+{
+    IExplorerPaneVisibility IExplorerPaneVisibility_iface;
+    LONG ref;
+    LONG count;
+    LONG np, cp, cp_o, cp_v, dp, pp, qp, aqp, unk; /* The panes */
+} IExplorerPaneVisibilityImpl;
+
+static inline IExplorerPaneVisibilityImpl *impl_from_IExplorerPaneVisibility(IExplorerPaneVisibility *iface)
+{
+    return CONTAINING_RECORD(iface, IExplorerPaneVisibilityImpl, IExplorerPaneVisibility_iface);
+}
+
+static HRESULT WINAPI IExplorerPaneVisibility_fnQueryInterface(IExplorerPaneVisibility *iface,
+                                                               REFIID riid, LPVOID *ppvObj)
+{
+    ok(0, "Not called.\n");
+    trace("REFIID:"); dbg_print_guid(riid);
+    *ppvObj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IExplorerPaneVisibility_fnAddRef(IExplorerPaneVisibility *iface)
+{
+    IExplorerPaneVisibilityImpl *This = impl_from_IExplorerPaneVisibility(iface);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IExplorerPaneVisibility_fnRelease(IExplorerPaneVisibility *iface)
+{
+    IExplorerPaneVisibilityImpl *This = impl_from_IExplorerPaneVisibility(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if(!ref)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI IExplorerPaneVisibility_fnGetPaneState(IExplorerPaneVisibility *iface,
+                                                             REFEXPLORERPANE ep,
+                                                             EXPLORERPANESTATE *peps)
+{
+    IExplorerPaneVisibilityImpl *This = impl_from_IExplorerPaneVisibility(iface);
+    This->count++;
+
+    ok(ep != NULL, "ep is NULL.\n");
+    ok(peps != NULL, "peps is NULL.\n");
+    ok(*peps == 0, "got %d\n", *peps);
+
+    *peps = EPS_FORCE;
+    if(IsEqualGUID(&EP_NavPane, ep))                 This->np++;
+    else if(IsEqualGUID(&EP_Commands, ep))           This->cp++;
+    else if(IsEqualGUID(&EP_Commands_Organize, ep))  This->cp_o++;
+    else if(IsEqualGUID(&EP_Commands_View, ep))      This->cp_v++;
+    else if(IsEqualGUID(&EP_DetailsPane, ep))        This->dp++;
+    else if(IsEqualGUID(&EP_PreviewPane, ep))        This->pp++;
+    else if(IsEqualGUID(&EP_QueryPane, ep))          This->qp++;
+    else if(IsEqualGUID(&EP_AdvQueryPane, ep))       This->aqp++;
+    else
+    {
+        trace("Unknown explorer pane: "); dbg_print_guid(ep);
+        This->unk++;
+    }
+
+    return S_OK;
+}
+
+static const IExplorerPaneVisibilityVtbl epvvt =
+{
+    IExplorerPaneVisibility_fnQueryInterface,
+    IExplorerPaneVisibility_fnAddRef,
+    IExplorerPaneVisibility_fnRelease,
+    IExplorerPaneVisibility_fnGetPaneState
+};
+
+static IExplorerPaneVisibilityImpl *create_explorerpanevisibility(void)
+{
+    IExplorerPaneVisibilityImpl *epv;
+
+    epv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IExplorerPaneVisibilityImpl));
+    epv->IExplorerPaneVisibility_iface.lpVtbl = &epvvt;
+    epv->ref = 1;
+
+    return epv;
+}
+
+/*********************************************************************
+ * ICommDlgBrowser3 implementation
+ */
+typedef struct
+{
+    ICommDlgBrowser3 ICommDlgBrowser3_iface;
+    LONG ref;
+    UINT OnDefaultCommand, OnStateChange, IncludeObject;
+    UINT Notify, GetDefaultMenuText, GetViewFlags;
+    UINT OnColumnClicked, GetCurrentFilter, OnPreviewCreated;
+} ICommDlgBrowser3Impl;
+
+static inline ICommDlgBrowser3Impl *impl_from_ICommDlgBrowser3(ICommDlgBrowser3 *iface)
+{
+    return CONTAINING_RECORD(iface, ICommDlgBrowser3Impl, ICommDlgBrowser3_iface);
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnQueryInterface(ICommDlgBrowser3 *iface, REFIID riid, LPVOID *ppvObj)
+{
+    ok(0, "Not called.\n");
+    trace("riid:");    dbg_print_guid(riid);
+    *ppvObj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ICommDlgBrowser3_fnAddRef(ICommDlgBrowser3 *iface)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI ICommDlgBrowser3_fnRelease(ICommDlgBrowser3 *iface)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if(!ref)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnOnDefaultCommand(ICommDlgBrowser3* iface, IShellView *shv)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->OnDefaultCommand++;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnOnStateChange(
+    ICommDlgBrowser3* iface,
+    IShellView *shv,
+    ULONG uChange)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->OnStateChange++;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnIncludeObject(
+    ICommDlgBrowser3* iface,
+    IShellView *shv,
+    LPCITEMIDLIST pidl)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->IncludeObject++;
+    return S_OK;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnNotify(
+    ICommDlgBrowser3* iface,
+    IShellView *ppshv,
+    DWORD dwNotifyType)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->Notify++;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnGetDefaultMenuText(
+    ICommDlgBrowser3* iface,
+    IShellView *ppshv,
+    LPWSTR pszText,
+    int cchMax)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->GetDefaultMenuText++;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnGetViewFlags(
+    ICommDlgBrowser3* iface,
+    DWORD *pdwFlags)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->GetViewFlags++;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnOnColumnClicked(
+    ICommDlgBrowser3* iface,
+    IShellView *ppshv,
+    int iColumn)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->OnColumnClicked++;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnGetCurrentFilter(
+    ICommDlgBrowser3* iface,
+    LPWSTR pszFileSpec,
+    int cchFileSpec)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->GetCurrentFilter++;
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ICommDlgBrowser3_fnOnPreviewCreated(
+    ICommDlgBrowser3* iface,
+    IShellView *ppshv)
+{
+    ICommDlgBrowser3Impl *This = impl_from_ICommDlgBrowser3(iface);
+    This->OnPreviewCreated++;
+    return E_NOTIMPL;
+}
+
+static const ICommDlgBrowser3Vtbl cdbvtbl =
+{
+    ICommDlgBrowser3_fnQueryInterface,
+    ICommDlgBrowser3_fnAddRef,
+    ICommDlgBrowser3_fnRelease,
+    ICommDlgBrowser3_fnOnDefaultCommand,
+    ICommDlgBrowser3_fnOnStateChange,
+    ICommDlgBrowser3_fnIncludeObject,
+    ICommDlgBrowser3_fnNotify,
+    ICommDlgBrowser3_fnGetDefaultMenuText,
+    ICommDlgBrowser3_fnGetViewFlags,
+    ICommDlgBrowser3_fnOnColumnClicked,
+    ICommDlgBrowser3_fnGetCurrentFilter,
+    ICommDlgBrowser3_fnOnPreviewCreated
+};
+
+static ICommDlgBrowser3Impl *create_commdlgbrowser3(void)
+{
+    ICommDlgBrowser3Impl *cdb;
+
+    cdb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ICommDlgBrowser3Impl));
+    cdb->ICommDlgBrowser3_iface.lpVtbl = &cdbvtbl;
+    cdb->ref = 1;
+
+    return cdb;
+}
+
+/*********************************************************************
+ * IServiceProvider Implementation
+ */
+typedef struct {
+    IServiceProvider IServiceProvider_iface;
+    LONG ref;
+    struct services {
+        REFGUID service;
+        REFIID id;
+        int count;
+        void *punk;
+    } *interfaces;
+} IServiceProviderImpl;
+
+static inline IServiceProviderImpl *impl_from_IServiceProvider(IServiceProvider *iface)
+{
+    return CONTAINING_RECORD(iface, IServiceProviderImpl, IServiceProvider_iface);
+}
+
+static HRESULT WINAPI IServiceProvider_fnQueryInterface(IServiceProvider *iface, REFIID riid, LPVOID *ppvObj)
+{
+    *ppvObj = NULL;
+    if(IsEqualIID(riid, &IID_IServiceProvider))
+    {
+        *ppvObj = iface;
+        IServiceProvider_AddRef(iface);
+        return S_OK;
+    }
+
+    if(IsEqualIID(riid, &IID_IOleCommandTarget))
+    {
+        /* Windows Vista. */
+        return E_NOINTERFACE;
+    }
+
+    ok(0, "Unexpected interface requested.\n");
+    trace("riid: "); dbg_print_guid(riid);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IServiceProvider_fnAddRef(IServiceProvider *iface)
+{
+    IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IServiceProvider_fnRelease(IServiceProvider *iface)
+{
+    IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    if(!ref)
+        HeapFree(GetProcessHeap(), 0, This);
+
+    return ref;
+}
+
+static HRESULT WINAPI IServiceProvider_fnQueryService(IServiceProvider *iface,
+                                                      REFGUID guidService,
+                                                      REFIID riid,
+                                                      void **ppv)
+{
+    IServiceProviderImpl *This = impl_from_IServiceProvider(iface);
+    BOOL was_in_list = FALSE;
+    IUnknown *punk = NULL;
+    UINT i;
+
+    *ppv = NULL;
+    for(i = 0; This->interfaces[i].service != NULL; i++)
+    {
+        if(IsEqualGUID(This->interfaces[i].service, guidService) &&
+           IsEqualIID(This->interfaces[i].id, riid))
+        {
+            was_in_list = TRUE;
+            This->interfaces[i].count++;
+            punk = This->interfaces[i].punk;
+            break;
+        }
+    }
+
+    ok(was_in_list, "-- Unknown service requested --\n");
+    if(!was_in_list)
+    {
+        trace("guidService: "); dbg_print_guid(guidService);
+        trace("riid: "); dbg_print_guid(riid);
+    }
+
+    /* Give back an interface, if any. */
+    if(punk)
+    {
+        *ppv = punk;
+        IUnknown_AddRef(punk);
+        return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static const IServiceProviderVtbl spvtbl =
+{
+    IServiceProvider_fnQueryInterface,
+    IServiceProvider_fnAddRef,
+    IServiceProvider_fnRelease,
+    IServiceProvider_fnQueryService
+};
+
+static IServiceProviderImpl *create_serviceprovider(void)
+{
+    IServiceProviderImpl *sp = HeapAlloc(GetProcessHeap(), 0, sizeof(IServiceProviderImpl));
+    sp->IServiceProvider_iface.lpVtbl = &spvtbl;
+    sp->ref = 1;
+    return sp;
+}
+
+static void test_QueryInterface(void)
+{
+    IExplorerBrowser *peb;
+    IUnknown *punk;
+    HRESULT hr;
+    LONG lres;
+
+    hr = ebrowser_instantiate(&peb);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+#define test_qinterface(iid, exp)                                       \
+    do {                                                                \
+        hr = IExplorerBrowser_QueryInterface(peb, &iid, (void**)&punk); \
+        ok(hr == exp, "(%s:)Expected (0x%08x), got (0x%08x)\n",         \
+           #iid, exp, hr);                                              \
+        if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
+    } while(0)
+
+    test_qinterface(IID_IUnknown, S_OK);
+    test_qinterface(IID_IExplorerBrowser, S_OK);
+    test_qinterface(IID_IShellBrowser, S_OK);
+    todo_wine test_qinterface(IID_IOleWindow, S_OK);
+    test_qinterface(IID_ICommDlgBrowser, S_OK);
+    test_qinterface(IID_ICommDlgBrowser2, S_OK);
+    test_qinterface(IID_ICommDlgBrowser3, S_OK);
+    todo_wine test_qinterface(IID_IServiceProvider, S_OK);
+    test_qinterface(IID_IObjectWithSite, S_OK);
+    todo_wine test_qinterface(IID_IConnectionPointContainer, S_OK);
+    test_qinterface(IID_IOleObject, E_NOINTERFACE);
+    test_qinterface(IID_IViewObject, E_NOINTERFACE);
+    test_qinterface(IID_IViewObject2, E_NOINTERFACE);
+    test_qinterface(IID_IViewObjectEx, E_NOINTERFACE);
+    test_qinterface(IID_IConnectionPoint, E_NOINTERFACE);
+    test_qinterface(IID_IShellView, E_NOINTERFACE);
+    test_qinterface(IID_INameSpaceTreeControlEvents, E_NOINTERFACE);
+
+#undef test_qinterface
+
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got %d\n", lres);
+}
+
+static void test_SB_misc(void)
+{
+    IExplorerBrowser *peb;
+    IShellBrowser *psb;
+    IUnknown *punk;
+    HRESULT hr;
+    HWND retHwnd;
+    LRESULT lres;
+    LONG ref;
+
+    ebrowser_instantiate(&peb);
+    hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(FAILED(hr))
+    {
+        skip("Failed to get IShellBrowser interface.\n");
+        return;
+    }
+
+    /* Some unimplemented methods */
+    retHwnd = (HWND)0xDEADBEEF;
+    hr = IShellBrowser_GetControlWindow(psb, FCW_TOOLBAR, &retHwnd);
+    ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
+    ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
+
+    hr = IShellBrowser_GetControlWindow(psb, FCW_STATUS, &retHwnd);
+    ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
+    ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
+
+    hr = IShellBrowser_GetControlWindow(psb, FCW_TREE, &retHwnd);
+    ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
+    ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
+
+    hr = IShellBrowser_GetControlWindow(psb, FCW_PROGRESS, &retHwnd);
+    ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
+    ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
+
+    /* ::InsertMenuSB */
+    hr = IShellBrowser_InsertMenusSB(psb, NULL, NULL);
+    ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
+
+    /* ::RemoveMenusSB */
+    hr = IShellBrowser_RemoveMenusSB(psb, NULL);
+    ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
+
+    /* ::SetMenuSB */
+    hr = IShellBrowser_SetMenuSB(psb, NULL, NULL, NULL);
+    ok(hr == E_NOTIMPL, "got (0x%08x)\n", hr);
+
+    /***** Before EB::Initialize *****/
+
+    /* ::GetWindow */
+    retHwnd = (HWND)0xDEADBEEF;
+    hr = IShellBrowser_GetWindow(psb, &retHwnd);
+    ok(hr == E_FAIL, "got (0x%08x)\n", hr);
+    ok(retHwnd == (HWND)0xDEADBEEF, "HWND overwritten\n");
+
+    todo_wine
+    {
+
+        /* ::SendControlMsg */
+        lres = 0xDEADBEEF;
+        hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        ok(lres == 0, "lres was %ld\n", lres);
+
+        lres = 0xDEADBEEF;
+        hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, TB_CHECKBUTTON,
+                                          FCIDM_TB_SMALLICON, TRUE, &lres);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        ok(lres == 0, "lres was %ld\n", lres);
+
+        hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        hr = IShellBrowser_SendControlMsg(psb, FCW_TREE, 0, 0, 0, NULL);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        hr = IShellBrowser_SendControlMsg(psb, FCW_PROGRESS, 0, 0, 0, NULL);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    /* ::QueryActiveShellView */
+    hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
+    ok(hr == E_FAIL, "got (0x%08x)\n", hr);
+
+    /* Initialize ExplorerBrowser */
+    ebrowser_initialize(peb);
+
+    /***** After EB::Initialize *****/
+
+    /* ::GetWindow */
+    hr = IShellBrowser_GetWindow(psb, &retHwnd);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    ok(GetParent(retHwnd) == hwnd, "The HWND returned is not our child.\n");
+
+    todo_wine
+    {
+        /* ::SendControlMsg */
+        hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, NULL);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        lres = 0xDEADBEEF;
+        hr = IShellBrowser_SendControlMsg(psb, FCW_TOOLBAR, 0, 0, 0, &lres);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        ok(lres == 0, "lres was %ld\n", lres);
+
+        lres = 0xDEADBEEF;
+        hr = IShellBrowser_SendControlMsg(psb, FCW_STATUS, 0, 0, 0, &lres);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        ok(lres == 0, "lres was %ld\n", lres);
+
+        lres = 0xDEADBEEF;
+        hr = IShellBrowser_SendControlMsg(psb, 1234, 0, 0, 0, &lres);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        ok(lres == 0, "lres was %ld\n", lres);
+
+        /* Returns S_OK */
+        hr = IShellBrowser_SetStatusTextSB(psb, NULL);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        hr = IShellBrowser_ContextSensitiveHelp(psb, FALSE);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        hr = IShellBrowser_EnableModelessSB(psb, TRUE);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        hr = IShellBrowser_SetToolbarItems(psb, NULL, 1, 1);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
+    ok(hr == E_FAIL, "got (0x%08x)\n", hr);
+
+    IShellBrowser_Release(psb);
+    IExplorerBrowser_Destroy(peb);
+    IExplorerBrowser_Release(peb);
+
+    /* Browse to the desktop. */
+    ebrowser_instantiate(&peb);
+    ebrowser_initialize(peb);
+    IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
+
+    process_msgs();
+    hr = ebrowser_browse_to_desktop(peb);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    process_msgs();
+
+    /****** After Browsing *****/
+
+    hr = IShellBrowser_QueryActiveShellView(psb, (IShellView**)&punk);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+    IShellBrowser_Release(psb);
+    IExplorerBrowser_Destroy(peb);
+    ref = IExplorerBrowser_Release(peb);
+    ok(ref == 0, "Got %d\n", ref);
+}
+
+static void test_initialization(void)
+{
+    IExplorerBrowser *peb;
+    IShellBrowser *psb;
+    HRESULT hr;
+    ULONG lres;
+    RECT rc;
+
+    ebrowser_instantiate(&peb);
+
+    if(0)
+    {
+        /* Crashes on Windows 7 */
+        IExplorerBrowser_Initialize(peb, NULL, NULL, NULL);
+        IExplorerBrowser_Initialize(peb, hwnd, NULL, NULL);
+    }
+
+    ZeroMemory(&rc, sizeof(RECT));
+
+    hr = IExplorerBrowser_Initialize(peb, NULL, &rc, NULL);
+    ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
+
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    /* Initialize twice */
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
+
+    hr = IExplorerBrowser_Destroy(peb);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    /* Initialize again */
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == E_UNEXPECTED, "got (0x%08x)\n", hr);
+
+    /* Destroy again */
+    hr = IExplorerBrowser_Destroy(peb);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got %d\n", lres);
+
+    /* Initialize with a few different rectangles */
+    peb = NULL;
+    ebrowser_instantiate(&peb);
+    rc.left = 50; rc.top = 20; rc.right = 100; rc.bottom = 80;
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        HWND eb_hwnd;
+        RECT eb_rc;
+        char buf[1024];
+        LONG style, expected_style;
+        static const RECT exp_rc = {0, 0, 48, 58};
+
+        hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+        GetClientRect(eb_hwnd, &eb_rc);
+        ok(EqualRect(&eb_rc, &exp_rc), "Got client rect (%d, %d)-(%d, %d)\n",
+           eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
+
+        GetWindowRect(eb_hwnd, &eb_rc);
+        ok(eb_rc.right - eb_rc.left == 50, "Got window width %d\n", eb_rc.right - eb_rc.left);
+        ok(eb_rc.bottom - eb_rc.top == 60, "Got window height %d\n", eb_rc.bottom - eb_rc.top);
+
+        buf[0] = '\0';
+        GetClassNameA(eb_hwnd, buf, 1024);
+        ok(!lstrcmpA(buf, "ExplorerBrowserControl"), "Unexpected classname %s\n", buf);
+
+        expected_style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER;
+        style = GetWindowLongPtrW(eb_hwnd, GWL_STYLE);
+        todo_wine ok(style == expected_style, "Got style 0x%08x, expected 0x%08x\n", style, expected_style);
+
+        expected_style = WS_EX_CONTROLPARENT;
+        style = GetWindowLongPtrW(eb_hwnd, GWL_EXSTYLE);
+        ok(style == expected_style, "Got exstyle 0x%08x, expected 0x%08x\n", style, expected_style);
+
+        ok(GetParent(eb_hwnd) == hwnd, "GetParent returns %p\n", GetParent(eb_hwnd));
+
+        /* ::Destroy() destroys the window. */
+        ok(IsWindow(eb_hwnd), "eb_hwnd invalid.\n");
+        IExplorerBrowser_Destroy(peb);
+        ok(!IsWindow(eb_hwnd), "eb_hwnd valid.\n");
+
+        IShellBrowser_Release(psb);
+        lres = IExplorerBrowser_Release(peb);
+        ok(lres == 0, "Got refcount %d\n", lres);
+    }
+    else
+    {
+        skip("Skipping some tests.\n");
+
+        IExplorerBrowser_Destroy(peb);
+        lres = IExplorerBrowser_Release(peb);
+        ok(lres == 0, "Got refcount %d\n", lres);
+    }
+
+    ebrowser_instantiate(&peb);
+    rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    IExplorerBrowser_Destroy(peb);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got refcount %d\n", lres);
+
+    ebrowser_instantiate(&peb);
+    rc.left = -1; rc.top = -1; rc.right = 1; rc.bottom = 1;
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    IExplorerBrowser_Destroy(peb);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got refcount %d\n", lres);
+
+    ebrowser_instantiate(&peb);
+    rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    IExplorerBrowser_Destroy(peb);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got refcount %d\n", lres);
+
+    ebrowser_instantiate(&peb);
+    rc.left = 10; rc.top = 10; rc.right = 5; rc.bottom = 5;
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    IExplorerBrowser_Destroy(peb);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got refcount %d\n", lres);
+}
+
+static void test_SetSite(void)
+{
+    IExplorerBrowser *peb;
+    IServiceProviderImpl *spimpl = create_serviceprovider();
+    ICommDlgBrowser3Impl *cdbimpl = create_commdlgbrowser3();
+    IExplorerPaneVisibilityImpl *epvimpl = create_explorerpanevisibility();
+    IObjectWithSite *pow;
+    HRESULT hr;
+    LONG ref;
+    UINT i;
+    struct services expected[] = {
+        /* Win 7 */
+        { &SID_STopLevelBrowser,        &IID_ICommDlgBrowser2, 0, cdbimpl },
+        { &SID_STopLevelBrowser,        &IID_IShellBrowserService, 0, NULL },
+        { &SID_STopLevelBrowser,        &IID_IShellBrowser, 0, NULL },
+        { &SID_STopLevelBrowser,        &IID_UnknownInterface8, 0, NULL },
+        { &SID_STopLevelBrowser,        &IID_IConnectionPointContainer, 0, NULL },
+        { &SID_STopLevelBrowser,        &IID_IProfferService, 0, NULL },
+        { &SID_STopLevelBrowser,        &IID_UnknownInterface9, 0, NULL },
+        { &SID_ExplorerPaneVisibility,  &IID_IExplorerPaneVisibility, 0, epvimpl },
+        { &SID_SExplorerBrowserFrame,   &IID_ICommDlgBrowser2, 0, cdbimpl },
+        { &SID_SExplorerBrowserFrame,   &IID_ICommDlgBrowser3, 0, cdbimpl },
+        { &IID_IFileDialogPrivate,      &IID_IFileDialogPrivate, 0, NULL },
+        { &IID_IFileDialogPrivate,      &IID_IFileDialog, 0, NULL },
+        { &IID_IShellTaskScheduler,     &IID_IShellTaskScheduler, 0, NULL },
+        { &IID_IShellTaskScheduler,     &IID_UnknownInterface2, 0, NULL },
+        { &IID_IWebbrowserApp,          &IID_IConnectionPointContainer, 0, NULL },
+        { &IID_IFolderView,             &IID_IFolderView, 0, NULL },
+        { &IID_ILayoutModifier,         &IID_ILayoutModifier, 0, NULL },
+        { &IID_IBrowserSettings,        &IID_IBrowserSettings, 0, NULL },
+        { &CLSID_Desktop,               &IID_IUnknown, 0, NULL },
+        { &IID_UnknownInterface1,       &IID_UnknownInterface1, 0, NULL },
+        { &IID_UnknownInterface3,       &IID_UnknownInterface3, 0, NULL },
+        { &IID_UnknownInterface4,       &IID_IUnknown, 0, NULL },
+        { &IID_UnknownInterface6,       &IID_UnknownInterface7, 0, NULL },
+        { &IID_IBrowserWithActivationNotification, &IID_IBrowserWithActivationNotification, 0, NULL },
+
+        /* Other services requested in Vista, Windows 2008 but not in Windows 7 */
+        { &IID_IBrowserSettings_Vista,  &IID_IBrowserSettings_Vista, 0, NULL },
+        { &IID_IFolderTypeModifier,     &IID_IFolderTypeModifier, 0, NULL },
+        { &SID_STopLevelBrowser,        &IID_IShellBrowserService_Vista, 0, NULL },
+        { &IID_UnknownInterface5,       &IID_UnknownInterface5, 0, NULL },
+        { &IID_ICommDlgBrowser,         &IID_ICommDlgBrowser, 0, cdbimpl },
+        { &IID_IFileDialogPrivate_Vista,&IID_IFileDialogPrivate_Vista, 0, NULL},
+        { &IID_IFileDialogPrivate_Vista,&IID_IFileDialog, 0, NULL},
+        { &IID_UnknownInterface10,      &IID_IHTMLDocument2, 0, NULL},
+        { &SID_SMenuBandParent,         &IID_IOleCommandTarget, 0, NULL},
+        { &SID_SMenuBandParent,         &IID_IShellMenu, 0, NULL},
+        { &SID_STopLevelBrowser,        &IID_IOleWindow, 0, NULL},
+        { &SID_SMenuPopup,              &IID_IOleCommandTarget, 0, NULL},
+        { NULL }
+    };
+
+    ebrowser_instantiate(&peb);
+    IExplorerBrowser_SetOptions(peb, EBO_SHOWFRAMES);
+
+    hr = IExplorerBrowser_QueryInterface(peb, &IID_IObjectWithSite, (void**)&pow);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        spimpl->interfaces = expected;
+
+        hr = IObjectWithSite_SetSite(pow, (IUnknown*)&spimpl->IServiceProvider_iface);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+        if(FAILED(hr))
+            IObjectWithSite_Release(pow);
+    }
+
+    if(FAILED(hr))
+    {
+        skip("Failed to set site.\n");
+
+        IServiceProvider_Release(&spimpl->IServiceProvider_iface);
+        ICommDlgBrowser3_Release(&cdbimpl->ICommDlgBrowser3_iface);
+        IExplorerPaneVisibility_Release(&epvimpl->IExplorerPaneVisibility_iface);
+        IExplorerBrowser_Destroy(peb);
+        ref = IExplorerBrowser_Release(peb);
+        ok(ref == 0, "Got ref %d\n", ref);
+
+        return;
+    }
+
+    ShowWindow(hwnd, TRUE);
+    ebrowser_initialize(peb);
+    ebrowser_browse_to_desktop(peb);
+
+    for(i = 0; i < 10; i++)
+    {
+        Sleep(100);
+        process_msgs();
+    }
+    ShowWindow(hwnd, FALSE);
+
+    /* ICommDlgBrowser3 */
+    ok(!cdbimpl->OnDefaultCommand, "Got %d\n", cdbimpl->OnDefaultCommand);
+    todo_wine ok(cdbimpl->OnStateChange, "Got %d\n", cdbimpl->OnStateChange);
+    ok(cdbimpl->IncludeObject, "Got %d\n", cdbimpl->IncludeObject);
+    ok(!cdbimpl->Notify, "Got %d\n", cdbimpl->Notify);
+    ok(!cdbimpl->GetDefaultMenuText, "Got %d\n", cdbimpl->GetDefaultMenuText);
+    todo_wine ok(cdbimpl->GetViewFlags, "Got %d\n", cdbimpl->GetViewFlags);
+    ok(!cdbimpl->OnColumnClicked, "Got %d\n", cdbimpl->OnColumnClicked);
+    ok(!cdbimpl->GetCurrentFilter, "Got %d\n", cdbimpl->GetCurrentFilter);
+    todo_wine ok(cdbimpl->OnPreviewCreated, "Got %d\n", cdbimpl->OnPreviewCreated);
+
+    /* IExplorerPaneVisibility */
+    ok(epvimpl->np, "Got %d\n", epvimpl->np);
+    todo_wine ok(epvimpl->cp, "Got %d\n", epvimpl->cp);
+    todo_wine ok(epvimpl->cp_o, "Got %d\n", epvimpl->cp_o);
+    todo_wine ok(epvimpl->cp_v, "Got %d\n", epvimpl->cp_v);
+    todo_wine ok(epvimpl->dp, "Got %d\n", epvimpl->dp);
+    todo_wine ok(epvimpl->pp, "Got %d\n", epvimpl->pp);
+    ok(!epvimpl->qp, "Got %d\n", epvimpl->qp);
+    ok(!epvimpl->aqp, "Got %d\n", epvimpl->aqp);
+    ok(!epvimpl->unk, "Got %d\n", epvimpl->unk);
+
+    if(0)
+    {
+        for(i = 0; expected[i].service != NULL; i++)
+            if(!expected[i].count) trace("count %d was 0.\n", i);
+    }
+
+    /* Test when IServiceProvider is released. */
+    IServiceProvider_AddRef(&spimpl->IServiceProvider_iface);
+    ref = IServiceProvider_Release(&spimpl->IServiceProvider_iface);
+    ok(ref == 2, "Got ref %d\n", ref);
+
+    hr = IObjectWithSite_SetSite(pow, NULL);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    IServiceProvider_AddRef(&spimpl->IServiceProvider_iface);
+    ref = IServiceProvider_Release(&spimpl->IServiceProvider_iface);
+    ok(ref == 1, "Got ref %d\n", ref);
+
+    hr = IObjectWithSite_SetSite(pow, (IUnknown*)&spimpl->IServiceProvider_iface);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    IServiceProvider_AddRef(&spimpl->IServiceProvider_iface);
+    ref = IServiceProvider_Release(&spimpl->IServiceProvider_iface);
+    ok(ref == 2, "Got ref %d\n", ref);
+
+    IExplorerBrowser_Destroy(peb);
+
+    IServiceProvider_AddRef(&spimpl->IServiceProvider_iface);
+    ref = IServiceProvider_Release(&spimpl->IServiceProvider_iface);
+    ok(ref == 2, "Got ref %d\n", ref);
+
+    IObjectWithSite_Release(pow);
+    ref = IExplorerBrowser_Release(peb);
+    ok(ref == 0, "Got ref %d\n", ref);
+
+    ref = IServiceProvider_Release(&spimpl->IServiceProvider_iface);
+    ok(ref == 0, "Got ref %d\n", ref);
+
+    ref = ICommDlgBrowser3_Release(&cdbimpl->ICommDlgBrowser3_iface);
+    ok(ref == 0, "Got ref %d\n", ref);
+    ref = IExplorerPaneVisibility_Release(&epvimpl->IExplorerPaneVisibility_iface);
+    ok(ref == 0, "Got ref %d\n", ref);
+}
+
+static void test_basics(void)
+{
+    IExplorerBrowser *peb;
+    IShellBrowser *psb;
+    FOLDERSETTINGS fs;
+    ULONG lres;
+    DWORD flags;
+    HDWP hdwp;
+    RECT rc;
+    HRESULT hr;
+    static const WCHAR winetest[] = {'W','i','n','e','T','e','s','t',0};
+
+    ebrowser_instantiate(&peb);
+    ebrowser_initialize(peb);
+
+    /* SetRect */
+    rc.left = 0; rc.top = 0; rc.right = 0; rc.bottom = 0;
+    hr = IExplorerBrowser_SetRect(peb, NULL, rc);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    rc.left = 100; rc.top = 100; rc.right = 10; rc.bottom = 10;
+    hr = IExplorerBrowser_SetRect(peb, NULL, rc);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    /* SetRect with DeferWindowPos */
+    rc.left = rc.top = 0; rc.right = rc.bottom = 10;
+    hdwp = BeginDeferWindowPos(1);
+    hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    lres = EndDeferWindowPos(hdwp);
+    ok(lres, "EndDeferWindowPos failed.\n");
+
+    hdwp = NULL;
+    hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    ok(hdwp == NULL, "got %p\n", hdwp);
+    lres = EndDeferWindowPos(hdwp);
+    ok(!lres, "EndDeferWindowPos succeeded unexpectedly.\n");
+
+    /* Test positioning */
+    rc.left = 10; rc.top = 20; rc.right = 50; rc.bottom = 50;
+    hr = IExplorerBrowser_SetRect(peb, NULL, rc);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        HWND eb_hwnd;
+        RECT eb_rc;
+        static const RECT exp_rc = {11, 21, 49, 49};
+        static const RECT exp_rc2 = {11, 21, 49, 24};
+
+        hr = IShellBrowser_GetWindow(psb, &eb_hwnd);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+        GetClientRect(eb_hwnd, &eb_rc);
+        MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
+        ok(EqualRect(&eb_rc, &exp_rc), "Got rect (%d, %d) - (%d, %d)\n",
+           eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
+
+        /* Try resizing with invalid hdwp */
+        rc.bottom = 25;
+        hdwp = (HDWP)0xdeadbeef;
+        hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
+        ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+        GetClientRect(eb_hwnd, &eb_rc);
+        MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
+        ok(EqualRect(&eb_rc, &exp_rc), "Got rect (%d, %d) - (%d, %d)\n",
+           eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
+
+        hdwp = NULL;
+        hr = IExplorerBrowser_SetRect(peb, &hdwp, rc);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        GetClientRect(eb_hwnd, &eb_rc);
+        MapWindowPoints(eb_hwnd, hwnd, (POINT*)&eb_rc, 2);
+        ok(EqualRect(&eb_rc, &exp_rc2), "Got rect (%d, %d) - (%d, %d)\n",
+           eb_rc.left, eb_rc.top, eb_rc.right, eb_rc.bottom);
+
+        IShellBrowser_Release(psb);
+    }
+
+    IExplorerBrowser_Destroy(peb);
+    IExplorerBrowser_Release(peb);
+
+    /* GetOptions/SetOptions*/
+    ebrowser_instantiate(&peb);
+
+    if(0) {
+        /* Crashes on Windows 7 */
+        IExplorerBrowser_GetOptions(peb, NULL);
+    }
+
+    hr = IExplorerBrowser_GetOptions(peb, &flags);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    ok(flags == 0, "got (0x%08x)\n", flags);
+
+    /* Settings preserved through Initialize. */
+    hr = IExplorerBrowser_SetOptions(peb, 0xDEADBEEF);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    ebrowser_initialize(peb);
+
+    hr = IExplorerBrowser_GetOptions(peb, &flags);
+    ok(flags == 0xDEADBEEF, "got (0x%08x)\n", flags);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    IExplorerBrowser_Destroy(peb);
+    IExplorerBrowser_Release(peb);
+
+    ebrowser_instantiate(&peb);
+    ebrowser_initialize(peb);
+
+    /* SetFolderSettings */
+    hr = IExplorerBrowser_SetFolderSettings(peb, NULL);
+    ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
+    fs.ViewMode = 0; fs.fFlags = 0;
+    hr = IExplorerBrowser_SetFolderSettings(peb, &fs);
+    todo_wine ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
+
+    /* SetPropertyBag */
+    hr = IExplorerBrowser_SetPropertyBag(peb, NULL);
+    ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
+    hr = IExplorerBrowser_SetPropertyBag(peb, winetest);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    /* TODO: Test after browsing somewhere. */
+
+    IExplorerBrowser_Destroy(peb);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got %d\n", lres);
+}
+
+static void test_Advise(void)
+{
+    IExplorerBrowser *peb;
+    IExplorerBrowserEvents *pebe;
+    DWORD cookies[10];
+    HRESULT hr;
+    UINT i, ref;
+
+    /* Set up our IExplorerBrowserEvents implementation */
+    ebev.IExplorerBrowserEvents_iface.lpVtbl = &ebevents;
+    pebe = &ebev.IExplorerBrowserEvents_iface;
+
+    ebrowser_instantiate(&peb);
+
+    if(0)
+    {
+        /* Crashes on Windows 7 */
+        IExplorerBrowser_Advise(peb, pebe, NULL);
+        IExplorerBrowser_Advise(peb, NULL, &cookies[0]);
+    }
+
+    /* Using Unadvise with a cookie that has yet to be given out
+     * results in E_INVALIDARG */
+    hr = IExplorerBrowser_Unadvise(peb, 11);
+    ok(hr == E_INVALIDARG, "got (0x%08x)\n", hr);
+
+    /* Add some before initialization */
+    for(i = 0; i < 5; i++)
+    {
+        hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    ebrowser_initialize(peb);
+
+    /* Add some after initialization */
+    for(i = 5; i < 10; i++)
+    {
+        hr = IExplorerBrowser_Advise(peb, pebe, &cookies[i]);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    ok(ebev.ref == 10, "Got %d\n", ebev.ref);
+
+    ebev.completed = 0;
+    ebrowser_browse_to_desktop(peb);
+    process_msgs();
+    ok(ebev.completed == 10, "Got %d\n", ebev.completed);
+
+    /* Remove a bunch somewhere in the middle */
+    for(i = 4; i < 8; i++)
+    {
+        hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    }
+
+    ebev.completed = 0;
+    ebrowser_browse_to_desktop(peb);
+    process_msgs();
+    ok(ebev.completed == 6, "Got %d\n", ebev.completed);
+
+    if(0)
+    {
+        /* Using unadvise with a previously unadvised cookie results
+         * in a crash. */
+        IExplorerBrowser_Unadvise(peb, cookies[5]);
+    }
+
+    /* Remove the rest. */
+    for(i = 0; i < 10; i++)
+    {
+        if(i<4||i>7)
+        {
+            hr = IExplorerBrowser_Unadvise(peb, cookies[i]);
+            ok(hr == S_OK, "%d: got (0x%08x)\n", i, hr);
+        }
+    }
+
+    ok(ebev.ref == 0, "Got %d\n", ebev.ref);
+
+    ebev.completed = 0;
+    ebrowser_browse_to_desktop(peb);
+    process_msgs();
+    ok(ebev.completed == 0, "Got %d\n", ebev.completed);
+
+    /* ::Destroy implies ::Unadvise. */
+    hr = IExplorerBrowser_Advise(peb, pebe, &cookies[0]);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(ebev.ref == 1, "Got %d\n", ebev.ref);
+
+    hr = IExplorerBrowser_Destroy(peb);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(ebev.ref == 0, "Got %d\n", ebev.ref);
+
+    ref = IExplorerBrowser_Release(peb);
+    ok(!ref, "Got %d\n", ref);
+}
+
+/* Based on PathAddBackslashW from dlls/shlwapi/path.c */
+static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
+{
+  size_t iLen;
+
+  if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
+    return NULL;
+
+  if (iLen)
+  {
+    lpszPath += iLen;
+    if (lpszPath[-1] != '\\')
+    {
+      *lpszPath++ = '\\';
+      *lpszPath = '\0';
+    }
+  }
+  return lpszPath;
+}
+
+static void test_browse_pidl_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
+                              LPITEMIDLIST pidl, UINT uFlags,
+                              HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
+                              const char *file, int line)
+{
+    HRESULT hr;
+    ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
+
+    hr = IExplorerBrowser_BrowseToIDList(peb, pidl, uFlags);
+    ok_(file, line) (hr == hr_exp, "BrowseToIDList returned 0x%08x\n", hr);
+    process_msgs();
+
+    ok_(file, line)
+        (ebev->pending == pending && ebev->created == created &&
+         ebev->failed == failed && ebev->completed == completed,
+         "Events occurred: %d, %d, %d, %d\n",
+         ebev->pending, ebev->created, ebev->failed, ebev->completed);
+}
+#define test_browse_pidl(peb, ebev, pidl, uFlags, hr, p, cr, f, co)     \
+    test_browse_pidl_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
+
+static void test_browse_pidl_sb_(IExplorerBrowser *peb, IExplorerBrowserEventsImpl *ebev,
+                                 LPITEMIDLIST pidl, UINT uFlags,
+                                 HRESULT hr_exp, UINT pending, UINT created, UINT failed, UINT completed,
+                                 const char *file, int line)
+{
+    IShellBrowser *psb;
+    HRESULT hr;
+
+    hr = IExplorerBrowser_QueryInterface(peb, &IID_IShellBrowser, (void**)&psb);
+    ok_(file, line) (hr == S_OK, "QueryInterface returned 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        ebev->completed = ebev->created = ebev->pending = ebev->failed = 0;
+
+        hr = IShellBrowser_BrowseObject(psb, pidl, uFlags);
+        ok_(file, line) (hr == hr_exp, "BrowseObject returned 0x%08x\n", hr);
+        process_msgs();
+
+        ok_(file, line)
+            (ebev->pending == pending && ebev->created == created &&
+             ebev->failed == failed && ebev->completed == completed,
+             "Events occurred: %d, %d, %d, %d\n",
+             ebev->pending, ebev->created, ebev->failed, ebev->completed);
+
+        IShellBrowser_Release(psb);
+    }
+}
+#define test_browse_pidl_sb(peb, ebev, pidl, uFlags, hr, p, cr, f, co)  \
+    test_browse_pidl_sb_(peb, ebev, pidl, uFlags, hr, p, cr, f, co, __FILE__, __LINE__)
+
+static void test_navigation(void)
+{
+    IExplorerBrowser *peb, *peb2;
+    IFolderView *pfv;
+    IShellItem *psi;
+    IShellFolder *psf;
+    LPITEMIDLIST pidl_current, pidl_child;
+    DWORD cookie, cookie2;
+    HRESULT hr;
+    LONG lres;
+    WCHAR current_path[MAX_PATH];
+    WCHAR child_path[MAX_PATH];
+    static const WCHAR testfolderW[] =
+        {'w','i','n','e','t','e','s','t','f','o','l','d','e','r','\0'};
+
+    ok(pSHParseDisplayName != NULL, "pSHParseDisplayName unexpectedly missing.\n");
+    ok(pSHCreateShellItem != NULL, "pSHCreateShellItem unexpectedly missing.\n");
+
+    GetCurrentDirectoryW(MAX_PATH, current_path);
+    if(!lstrlenW(current_path))
+    {
+        skip("Failed to create test-directory.\n");
+        return;
+    }
+
+    lstrcpyW(child_path, current_path);
+    myPathAddBackslashW(child_path);
+    lstrcatW(child_path, testfolderW);
+
+    CreateDirectoryW(child_path, NULL);
+
+    pSHParseDisplayName(current_path, NULL, &pidl_current, 0, NULL);
+    pSHParseDisplayName(child_path, NULL, &pidl_child, 0, NULL);
+
+    ebrowser_instantiate(&peb);
+    ebrowser_initialize(peb);
+
+    ebrowser_instantiate(&peb2);
+    ebrowser_initialize(peb2);
+
+    /* Set up our IExplorerBrowserEvents implementation */
+    ebev.IExplorerBrowserEvents_iface.lpVtbl = &ebevents;
+
+    IExplorerBrowser_Advise(peb, &ebev.IExplorerBrowserEvents_iface, &cookie);
+    IExplorerBrowser_Advise(peb2, &ebev.IExplorerBrowserEvents_iface, &cookie2);
+
+    /* These should all fail */
+    test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE | SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, E_INVALIDARG, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_RELATIVE, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, E_FAIL, 0, 0, 0, 0);
+
+    /* "The first browse is synchronous" */
+    test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, S_OK, 1, 1, 0, 1);
+
+    /* Navigate empty history */
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 0, 0, 0, 0);
+
+    /* Navigate history */
+    test_browse_pidl(peb, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_PARENT, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEBACK, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_NAVIGATEFORWARD, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, 0, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
+
+    /* Relative navigation */
+    test_browse_pidl(peb, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_ABSOLUTE, S_OK, 1, 0, 0, 1);
+
+    hr = IExplorerBrowser_GetCurrentView(peb, &IID_IFolderView, (void**)&pfv);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        LPITEMIDLIST pidl_relative;
+
+        hr = IFolderView_GetFolder(pfv, &IID_IShellFolder, (void**)&psf);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        hr = IShellFolder_ParseDisplayName(psf, NULL, NULL, (LPWSTR)testfolderW,
+                                           NULL, &pidl_relative, NULL);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+        /* Browsing to another location here before using the
+         * pidl_relative would make ExplorerBrowser in Windows 7 show a
+         * not-available dialog. Also, passing a relative pidl without
+         * specifying SBSP_RELATIVE makes it look for the pidl on the
+         * desktop
+         */
+
+        test_browse_pidl(peb, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
+        test_browse_pidl_sb(peb2, &ebev, pidl_relative, SBSP_RELATIVE, S_OK, 1, 1, 0, 1);
+
+        ILFree(pidl_relative);
+        /* IShellFolder_Release(psf); */
+        IFolderView_Release(pfv);
+    }
+
+    /* misc **/
+    test_browse_pidl(peb, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_ABSOLUTE, S_OK, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, NULL, SBSP_DEFBROWSER, S_OK, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_SAMEBROWSER, S_OK, 1, 0, 0, 1);
+
+    test_browse_pidl(peb, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_EXPLOREMODE, E_INVALIDARG, 0, 0, 0, 0);
+    test_browse_pidl(peb, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
+    test_browse_pidl_sb(peb2, &ebev, pidl_current, SBSP_OPENMODE, S_OK, 1, 0, 0, 1);
+
+    /* SBSP_NEWBROWSER will return E_INVALIDARG, claims MSDN, but in
+     * reality it works as one would expect (Windows 7 only?).
+     */
+    if(0)
+    {
+        IExplorerBrowser_BrowseToIDList(peb, NULL, SBSP_NEWBROWSER);
+    }
+
+    hr = IExplorerBrowser_Unadvise(peb, cookie);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    IExplorerBrowser_Destroy(peb);
+    process_msgs();
+    hr = IExplorerBrowser_Unadvise(peb2, cookie2);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    IExplorerBrowser_Destroy(peb2);
+    process_msgs();
+
+    /* Attempt browsing after destroyed */
+    test_browse_pidl(peb, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
+    test_browse_pidl_sb(peb2, &ebev, pidl_child, SBSP_ABSOLUTE, HRESULT_FROM_WIN32(ERROR_BUSY), 0, 0, 0, 0);
+
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got lres %d\n", lres);
+    lres = IExplorerBrowser_Release(peb2);
+    ok(lres == 0, "Got lres %d\n", lres);
+
+    /******************************************/
+    /* Test some options that affect browsing */
+
+    ebrowser_instantiate(&peb);
+    hr = IExplorerBrowser_Advise(peb, &ebev.IExplorerBrowserEvents_iface, &cookie);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    hr = IExplorerBrowser_SetOptions(peb, EBO_NAVIGATEONCE);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    ebrowser_initialize(peb);
+
+    test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 1, 0, 1);
+    test_browse_pidl(peb, &ebev, pidl_current, 0, E_FAIL, 0, 0, 0, 0);
+
+    hr = IExplorerBrowser_SetOptions(peb, 0);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
+    test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
+
+    /* Difference in behavior lies where? */
+    hr = IExplorerBrowser_SetOptions(peb, EBO_ALWAYSNAVIGATE);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
+    test_browse_pidl(peb, &ebev, pidl_current, 0, S_OK, 1, 0, 0, 1);
+
+    hr = IExplorerBrowser_Unadvise(peb, cookie);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    IExplorerBrowser_Destroy(peb);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got lres %d\n", lres);
+
+    /* BrowseToObject tests */
+    ebrowser_instantiate(&peb);
+    ebrowser_initialize(peb);
+
+    /* Browse to the desktop by passing an IShellFolder */
+    hr = SHGetDesktopFolder(&psf);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psf, SBSP_DEFBROWSER);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        if(hr == S_OK) process_msgs();
+
+        IShellFolder_Release(psf);
+    }
+
+    /* Browse to the current directory by passing a ShellItem */
+    hr = pSHCreateShellItem(NULL, NULL, pidl_current, &psi);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psi, SBSP_DEFBROWSER);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        process_msgs();
+
+        IShellItem_Release(psi);
+    }
+
+    IExplorerBrowser_Destroy(peb);
+    lres = IExplorerBrowser_Release(peb);
+    ok(lres == 0, "Got lres %d\n", lres);
+
+    /* Cleanup */
+    RemoveDirectoryW(child_path);
+    ILFree(pidl_current);
+    ILFree(pidl_child);
+}
+
+static void test_GetCurrentView(void)
+{
+    IExplorerBrowser *peb;
+    IUnknown *punk;
+    HRESULT hr;
+
+    /* GetCurrentView */
+    ebrowser_instantiate(&peb);
+
+    if(0)
+    {
+        /* Crashes under Windows 7 */
+        IExplorerBrowser_GetCurrentView(peb, NULL, NULL);
+    }
+    hr = IExplorerBrowser_GetCurrentView(peb, NULL, (void**)&punk);
+    ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+#define test_gcv(iid, exp)                                              \
+    do {                                                                \
+        hr = IExplorerBrowser_GetCurrentView(peb, &iid, (void**)&punk); \
+        ok(hr == exp, "(%s:)Expected (0x%08x), got: (0x%08x)\n",        \
+           #iid ,exp, hr);                                              \
+        if(SUCCEEDED(hr)) IUnknown_Release(punk);                       \
+    } while(0)
+
+    test_gcv(IID_IUnknown, E_FAIL);
+    test_gcv(IID_IUnknown, E_FAIL);
+    test_gcv(IID_IShellView, E_FAIL);
+    test_gcv(IID_IShellView2, E_FAIL);
+    test_gcv(IID_IFolderView, E_FAIL);
+    test_gcv(IID_IPersistFolder, E_FAIL);
+    test_gcv(IID_IPersistFolder2, E_FAIL);
+    test_gcv(IID_ICommDlgBrowser, E_FAIL);
+    test_gcv(IID_ICommDlgBrowser2, E_FAIL);
+    test_gcv(IID_ICommDlgBrowser3, E_FAIL);
+
+    ebrowser_initialize(peb);
+    ebrowser_browse_to_desktop(peb);
+
+    test_gcv(IID_IUnknown, S_OK);
+    test_gcv(IID_IUnknown, S_OK);
+    test_gcv(IID_IShellView, S_OK);
+    test_gcv(IID_IShellView2, S_OK);
+    test_gcv(IID_IFolderView, S_OK);
+    todo_wine test_gcv(IID_IPersistFolder, S_OK);
+    test_gcv(IID_IPersistFolder2, E_NOINTERFACE);
+    test_gcv(IID_ICommDlgBrowser, E_NOINTERFACE);
+    test_gcv(IID_ICommDlgBrowser2, E_NOINTERFACE);
+    test_gcv(IID_ICommDlgBrowser3, E_NOINTERFACE);
+
+#undef test_gcv
+
+    IExplorerBrowser_Destroy(peb);
+    IExplorerBrowser_Release(peb);
+}
+
+static void test_InputObject(void)
+{
+    IExplorerBrowser *peb;
+    IShellFolder *psf;
+    IInputObject *pio;
+    HRESULT hr;
+    RECT rc;
+    UINT i;
+    WPARAM supported_key_accels_mode1[] = {
+        VK_BACK, VK_TAB, VK_RETURN, VK_PRIOR, VK_NEXT, VK_END, VK_HOME,
+        VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_DELETE, VK_F1, VK_F2,
+        VK_F5, VK_F6, VK_F10, 0 };
+    WPARAM supported_key_accels_mode2[] = {
+        VK_RETURN, VK_PRIOR, VK_NEXT, VK_END, VK_HOME,
+        VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN, VK_DELETE, VK_F1, VK_F2,
+        VK_F10, 0 };
+    WPARAM *key_accels;
+    MSG msg_a = {
+        hwnd,
+        WM_KEYDOWN,
+        VK_F5, 0,
+        GetTickCount(),
+        {5, 2}
+    };
+
+    ebrowser_instantiate(&peb);
+    hr = IExplorerBrowser_QueryInterface(peb, &IID_IInputObject, (void**)&pio);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(FAILED(hr))
+    {
+        win_skip("IInputObject not supported.\n");
+        return;
+    }
+
+    /* Before initializing */
+    hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
+    todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_HasFocusIO(pio);
+    todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_UIActivateIO(pio, TRUE, &msg_a);
+    todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_HasFocusIO(pio);
+    todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
+    todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+    rc.left = 0; rc.top = 0; rc.right = 100; rc.bottom = 100;
+    hr = IExplorerBrowser_Initialize(peb, hwnd, &rc, NULL);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_HasFocusIO(pio);
+    todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
+    todo_wine ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+    /* Browse to the desktop */
+    SHGetDesktopFolder(&psf);
+    hr = IExplorerBrowser_BrowseToObject(peb, (IUnknown*)psf, SBSP_DEFBROWSER);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    IShellFolder_Release(psf);
+
+    hr = IInputObject_UIActivateIO(pio, TRUE, &msg_a);
+    todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_HasFocusIO(pio);
+    todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_UIActivateIO(pio, FALSE, &msg_a);
+    todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_HasFocusIO(pio);
+    todo_wine ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+    hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
+    if(hr == S_OK)
+        key_accels = supported_key_accels_mode1;
+    else
+        key_accels = supported_key_accels_mode2;
+
+    for(i = 0; i < 0x100; i++)
+    {
+        BOOL found = FALSE;
+        UINT j;
+        for(j = 0; key_accels[j] != 0; j++)
+            if(key_accels[j] == i)
+            {
+                found = TRUE;
+                break;
+            }
+
+        msg_a.wParam = i;
+        process_msgs();
+        hr = IInputObject_TranslateAcceleratorIO(pio, &msg_a);
+        todo_wine ok(hr == (found ? S_OK : S_FALSE), "Got 0x%08x (%04x)\n", hr, i);
+        if(i == VK_F5)
+            Sleep(1000); /* Needed for w2k8 (64bit) */
+    }
+
+    process_msgs();
+
+    IInputObject_Release(pio);
+    IExplorerBrowser_Destroy(peb);
+    IExplorerBrowser_Release(peb);
+}
+
+static BOOL test_instantiate_control(void)
+{
+    IExplorerBrowser *peb;
+    HRESULT hr;
+
+    hr = ebrowser_instantiate(&peb);
+    ok(hr == S_OK || hr == REGDB_E_CLASSNOTREG, "Got (0x%08x)\n", hr);
+    if(FAILED(hr))
+        return FALSE;
+
+    IExplorerBrowser_Release(peb);
+    return TRUE;
+}
+
+static void setup_window(void)
+{
+    WNDCLASSW wc;
+    static const WCHAR ebtestW[] = {'e','b','t','e','s','t',0};
+
+    ZeroMemory(&wc, sizeof(WNDCLASSW));
+    wc.lpfnWndProc      = DefWindowProcW;
+    wc.lpszClassName    = ebtestW;
+    RegisterClassW(&wc);
+    hwnd = CreateWindowExW(0, ebtestW, NULL, 0,
+                           0, 0, 500, 500,
+                           NULL, 0, 0, NULL);
+    ok(hwnd != NULL, "Failed to create window for tests.\n");
+}
+
+START_TEST(ebrowser)
+{
+    OleInitialize(NULL);
+
+    if(!test_instantiate_control())
+    {
+        win_skip("No ExplorerBrowser control..\n");
+        OleUninitialize();
+        return;
+    }
+
+    setup_window();
+    init_function_pointers();
+
+    test_QueryInterface();
+    test_SB_misc();
+    test_initialization();
+    test_basics();
+    test_Advise();
+    test_navigation();
+    test_GetCurrentView();
+    test_SetSite();
+    test_InputObject();
+
+    DestroyWindow(hwnd);
+    OleUninitialize();
+}
diff --git a/rostests/winetests/shell32/progman_dde.c b/rostests/winetests/shell32/progman_dde.c
index d7bf4326a30..1e3239da818 100644
--- a/rostests/winetests/shell32/progman_dde.c
+++ b/rostests/winetests/shell32/progman_dde.c
@@ -200,14 +200,22 @@ static void init_strings(void)
             WCHAR module[MAX_PATH];
             WCHAR module_expanded[MAX_PATH];
             WCHAR localized[MAX_PATH];
+            HRESULT hr;
             int id;
 
             MultiByteToWideChar(CP_ACP, 0, startup, -1, startupW, sizeof(startupW)/sizeof(WCHAR));
-            pSHGetLocalizedName(startupW, module, MAX_PATH, &id);
-            ExpandEnvironmentStringsW(module, module_expanded, MAX_PATH);
-            LoadStringW(GetModuleHandleW(module_expanded), id, localized, MAX_PATH);
+            hr = pSHGetLocalizedName(startupW, module, MAX_PATH, &id);
+            todo_wine ok(hr == S_OK, "got 0x%08x\n", hr);
+            /* check to be removed when SHGetLocalizedName is implemented */
+            if (hr == S_OK)
+            {
+                ExpandEnvironmentStringsW(module, module_expanded, MAX_PATH);
+                LoadStringW(GetModuleHandleW(module_expanded), id, localized, MAX_PATH);
 
-            WideCharToMultiByte(CP_ACP, 0, localized, -1, StartupTitle, sizeof(StartupTitle), NULL, NULL);
+                WideCharToMultiByte(CP_ACP, 0, localized, -1, StartupTitle, sizeof(StartupTitle), NULL, NULL);
+            }
+            else
+                lstrcpyA(StartupTitle, (strrchr(startup, '\\') + 1));
         }
         else
         {
diff --git a/rostests/winetests/shell32/recyclebin.c b/rostests/winetests/shell32/recyclebin.c
new file mode 100644
index 00000000000..391e0254990
--- /dev/null
+++ b/rostests/winetests/shell32/recyclebin.c
@@ -0,0 +1,107 @@
+/*
+ * Tests for recycle bin functions
+ *
+ * Copyright 2011 Jay Yang
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include "shellapi.h"
+
+#include <stdio.h>
+#include "wine/test.h"
+
+static int (WINAPI *pSHQueryRecycleBinA)(LPCSTR,LPSHQUERYRBINFO);
+static int (WINAPI *pSHFileOperationA)(LPSHFILEOPSTRUCTA);
+
+static char int64_buffer[65];
+/* Note: This function uses a single buffer for the return value.*/
+static const char* str_from_int64(__int64 ll)
+{
+
+    if (sizeof(ll) > sizeof(unsigned long) && ll >> 32)
+        sprintf(int64_buffer,"%lx%08lx",(unsigned long)(ll >> 32),(unsigned long)ll);
+    else
+        sprintf(int64_buffer,"%lx",(unsigned long)ll);
+    return int64_buffer;
+}
+
+static void setup_pointers(void)
+{
+    HMODULE hshell32 = GetModuleHandleA("shell32.dll");
+    pSHQueryRecycleBinA = (void*)GetProcAddress(hshell32, "SHQueryRecycleBinA");
+    pSHFileOperationA = (void*)GetProcAddress(hshell32, "SHFileOperationA");
+}
+
+static void test_query_recyclebin(void)
+{
+    SHQUERYRBINFO info1={sizeof(info1),0xdeadbeef,0xdeadbeef};
+    SHQUERYRBINFO info2={sizeof(info2),0xdeadbeef,0xdeadbeef};
+    UINT written;
+    HRESULT hr;
+    HANDLE file;
+    SHFILEOPSTRUCTA shfo;
+    const CHAR *name="test.txt";
+    CHAR buf[MAX_PATH+strlen(name)+2];
+    if(!pSHQueryRecycleBinA)
+    {
+        skip("SHQueryRecycleBinA does not exist\n");
+        return;
+    }
+    if(!pSHFileOperationA)
+    {
+        skip("SHFileOperationA does not exist\n");
+        return;
+    }
+    GetCurrentDirectoryA(MAX_PATH, buf);
+    strcat(buf,"\\");
+    strcat(buf,name);
+    buf[strlen(buf) + 1] = '\0';
+    hr = pSHQueryRecycleBinA(buf,&info1);
+    ok(hr == S_OK, "SHQueryRecycleBinA failed with error 0x%x\n", hr);
+    ok(info1.i64Size!=0xdeadbeef,"i64Size not set\n");
+    ok(info1.i64NumItems!=0xdeadbeef,"i64NumItems not set\n");
+    /*create and send a file to the recycle bin*/
+    file = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL);
+    ok(file != INVALID_HANDLE_VALUE, "Failure to open file %s\n",name);
+    WriteFile(file,name,strlen(name),&written,NULL);
+    CloseHandle(file);
+    shfo.hwnd = NULL;
+    shfo.wFunc = FO_DELETE;
+    shfo.pFrom = buf;
+    shfo.pTo = NULL;
+    shfo.fFlags = FOF_FILESONLY | FOF_NOCONFIRMATION | FOF_SILENT | FOF_ALLOWUNDO;
+    shfo.hNameMappings = NULL;
+    shfo.lpszProgressTitle = NULL;
+    ok(!pSHFileOperationA(&shfo), "Deletion was not successful\n");
+    hr = pSHQueryRecycleBinA(buf,&info2);
+    ok(hr == S_OK, "SHQueryRecycleBinW failed with error 0x%x\n", hr);
+    if(info2.i64Size!=info1.i64Size || info2.i64NumItems!=info1.i64NumItems) {
+      ok(info2.i64Size==info1.i64Size+written,"Expected recycle bin to have 0x%s bytes\n",str_from_int64(info1.i64Size+written));
+      ok(info2.i64NumItems==info1.i64NumItems+1,"Expected recycle bin to have 0x%s items\n",str_from_int64(info1.i64NumItems+1));
+    } else todo_wine {
+      ok(info2.i64Size==info1.i64Size+written,"Expected recycle bin to have 0x%s bytes\n",str_from_int64(info1.i64Size+written));
+      ok(info2.i64NumItems==info1.i64NumItems+1,"Expected recycle bin to have 0x%s items\n",str_from_int64(info1.i64NumItems+1));
+    }
+}
+
+
+START_TEST(recyclebin)
+{
+    setup_pointers();
+    test_query_recyclebin();
+}
diff --git a/rostests/winetests/shell32/shell32.rbuild b/rostests/winetests/shell32/shell32.rbuild
index 9f9d037be52..a503d9c6225 100644
--- a/rostests/winetests/shell32/shell32.rbuild
+++ b/rostests/winetests/shell32/shell32.rbuild
@@ -17,10 +17,16 @@
 	<library>ntdll</library>
 	<file>appbar.c</file>
 	<file>autocomplete.c</file>
+	<file>brsfolder.c</file>
+	<file>ebrowser.c</file>
 	<file>generated.c</file>
 	<file>progman_dde.c</file>
+	<file>recyclebin.c</file>
+	<file>shelldispatch.c</file>
 	<file>shelllink.c</file>
+	<file>shellole.c</file>
 	<file>shellpath.c</file>
+	<file>shfldr_special.c</file>
 	<file>shlexec.c</file>
 	<file>shlfileop.c</file>
 	<file>shlfolder.c</file>
@@ -28,7 +34,6 @@
 	<file>string.c</file>
 	<file>systray.c</file>
 	<file>testlist.c</file>
-	<file>shfldr_special.c</file>
 	<file>rsrc.rc</file>
 </module>
 </group>
diff --git a/rostests/winetests/shell32/shell32_test.h b/rostests/winetests/shell32/shell32_test.h
index 64a2be1ef62..42a74fb2d5f 100755
--- a/rostests/winetests/shell32/shell32_test.h
+++ b/rostests/winetests/shell32/shell32_test.h
@@ -1,7 +1,7 @@
 /*
  * Unit test suite for shell32 functions
  *
- * Copyright 2005 Francois Gougett for CodeWeavers
+ * Copyright 2005 Francois Gouget for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/rostests/winetests/shell32/shelldispatch.c b/rostests/winetests/shell32/shelldispatch.c
new file mode 100644
index 00000000000..2ccc364a2be
--- /dev/null
+++ b/rostests/winetests/shell32/shelldispatch.c
@@ -0,0 +1,319 @@
+/*
+ * Unit tests for IShellDispatch
+ *
+ * Copyright 2010 Alexander Morozov for Etersoft
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "shldisp.h"
+#include "shlobj.h"
+#include "shlwapi.h"
+#include "wine/test.h"
+
+static HRESULT (WINAPI *pSHGetFolderPathW)(HWND, int, HANDLE, DWORD, LPWSTR);
+static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
+static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
+static DWORD (WINAPI *pGetLongPathNameW)(LPCWSTR, LPWSTR, DWORD);
+
+static void init_function_pointers(void)
+{
+    HMODULE hshell32, hkernel32;
+
+    hshell32 = GetModuleHandleA("shell32.dll");
+    hkernel32 = GetModuleHandleA("kernel32.dll");
+    pSHGetFolderPathW = (void*)GetProcAddress(hshell32, "SHGetFolderPathW");
+    pSHGetNameFromIDList = (void*)GetProcAddress(hshell32, "SHGetNameFromIDList");
+    pSHGetSpecialFolderLocation = (void*)GetProcAddress(hshell32,
+     "SHGetSpecialFolderLocation");
+    pGetLongPathNameW = (void*)GetProcAddress(hkernel32, "GetLongPathNameW");
+}
+
+static void test_namespace(void)
+{
+    static const WCHAR winetestW[] = {'w','i','n','e','t','e','s','t',0};
+    static const WCHAR backslashW[] = {'\\',0};
+    static const WCHAR clsidW[] = {
+        ':',':','{','6','4','5','F','F','0','4','0','-','5','0','8','1','-',
+                    '1','0','1','B','-','9','F','0','8','-',
+                    '0','0','A','A','0','0','2','F','9','5','4','E','}',0};
+
+    static WCHAR tempW[MAX_PATH], curW[MAX_PATH];
+    WCHAR *long_pathW = NULL;
+    HRESULT r;
+    IShellDispatch *sd;
+    Folder *folder;
+    Folder2 *folder2;
+    FolderItem *item;
+    VARIANT var;
+    BSTR title, item_path;
+    int len;
+
+    r = CoCreateInstance(&CLSID_Shell, NULL, CLSCTX_INPROC_SERVER,
+     &IID_IShellDispatch, (LPVOID*)&sd);
+    if (r == REGDB_E_CLASSNOTREG) /* NT4 */
+    {
+        win_skip("skipping IShellDispatch tests\n");
+        return;
+    }
+    ok(SUCCEEDED(r), "CoCreateInstance failed: %08x\n", r);
+    if (FAILED(r))
+        return;
+
+    VariantInit(&var);
+    folder = (void*)0xdeadbeef;
+    r = IShellDispatch_NameSpace(sd, var, &folder);
+    ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
+    ok(folder == NULL, "expected NULL, got %p\n", folder);
+
+    V_VT(&var) = VT_I4;
+    V_I4(&var) = -1;
+    folder = (void*)0xdeadbeef;
+    r = IShellDispatch_NameSpace(sd, var, &folder);
+    todo_wine {
+    ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
+    ok(folder == NULL, "got %p\n", folder);
+}
+    V_VT(&var) = VT_I4;
+    V_I4(&var) = ssfPROGRAMFILES;
+    r = IShellDispatch_NameSpace(sd, var, &folder);
+    ok(r == S_OK ||
+     broken(r == S_FALSE), /* NT4 */
+     "IShellDispatch::NameSpace failed: %08x\n", r);
+    if (r == S_OK)
+    {
+        static WCHAR path[MAX_PATH];
+
+        if (pSHGetFolderPathW)
+        {
+            r = pSHGetFolderPathW(NULL, CSIDL_PROGRAM_FILES, NULL,
+             SHGFP_TYPE_CURRENT, path);
+            ok(r == S_OK, "SHGetFolderPath failed: %08x\n", r);
+        }
+        r = Folder_get_Title(folder, &title);
+        todo_wine
+        ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
+        if (r == S_OK)
+        {
+            /* On Win2000-2003 title is equal to program files directory name in
+               HKLM\Software\Microsoft\Windows\CurrentVersion\ProgramFilesDir.
+               On newer Windows it seems constant and is not changed
+               if the program files directory name is changed */
+            if (pSHGetSpecialFolderLocation && pSHGetNameFromIDList)
+            {
+                LPITEMIDLIST pidl;
+                PWSTR name;
+
+                r = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidl);
+                ok(r == S_OK, "SHGetSpecialFolderLocation failed: %08x\n", r);
+                r = pSHGetNameFromIDList(pidl, SIGDN_NORMALDISPLAY, &name);
+                ok(r == S_OK, "SHGetNameFromIDList failed: %08x\n", r);
+                todo_wine
+                ok(!lstrcmpW(title, name), "expected %s, got %s\n",
+                 wine_dbgstr_w(name), wine_dbgstr_w(title));
+                CoTaskMemFree(name);
+                CoTaskMemFree(pidl);
+            }
+            else if (pSHGetFolderPathW)
+            {
+                WCHAR *p;
+
+                p = path + lstrlenW(path);
+                while (path < p && *(p - 1) != '\\')
+                    p--;
+                ok(!lstrcmpW(title, p), "expected %s, got %s\n",
+                 wine_dbgstr_w(p), wine_dbgstr_w(title));
+            }
+            else skip("skipping Folder::get_Title test\n");
+            SysFreeString(title);
+        }
+        r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
+        ok(r == S_OK, "Folder::QueryInterface failed: %08x\n", r);
+        if (r == S_OK)
+        {
+            r = Folder2_get_Self(folder2, &item);
+            ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
+            if (r == S_OK)
+            {
+                r = FolderItem_get_Path(item, &item_path);
+                ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
+                if (pSHGetFolderPathW)
+                    ok(!lstrcmpW(item_path, path), "expected %s, got %s\n",
+                     wine_dbgstr_w(path), wine_dbgstr_w(item_path));
+                SysFreeString(item_path);
+                FolderItem_Release(item);
+            }
+            Folder2_Release(folder2);
+        }
+        Folder_Release(folder);
+    }
+
+    V_VT(&var) = VT_I4;
+    V_I4(&var) = ssfBITBUCKET;
+    r = IShellDispatch_NameSpace(sd, var, &folder);
+    ok(r == S_OK ||
+     broken(r == S_FALSE), /* NT4 */
+     "IShellDispatch::NameSpace failed: %08x\n", r);
+    if (r == S_OK)
+    {
+        r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
+        ok(r == S_OK ||
+         broken(r == E_NOINTERFACE), /* NT4 */
+         "Folder::QueryInterface failed: %08x\n", r);
+        if (r == S_OK)
+        {
+            r = Folder2_get_Self(folder2, &item);
+            ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
+            if (r == S_OK)
+            {
+                r = FolderItem_get_Path(item, &item_path);
+                todo_wine
+                ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
+                todo_wine
+                ok(!lstrcmpW(item_path, clsidW), "expected %s, got %s\n",
+                 wine_dbgstr_w(clsidW), wine_dbgstr_w(item_path));
+                SysFreeString(item_path);
+                FolderItem_Release(item);
+            }
+            Folder2_Release(folder2);
+        }
+        Folder_Release(folder);
+    }
+
+    GetTempPathW(MAX_PATH, tempW);
+    GetCurrentDirectoryW(MAX_PATH, curW);
+    SetCurrentDirectoryW(tempW);
+    CreateDirectoryW(winetestW, NULL);
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(winetestW);
+    r = IShellDispatch_NameSpace(sd, var, &folder);
+    ok(r == S_FALSE, "expected S_FALSE, got %08x\n", r);
+    SysFreeString(V_BSTR(&var));
+
+    GetFullPathNameW(winetestW, MAX_PATH, tempW, NULL);
+    if (pGetLongPathNameW)
+    {
+        len = pGetLongPathNameW(tempW, NULL, 0);
+        long_pathW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (long_pathW)
+            pGetLongPathNameW(tempW, long_pathW, len);
+    }
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(tempW);
+    r = IShellDispatch_NameSpace(sd, var, &folder);
+    ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
+    if (r == S_OK)
+    {
+        r = Folder_get_Title(folder, &title);
+        ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
+        if (r == S_OK)
+        {
+            ok(!lstrcmpW(title, winetestW), "bad title: %s\n",
+             wine_dbgstr_w(title));
+            SysFreeString(title);
+        }
+        r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
+        ok(r == S_OK ||
+         broken(r == E_NOINTERFACE), /* NT4 */
+         "Folder::QueryInterface failed: %08x\n", r);
+        if (r == S_OK)
+        {
+            r = Folder2_get_Self(folder2, &item);
+            ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
+            if (r == S_OK)
+            {
+                r = FolderItem_get_Path(item, &item_path);
+                ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
+                if (long_pathW)
+                    ok(!lstrcmpW(item_path, long_pathW),
+                     "expected %s, got %s\n", wine_dbgstr_w(long_pathW),
+                     wine_dbgstr_w(item_path));
+                SysFreeString(item_path);
+                FolderItem_Release(item);
+            }
+            Folder2_Release(folder2);
+        }
+        Folder_Release(folder);
+    }
+    SysFreeString(V_BSTR(&var));
+
+    len = lstrlenW(tempW);
+    if (len < MAX_PATH - 1)
+    {
+        lstrcatW(tempW, backslashW);
+        V_VT(&var) = VT_BSTR;
+        V_BSTR(&var) = SysAllocString(tempW);
+        r = IShellDispatch_NameSpace(sd, var, &folder);
+        ok(r == S_OK, "IShellDispatch::NameSpace failed: %08x\n", r);
+        if (r == S_OK)
+        {
+            r = Folder_get_Title(folder, &title);
+            ok(r == S_OK, "Folder::get_Title failed: %08x\n", r);
+            if (r == S_OK)
+            {
+                ok(!lstrcmpW(title, winetestW), "bad title: %s\n",
+                 wine_dbgstr_w(title));
+                SysFreeString(title);
+            }
+            r = Folder_QueryInterface(folder, &IID_Folder2, (LPVOID*)&folder2);
+            ok(r == S_OK ||
+             broken(r == E_NOINTERFACE), /* NT4 */
+             "Folder::QueryInterface failed: %08x\n", r);
+            if (r == S_OK)
+            {
+                r = Folder2_get_Self(folder2, &item);
+                ok(r == S_OK, "Folder::get_Self failed: %08x\n", r);
+                if (r == S_OK)
+                {
+                    r = FolderItem_get_Path(item, &item_path);
+                    ok(r == S_OK, "FolderItem::get_Path failed: %08x\n", r);
+                    if (long_pathW)
+                        ok(!lstrcmpW(item_path, long_pathW),
+                         "expected %s, got %s\n", wine_dbgstr_w(long_pathW),
+                         wine_dbgstr_w(item_path));
+                    SysFreeString(item_path);
+                    FolderItem_Release(item);
+                }
+                Folder2_Release(folder2);
+            }
+            Folder_Release(folder);
+        }
+        SysFreeString(V_BSTR(&var));
+    }
+
+    HeapFree(GetProcessHeap(), 0, long_pathW);
+    RemoveDirectoryW(winetestW);
+    SetCurrentDirectoryW(curW);
+    IShellDispatch_Release(sd);
+}
+
+START_TEST(shelldispatch)
+{
+    HRESULT r;
+
+    r = CoInitialize(NULL);
+    ok(SUCCEEDED(r), "CoInitialize failed: %08x\n", r);
+    if (FAILED(r))
+        return;
+
+    init_function_pointers();
+    test_namespace();
+
+    CoUninitialize();
+}
diff --git a/rostests/winetests/shell32/shelllink.c b/rostests/winetests/shell32/shelllink.c
index 1b38b0dc82a..d28cff0ac27 100755
--- a/rostests/winetests/shell32/shelllink.c
+++ b/rostests/winetests/shell32/shelllink.c
@@ -168,15 +168,15 @@ static void test_get_set(void)
 
     CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
                      &IID_IShellLinkW, (LPVOID*)&slW);
-    if (!slW)
-        skip("SetPath with NULL parameter crashes on Win9x\n");
+    if (!slW /* Win9x */ || !pGetLongPathNameA /* NT4 */)
+        skip("SetPath with NULL parameter crashes on Win9x and some NT4\n");
     else
     {
         IShellLinkW_Release(slW);
         r = IShellLinkA_SetPath(sl, NULL);
         ok(r==E_INVALIDARG ||
            broken(r==S_OK), /* Some Win95 and NT4 */
-           "SetPath failed (0x%08x)\n", r);
+           "SetPath returned wrong error (0x%08x)\n", r);
     }
 
     r = IShellLinkA_SetPath(sl, "");
@@ -204,16 +204,14 @@ static void test_get_set(void)
     /* Test the interaction of SetPath and SetIDList */
     tmp_pidl=NULL;
     r = IShellLinkA_GetIDList(sl, &tmp_pidl);
-    todo_wine ok(r == S_OK, "GetIDList failed (0x%08x)\n", r);
+    ok(r == S_OK, "GetIDList failed (0x%08x)\n", r);
     if (r == S_OK)
     {
         BOOL ret;
 
         strcpy(buffer,"garbage");
         ret = SHGetPathFromIDListA(tmp_pidl, buffer);
-        todo_wine {
         ok(ret, "SHGetPathFromIDListA failed\n");
-        }
         if (ret)
             ok(lstrcmpi(buffer,str)==0, "GetIDList returned '%s'\n", buffer);
         pILFree(tmp_pidl);
@@ -326,9 +324,7 @@ static void test_get_set(void)
     i=0xdeadbeef;
     strcpy(buffer,"garbage");
     r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
-    todo_wine {
     ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
-    }
     ok(*buffer=='\0', "GetIconLocation returned '%s'\n", buffer);
     ok(i==0, "GetIconLocation returned %d\n", i);
 
@@ -435,7 +431,7 @@ void create_lnk_(int line, const WCHAR* path, lnk_desc_t* desc, int save_fails)
     if (0)
     {
         /* crashes on XP */
-        r = IPersistFile_GetCurFile(pf, NULL);
+        IPersistFile_GetCurFile(pf, NULL);
     }
 
         /* test GetCurFile before ::Save */
@@ -685,6 +681,24 @@ static void test_load_save(void)
     create_lnk(lnkfile, &desc, 0);
     check_lnk(lnkfile, &desc, 0x0);
 
+    /* Test omitting .exe from an absolute path */
+    p=strrchr(realpath, '.');
+    if (p)
+        *p='\0';
+
+    desc.description="absolute path without .exe";
+    desc.workdir=mydir;
+    desc.path=realpath;
+    desc.pidl=NULL;
+    desc.arguments="/option1 /option2 \"Some string\"";
+    desc.showcmd=SW_SHOWNORMAL;
+    desc.icon=mypath;
+    desc.icon_id=0;
+    desc.hotkey=0x1234;
+    create_lnk(lnkfile, &desc, 0);
+    strcat(realpath, ".exe");
+    check_lnk(lnkfile, &desc, 0x4);
+
     /* Overwrite the existing lnk file and test link to a command on the path */
     desc.description="command on path";
     desc.workdir=mypath;
@@ -701,6 +715,22 @@ static void test_load_save(void)
     desc.path=realpath;
     check_lnk(lnkfile, &desc, 0x0);
 
+    /* Test omitting .exe from a command on the path */
+    desc.description="command on path without .exe";
+    desc.workdir=mypath;
+    desc.path="rundll32";
+    desc.pidl=NULL;
+    desc.arguments="/option1 /option2 \"Some string\"";
+    desc.showcmd=SW_SHOWNORMAL;
+    desc.icon=mypath;
+    desc.icon_id=0;
+    desc.hotkey=0x1234;
+    create_lnk(lnkfile, &desc, 0);
+    /* Check that link is created to proper location */
+    SearchPathA( NULL, "rundll32", NULL, MAX_PATH, realpath, NULL);
+    desc.path=realpath;
+    check_lnk(lnkfile, &desc, 0x4);
+
     /* Create a temporary non-executable file */
     r=GetTempPath(sizeof(mypath), mypath);
     ok(r<sizeof(mypath), "GetTempPath failed (%d), err %d\n", r, GetLastError());
@@ -730,6 +760,8 @@ static void test_load_save(void)
     check_lnk(lnkfile, &desc, 0x0);
 
     r=pGetShortPathNameA(mydir, mypath, sizeof(mypath));
+    ok(r<sizeof(mypath), "GetShortPathName failed (%d), err %d\n", r, GetLastError());
+
     strcpy(realpath, mypath);
     strcat(realpath, "\\test.txt");
     strcat(mypath, "\\\\test.txt");
@@ -751,6 +783,36 @@ static void test_load_save(void)
     r = DeleteFileA(mypath);
     ok(r, "failed to delete file %s (%d)\n", mypath, GetLastError());
 
+    /* Create a temporary .bat file */
+    strcpy(mypath, mydir);
+    strcat(mypath, "\\test.bat");
+    hf = CreateFile(mypath, GENERIC_WRITE, 0, NULL,
+                    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    CloseHandle(hf);
+
+    strcpy(realpath, mypath);
+
+    p=strrchr(mypath, '.');
+    if (p)
+        *p='\0';
+
+    /* Try linking to the .bat file without the extension */
+    desc.description="batch file";
+    desc.workdir=mydir;
+    desc.path=mypath;
+    desc.pidl=NULL;
+    desc.arguments="";
+    desc.showcmd=SW_SHOWNORMAL;
+    desc.icon=mypath;
+    desc.icon_id=0;
+    desc.hotkey=0x1234;
+    create_lnk(lnkfile, &desc, 0);
+    desc.path = realpath;
+    check_lnk(lnkfile, &desc, 0x4);
+
+    r = DeleteFileA(realpath);
+    ok(r, "failed to delete file %s (%d)\n", realpath, GetLastError());
+
     /* FIXME: Also test saving a .lnk pointing to a pidl that cannot be
      * represented as a path.
      */
@@ -812,16 +874,21 @@ static void test_datalink(void)
     ok( r == E_FAIL, "CopyDataBlock failed\n");
     ok( dar == NULL, "should be null\n");
 
-    r = IShellLinkW_SetPath(sl, NULL);
-    ok(r == E_INVALIDARG, "set path failed\n");
+    if (!pGetLongPathNameA /* NT4 */)
+        skip("SetPath with NULL parameter crashes on NT4\n");
+    else
+    {
+        r = IShellLinkW_SetPath(sl, NULL);
+        ok(r == E_INVALIDARG, "SetPath returned wrong error (0x%08x)\n", r);
+    }
 
     r = IShellLinkW_SetPath(sl, lnk);
-    ok(r == S_OK, "set path failed\n");
+    ok(r == S_OK, "SetPath failed\n");
 
 if (0)
 {
     /* the following crashes */
-    r = IShellLinkDataList_GetFlags( dl, NULL );
+    IShellLinkDataList_GetFlags( dl, NULL );
 }
 
     flags = 0;
@@ -872,6 +939,66 @@ static void test_shdefextracticon(void)
     ok(SUCCEEDED(res), "SHDefExtractIconA failed, res=%x\n", res);
 }
 
+static void test_GetIconLocation(void)
+{
+    IShellLinkA *sl;
+    const char *str;
+    char buffer[INFOTIPSIZE], mypath[MAX_PATH];
+    int i;
+    HRESULT r;
+    LPITEMIDLIST pidl;
+
+    r = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+            &IID_IShellLinkA, (LPVOID*)&sl);
+    ok(r == S_OK, "no IID_IShellLinkA (0x%08x)\n", r);
+    if(r != S_OK)
+        return;
+
+    i = 0xdeadbeef;
+    strcpy(buffer, "garbage");
+    r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+    ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
+    ok(*buffer == '\0', "GetIconLocation returned '%s'\n", buffer);
+    ok(i == 0, "GetIconLocation returned %d\n", i);
+
+    str = "c:\\some\\path";
+    r = IShellLinkA_SetPath(sl, str);
+    ok(r == S_FALSE || r == S_OK, "SetPath failed (0x%08x)\n", r);
+
+    i = 0xdeadbeef;
+    strcpy(buffer, "garbage");
+    r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+    ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
+    ok(*buffer == '\0', "GetIconLocation returned '%s'\n", buffer);
+    ok(i == 0, "GetIconLocation returned %d\n", i);
+
+    GetWindowsDirectoryA(mypath, sizeof(mypath) - 12);
+    strcat(mypath, "\\regedit.exe");
+    pidl = path_to_pidl(mypath);
+    r = IShellLinkA_SetIDList(sl, pidl);
+    ok(r == S_OK, "SetPath failed (0x%08x)\n", r);
+    pILFree(pidl);
+
+    i = 0xdeadbeef;
+    strcpy(buffer, "garbage");
+    r = IShellLinkA_GetIconLocation(sl, buffer, sizeof(buffer), &i);
+    ok(r == S_OK, "GetIconLocation failed (0x%08x)\n", r);
+    ok(*buffer == '\0', "GetIconLocation returned '%s'\n", buffer);
+    ok(i == 0, "GetIconLocation returned %d\n", i);
+
+    str = "c:\\nonexistent\\file";
+    r = IShellLinkA_SetIconLocation(sl, str, 0xbabecafe);
+    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(lstrcmpi(buffer,str) == 0, "GetIconLocation returned '%s'\n", buffer);
+    ok(i == 0xbabecafe, "GetIconLocation returned %d'\n", i);
+
+    IShellLinkA_Release(sl);
+}
+
 START_TEST(shelllink)
 {
     HRESULT r;
@@ -895,6 +1022,7 @@ START_TEST(shelllink)
     test_load_save();
     test_datalink();
     test_shdefextracticon();
+    test_GetIconLocation();
 
     CoUninitialize();
 }
diff --git a/rostests/winetests/shell32/shellole.c b/rostests/winetests/shell32/shellole.c
new file mode 100644
index 00000000000..da1f667932e
--- /dev/null
+++ b/rostests/winetests/shell32/shellole.c
@@ -0,0 +1,437 @@
+/*
+ * Copyright 2010 Piotr Caban for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+#define CONST_VTABLE
+#define NONAMELESSUNION
+
+#include <stdio.h>
+#include <wine/test.h>
+
+#include "winbase.h"
+#include "shlobj.h"
+#include "initguid.h"
+
+DEFINE_GUID(FMTID_Test,0x12345678,0x1234,0x1234,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12);
+DEFINE_GUID(FMTID_NotExisting, 0x12345678,0x1234,0x1234,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x13);
+
+#define DEFINE_EXPECT(func) \
+    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+
+#define SET_EXPECT(func) \
+    expect_ ## func = TRUE
+
+#define CHECK_EXPECT2(func) \
+    do { \
+        ok(expect_ ##func, "unexpected call " #func "\n"); \
+        called_ ## func = TRUE; \
+    }while(0)
+
+#define CHECK_EXPECT(func) \
+    do { \
+        CHECK_EXPECT2(func); \
+        expect_ ## func = FALSE; \
+    }while(0)
+
+#define CHECK_CALLED(func) \
+    do { \
+        ok(called_ ## func, "expected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
+DEFINE_EXPECT(Create);
+DEFINE_EXPECT(Delete);
+DEFINE_EXPECT(Open);
+DEFINE_EXPECT(ReadMultiple);
+DEFINE_EXPECT(ReadMultipleCodePage);
+DEFINE_EXPECT(Release);
+DEFINE_EXPECT(Stat);
+DEFINE_EXPECT(WriteMultiple);
+
+static HRESULT (WINAPI *pSHPropStgCreate)(IPropertySetStorage*, REFFMTID, const CLSID*,
+        DWORD, DWORD, DWORD, IPropertyStorage**, UINT*);
+static HRESULT (WINAPI *pSHPropStgReadMultiple)(IPropertyStorage*, UINT,
+        ULONG, const PROPSPEC*, PROPVARIANT*);
+static HRESULT (WINAPI *pSHPropStgWriteMultiple)(IPropertyStorage*, UINT*,
+        ULONG, const PROPSPEC*, PROPVARIANT*, PROPID);
+
+static void init(void)
+{
+    HMODULE hmod = GetModuleHandleA("shell32.dll");
+
+    pSHPropStgCreate = (void*)GetProcAddress(hmod, "SHPropStgCreate");
+    pSHPropStgReadMultiple = (void*)GetProcAddress(hmod, "SHPropStgReadMultiple");
+    pSHPropStgWriteMultiple = (void*)GetProcAddress(hmod, "SHPropStgWriteMultiple");
+}
+
+static HRESULT WINAPI PropertyStorage_QueryInterface(IPropertyStorage *This,
+        REFIID riid, void **ppvObject)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static ULONG WINAPI PropertyStorage_AddRef(IPropertyStorage *This)
+{
+    ok(0, "unexpected call\n");
+    return 2;
+}
+
+static ULONG WINAPI PropertyStorage_Release(IPropertyStorage *This)
+{
+    CHECK_EXPECT(Release);
+    return 1;
+}
+
+static HRESULT WINAPI PropertyStorage_ReadMultiple(IPropertyStorage *This, ULONG cpspec,
+        const PROPSPEC *rgpspec, PROPVARIANT *rgpropvar)
+{
+    if(cpspec == 1) {
+        CHECK_EXPECT(ReadMultipleCodePage);
+
+        ok(rgpspec != NULL, "rgpspec = NULL\n");
+        ok(rgpropvar != NULL, "rgpropvar = NULL\n");
+
+        ok(rgpspec[0].ulKind == PRSPEC_PROPID, "rgpspec[0].ulKind = %d\n", rgpspec[0].ulKind);
+        ok(rgpspec[0].u.propid == PID_CODEPAGE, "rgpspec[0].propid = %d\n", rgpspec[0].u.propid);
+
+        rgpropvar[0].vt = VT_I2;
+        rgpropvar[0].u.iVal = 1234;
+    } else {
+        CHECK_EXPECT(ReadMultiple);
+
+        ok(cpspec == 10, "cpspec = %u\n", cpspec);
+        ok(rgpspec == (void*)0xdeadbeef, "rgpspec = %p\n", rgpspec);
+        ok(rgpropvar != NULL, "rgpropvar = NULL\n");
+
+        ok(rgpropvar[0].vt==0 || broken(rgpropvar[0].vt==VT_BSTR), "rgpropvar[0].vt = %d\n", rgpropvar[0].vt);
+
+        rgpropvar[0].vt = VT_BSTR;
+        rgpropvar[0].u.bstrVal = (void*)0xdeadbeef;
+        rgpropvar[1].vt = VT_LPSTR;
+        rgpropvar[1].u.pszVal = (void*)0xdeadbeef;
+        rgpropvar[2].vt = VT_BYREF|VT_I1;
+        rgpropvar[2].u.pcVal = (void*)0xdeadbeef;
+        rgpropvar[3].vt = VT_BYREF|VT_VARIANT;
+        rgpropvar[3].u.pvarVal = (void*)0xdeadbeef;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PropertyStorage_WriteMultiple(IPropertyStorage *This, ULONG cpspec,
+        const PROPSPEC *rgpspec, const PROPVARIANT *rgpropvar,
+        PROPID propidNameFirst)
+{
+    CHECK_EXPECT(WriteMultiple);
+
+    ok(cpspec == 20, "cpspec = %d\n", cpspec);
+    ok(rgpspec == (void*)0xdeadbeef, "rgpspec = %p\n", rgpspec);
+    ok(rgpropvar == (void*)0xdeadbeef, "rgpropvar = %p\n", rgpspec);
+    ok(propidNameFirst == PID_FIRST_USABLE, "propidNameFirst = %d\n", propidNameFirst);
+    return S_OK;
+}
+
+static HRESULT WINAPI PropertyStorage_DeleteMultiple(IPropertyStorage *This, ULONG cpspec,
+        const PROPSPEC *rgpspec)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_ReadPropertyNames(IPropertyStorage *This, ULONG cpropid,
+        const PROPID *rgpropid, LPOLESTR *rglpwstrName)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_WritePropertyNames(IPropertyStorage *This, ULONG cpropid,
+        const PROPID *rgpropid, const LPOLESTR *rglpwstrName)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_DeletePropertyNames(IPropertyStorage *This, ULONG cpropid,
+        const PROPID *rgpropid)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_Commit(IPropertyStorage *This, DWORD grfCommitFlags)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_Revert(IPropertyStorage *This)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_Enum(IPropertyStorage *This, IEnumSTATPROPSTG **ppenum)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_SetTimes(IPropertyStorage *This, const FILETIME *pctime,
+        const FILETIME *patime, const FILETIME *pmtime)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_SetClass(IPropertyStorage *This, REFCLSID clsid)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PropertyStorage_Stat(IPropertyStorage *This, STATPROPSETSTG *statpsstg)
+{
+    CHECK_EXPECT(Stat);
+
+    memset(statpsstg, 0, sizeof(STATPROPSETSTG));
+    memcpy(&statpsstg->fmtid, &FMTID_Test, sizeof(FMTID));
+    statpsstg->grfFlags = PROPSETFLAG_ANSI;
+    return S_OK;
+}
+
+static IPropertyStorageVtbl PropertyStorageVtbl = {
+    PropertyStorage_QueryInterface,
+    PropertyStorage_AddRef,
+    PropertyStorage_Release,
+    PropertyStorage_ReadMultiple,
+    PropertyStorage_WriteMultiple,
+    PropertyStorage_DeleteMultiple,
+    PropertyStorage_ReadPropertyNames,
+    PropertyStorage_WritePropertyNames,
+    PropertyStorage_DeletePropertyNames,
+    PropertyStorage_Commit,
+    PropertyStorage_Revert,
+    PropertyStorage_Enum,
+    PropertyStorage_SetTimes,
+    PropertyStorage_SetClass,
+    PropertyStorage_Stat
+};
+
+static IPropertyStorage PropertyStorage = { &PropertyStorageVtbl };
+
+static HRESULT WINAPI PropertySetStorage_QueryInterface(IPropertySetStorage *This,
+        REFIID riid, void **ppvObject)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static ULONG WINAPI PropertySetStorage_AddRef(IPropertySetStorage *This)
+{
+    ok(0, "unexpected call\n");
+    return 2;
+}
+
+static ULONG WINAPI PropertySetStorage_Release(IPropertySetStorage *This)
+{
+    ok(0, "unexpected call\n");
+    return 1;
+}
+
+static HRESULT WINAPI PropertySetStorage_Create(IPropertySetStorage *This,
+        REFFMTID rfmtid, const CLSID *pclsid, DWORD grfFlags,
+        DWORD grfMode, IPropertyStorage **ppprstg)
+{
+    CHECK_EXPECT(Create);
+    ok(IsEqualGUID(rfmtid, &FMTID_Test) || IsEqualGUID(rfmtid, &FMTID_NotExisting),
+            "Incorrect rfmtid value\n");
+    ok(pclsid == NULL, "pclsid != NULL\n");
+    ok(grfFlags == PROPSETFLAG_ANSI, "grfFlags = %x\n", grfFlags);
+    ok(grfMode == STGM_READ, "grfMode = %x\n", grfMode);
+
+    *ppprstg = &PropertyStorage;
+    return S_OK;
+}
+
+static HRESULT WINAPI PropertySetStorage_Open(IPropertySetStorage *This,
+        REFFMTID rfmtid, DWORD grfMode, IPropertyStorage **ppprstg)
+{
+    CHECK_EXPECT(Open);
+
+    if(IsEqualGUID(rfmtid, &FMTID_Test)) {
+        ok(grfMode == STGM_READ, "grfMode = %x\n", grfMode);
+
+        *ppprstg = &PropertyStorage;
+        return S_OK;
+    }
+
+    return STG_E_FILENOTFOUND;
+}
+
+static HRESULT WINAPI PropertySetStorage_Delete(IPropertySetStorage *This,
+        REFFMTID rfmtid)
+{
+    CHECK_EXPECT(Delete);
+    ok(IsEqualGUID(rfmtid, &FMTID_Test), "wrong rfmtid value\n");
+    return S_OK;
+}
+
+static HRESULT WINAPI PropertySetStorage_Enum(IPropertySetStorage *This,
+        IEnumSTATPROPSETSTG **ppenum)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static IPropertySetStorageVtbl PropertySetStorageVtbl = {
+    PropertySetStorage_QueryInterface,
+    PropertySetStorage_AddRef,
+    PropertySetStorage_Release,
+    PropertySetStorage_Create,
+    PropertySetStorage_Open,
+    PropertySetStorage_Delete,
+    PropertySetStorage_Enum
+};
+
+static IPropertySetStorage PropertySetStorage = { &PropertySetStorageVtbl };
+
+static void test_SHPropStg_functions(void)
+{
+    IPropertyStorage *property_storage;
+    UINT codepage;
+    PROPVARIANT read[10];
+    HRESULT hres;
+
+    if(!pSHPropStgCreate || !pSHPropStgReadMultiple || !pSHPropStgWriteMultiple) {
+        win_skip("SHPropStg* functions are missing\n");
+        return;
+    }
+
+    if(0) {
+        /* Crashes on Windows */
+        pSHPropStgCreate(NULL, &FMTID_Test, NULL, PROPSETFLAG_DEFAULT,
+                STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
+        pSHPropStgCreate(&PropertySetStorage, NULL, NULL, PROPSETFLAG_DEFAULT,
+                STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
+        pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, NULL, PROPSETFLAG_DEFAULT,
+                STGM_READ, OPEN_EXISTING, NULL, &codepage);
+    }
+
+    SET_EXPECT(Open);
+    SET_EXPECT(ReadMultipleCodePage);
+    hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, NULL, PROPSETFLAG_DEFAULT,
+            STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
+    ok(codepage == 1234, "codepage = %d\n", codepage);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    CHECK_CALLED(Open);
+    CHECK_CALLED(ReadMultipleCodePage);
+
+    SET_EXPECT(Open);
+    hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_NotExisting, NULL,
+            PROPSETFLAG_DEFAULT, STGM_READ, OPEN_EXISTING, &property_storage, &codepage);
+    ok(hres == STG_E_FILENOTFOUND, "hres = %x\n", hres);
+    CHECK_CALLED(Open);
+
+    SET_EXPECT(Open);
+    SET_EXPECT(Release);
+    SET_EXPECT(Delete);
+    SET_EXPECT(Create);
+    SET_EXPECT(ReadMultipleCodePage);
+    hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, NULL, PROPSETFLAG_ANSI,
+            STGM_READ, CREATE_ALWAYS, &property_storage, &codepage);
+    ok(codepage == 1234, "codepage = %d\n", codepage);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    CHECK_CALLED(Open);
+    CHECK_CALLED(Release);
+    CHECK_CALLED(Delete);
+    CHECK_CALLED(Create);
+    CHECK_CALLED(ReadMultipleCodePage);
+
+    SET_EXPECT(Open);
+    SET_EXPECT(Create);
+    SET_EXPECT(ReadMultipleCodePage);
+    hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_NotExisting, NULL, PROPSETFLAG_ANSI,
+            STGM_READ, CREATE_ALWAYS, &property_storage, &codepage);
+    ok(codepage == 1234, "codepage = %d\n", codepage);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    CHECK_CALLED(Open);
+    CHECK_CALLED(Create);
+    CHECK_CALLED(ReadMultipleCodePage);
+
+    SET_EXPECT(Open);
+    hres = pSHPropStgCreate(&PropertySetStorage, &FMTID_Test, &FMTID_NotExisting,
+            PROPSETFLAG_DEFAULT, STGM_READ, OPEN_EXISTING, &property_storage, NULL);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    CHECK_CALLED(Open);
+
+    SET_EXPECT(Stat);
+    SET_EXPECT(ReadMultipleCodePage);
+    SET_EXPECT(WriteMultiple);
+    codepage = 0;
+    hres = pSHPropStgWriteMultiple(property_storage, &codepage, 20, (void*)0xdeadbeef, (void*)0xdeadbeef, PID_FIRST_USABLE);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    ok(codepage == 1234, "codepage = %d\n", codepage);
+    CHECK_CALLED(Stat);
+    CHECK_CALLED(ReadMultipleCodePage);
+    CHECK_CALLED(WriteMultiple);
+
+    SET_EXPECT(Stat);
+    SET_EXPECT(ReadMultipleCodePage);
+    SET_EXPECT(WriteMultiple);
+    hres = pSHPropStgWriteMultiple(property_storage, NULL, 20, (void*)0xdeadbeef, (void*)0xdeadbeef, PID_FIRST_USABLE);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    CHECK_CALLED(Stat);
+    CHECK_CALLED(ReadMultipleCodePage);
+    CHECK_CALLED(WriteMultiple);
+
+    SET_EXPECT(Stat);
+    SET_EXPECT(WriteMultiple);
+    codepage = 1000;
+    hres = pSHPropStgWriteMultiple(property_storage, &codepage, 20, (void*)0xdeadbeef, (void*)0xdeadbeef, PID_FIRST_USABLE);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    ok(codepage == 1000, "codepage = %d\n", codepage);
+    CHECK_CALLED(Stat);
+    CHECK_CALLED(WriteMultiple);
+
+    read[0].vt = VT_BSTR;
+    read[0].u.bstrVal = (void*)0xdeadbeef;
+    SET_EXPECT(ReadMultiple);
+    SET_EXPECT(ReadMultipleCodePage);
+    SET_EXPECT(Stat);
+    hres = pSHPropStgReadMultiple(property_storage, 0, 10, (void*)0xdeadbeef, read);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    CHECK_CALLED(ReadMultiple);
+    CHECK_CALLED(ReadMultipleCodePage);
+    CHECK_CALLED(Stat);
+
+    SET_EXPECT(ReadMultiple);
+    SET_EXPECT(Stat);
+    hres = pSHPropStgReadMultiple(property_storage, 1251, 10, (void*)0xdeadbeef, read);
+    ok(hres == S_OK, "hres = %x\n", hres);
+    CHECK_CALLED(ReadMultiple);
+    CHECK_CALLED(Stat);
+}
+
+START_TEST(shellole)
+{
+    init();
+
+    test_SHPropStg_functions();
+}
diff --git a/rostests/winetests/shell32/shellpath.c b/rostests/winetests/shell32/shellpath.c
index b874b5a1ee4..0db72dfc15e 100644
--- a/rostests/winetests/shell32/shellpath.c
+++ b/rostests/winetests/shell32/shellpath.c
@@ -31,6 +31,7 @@
 #include "shlobj.h"
 #include "shlwapi.h"
 #include "initguid.h"
+#include "knownfolders.h"
 #include "wine/test.h"
 
 /* CSIDL_MYDOCUMENTS is now the same as CSIDL_PERSONAL, but what we want
@@ -38,6 +39,8 @@
  */
 #define OLD_CSIDL_MYDOCUMENTS  0x000c
 
+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
@@ -93,6 +96,10 @@ static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
 static int (WINAPI *pSHFileOperationA)(LPSHFILEOPSTRUCTA);
 static HRESULT (WINAPI *pSHGetMalloc)(LPMALLOC *);
 static UINT (WINAPI *pGetSystemWow64DirectoryA)(LPSTR,UINT);
+static HRESULT (WINAPI *pSHGetKnownFolderPath)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *);
+static HRESULT (WINAPI *pSHSetKnownFolderPath)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR);
+static HRESULT (WINAPI *pSHGetFolderPathEx)(REFKNOWNFOLDERID, DWORD, HANDLE, LPWSTR, DWORD);
+
 static DLLVERSIONINFO shellVersion = { 0 };
 static LPMALLOC pMalloc;
 static const BYTE guidType[] = { PT_GUID };
@@ -187,7 +194,10 @@ static void loadShell32(void)
 
     GET_PROC(DllGetVersion)
     GET_PROC(SHGetFolderPathA)
+    GET_PROC(SHGetFolderPathEx)
     GET_PROC(SHGetFolderLocation)
+    GET_PROC(SHGetKnownFolderPath)
+    GET_PROC(SHSetKnownFolderPath)
     GET_PROC(SHGetSpecialFolderPathA)
     GET_PROC(SHGetSpecialFolderLocation)
     GET_PROC(ILFindLastID)
@@ -352,7 +362,7 @@ static void test_parameters(void)
         BOOL ret;
 
         if (0)
-           ret = pSHGetSpecialFolderPathA(NULL, NULL, CSIDL_BITBUCKET, FALSE);
+           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.
@@ -833,6 +843,1651 @@ static void test_NonExistentPath(void)
     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);
+}
+    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 == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER), "expected 0x8007007a, 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 CSIDL_TODO_WINE 0x20000
+#define KNOWN_FOLDER(id, csidl, name, category, parent, relative_path, parsing_name, attributes, definitionFlags) \
+    { &id, # id, csidl, # csidl, name, category, &parent, # parent, 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 *fidParent;
+    const char *sParent;
+    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.
+ */
+static const struct knownFolderDef known_folders[] = {
+    KNOWN_FOLDER(FOLDERID_AddNewPrograms,
+                 NO_CSIDL,
+                 "AddNewProgramsFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{15eae92e-f17a-4431-9f28-805e482dafd4}\0"
+                "shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{15eae92e-f17a-4431-9f28-805e482dafd4}\0\0" /* 6.1 */,
+                0,
+                0),
+    KNOWN_FOLDER(FOLDERID_AdminTools,
+                 CSIDL_ADMINTOOLS,
+                 "Administrative Tools",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Programs,
+                 "Administrative Tools",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_AppUpdates,
+                 NO_CSIDL,
+                 "AppUpdatesFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\\::{d450a8a1-9568-45c7-9c0e-b4f9fb4537bd}\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\\::{d450a8a1-9568-45c7-9c0e-b4f9fb4537bd}\0\0" /* 6.1 */,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_CDBurning,
+                 CSIDL_CDBURN_AREA,
+                 "CD Burning",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Microsoft\\Windows\\Burn\\Burn",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_LOCAL_REDIRECT_ONLY),
+    KNOWN_FOLDER(FOLDERID_ChangeRemovePrograms,
+                 NO_CSIDL,
+                 "ChangeRemoveProgramsFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{7b81be6a-ce2b-4676-a29e-eb907a5126c5}\0\0" /* 6.1 */,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_CommonAdminTools,
+                 CSIDL_COMMON_ADMINTOOLS,
+                 "Common Administrative Tools",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_CommonPrograms,
+                 "Administrative Tools",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_CommonOEMLinks,
+                 CSIDL_COMMON_OEM_LINKS,"OEM Links",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_ProgramData,
+                 "OEM Links",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_CommonPrograms,
+                 CSIDL_COMMON_PROGRAMS,
+                 "Common Programs",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_CommonStartMenu,
+                 "Programs",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_CommonStartMenu,
+                 CSIDL_COMMON_STARTMENU,
+                 "Common Start Menu",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_ProgramData,
+                 "Microsoft\\Windows\\Start Menu",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_CommonStartup,
+                 CSIDL_COMMON_STARTUP,
+                 "Common Startup",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_CommonPrograms,
+                 "StartUp",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_CommonTemplates,
+                 CSIDL_COMMON_TEMPLATES,
+                 "Common Templates",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_ProgramData,
+                 "Microsoft\\Windows\\Templates",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ComputerFolder,
+                 CSIDL_DRIVES,
+                 "MyComputerFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ConflictFolder,
+                 NO_CSIDL,
+                 "ConflictFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{E413D040-6788-4C22-957E-175D1C513A34},\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{E413D040-6788-4C22-957E-175D1C513A34},\0\0" /* 6.1 */,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ConnectionsFolder,
+                 CSIDL_CONNECTIONS,
+                 "ConnectionsFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{7007ACC7-3202-11D1-AAD2-00805FC1270E}\0\0" /* 6.1 */,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Contacts,
+                 NO_CSIDL,
+                 "Contacts",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Contacts",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{56784854-C6CB-462B-8169-88E350ACB882}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_ControlPanelFolder,
+                 CSIDL_CONTROLS,
+                 "ControlPanelFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\0\0" /* 6.1 */,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Cookies,
+                 CSIDL_COOKIES,
+                 "Cookies",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\Cookies",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Desktop,
+                 CSIDL_DESKTOP,
+                 "Desktop",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Desktop",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_DeviceMetadataStore,
+                 NO_CSIDL,
+                 "Device Metadata Store",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_ProgramData,
+                 "Microsoft\\Windows\\DeviceMetadataStore",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Documents,
+                 CSIDL_MYDOCUMENTS,
+                 "Personal",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Documents",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{FDD39AD0-238F-46AF-ADB4-6C85480369C7}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_DocumentsLibrary,
+                 NO_CSIDL,
+                 "DocumentsLibrary",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Libraries,
+                 "Documents.library-ms",
+                 "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{7b0db17d-9cd2-4a93-9733-46cc89022e7c}\0\0",
+                 0,
+                 KFDF_PRECREATE | KFDF_STREAM),
+    KNOWN_FOLDER(FOLDERID_Downloads,
+                 NO_CSIDL,
+                 "Downloads",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Downloads",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_Favorites,
+                 CSIDL_FAVORITES,
+                 "Favorites",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Favorites",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_Fonts,
+                 CSIDL_FONTS,
+                 "Fonts",
+                 KF_CATEGORY_FIXED,
+                 FOLDERID_Windows,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Games,
+                 NO_CSIDL,
+                 "Games",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{ED228FDF-9EA8-4870-83b1-96b02CFE0D52}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_GameTasks,
+                 NO_CSIDL,
+                 "GameTasks",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Microsoft\\Windows\\GameExplorer",
+                 NULL,
+                 0,
+                 KFDF_LOCAL_REDIRECT_ONLY),
+    KNOWN_FOLDER(FOLDERID_History,
+                 CSIDL_HISTORY,
+                 "History",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Microsoft\\Windows\\History",
+                 NULL,
+                 0,
+                 KFDF_LOCAL_REDIRECT_ONLY),
+    KNOWN_FOLDER(FOLDERID_HomeGroup,
+                 NO_CSIDL,
+                 "HomeGroupFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{B4FB3F98-C1EA-428d-A78A-D1F5659CBA93}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ImplicitAppShortcuts,
+                 NO_CSIDL,
+                 "ImplicitAppShortcuts",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_UserPinned,
+                 "ImplicitAppShortcuts",
+                 NULL,
+                 0,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_InternetCache,
+                 CSIDL_INTERNET_CACHE,
+                 "Cache",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Microsoft\\Windows\\Temporary Internet Files",
+                 NULL,
+                 0,
+                 KFDF_LOCAL_REDIRECT_ONLY),
+    KNOWN_FOLDER(FOLDERID_InternetFolder,
+                 CSIDL_INTERNET,
+                 "InternetFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{871C5380-42A0-1069-A2EA-08002B30309D}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Libraries,
+                 NO_CSIDL,
+                 "Libraries",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\Libraries",
+                 NULL,
+                 0,
+                 KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_Links,
+                 NO_CSIDL,
+                 "Links",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Links",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{bfb9d5e0-c6a9-404c-b2b2-ae6db6af4968}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_LocalAppData,
+                 CSIDL_LOCAL_APPDATA,
+                 "Local AppData",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "AppData\\Local",
+                 NULL,
+                 0,
+                 KFDF_LOCAL_REDIRECT_ONLY | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_LocalAppDataLow,
+                 NO_CSIDL,
+                 "LocalAppDataLow",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "AppData\\LocalLow",
+                 NULL,
+                 FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
+                 KFDF_LOCAL_REDIRECT_ONLY | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_LocalizedResourcesDir,
+                 CSIDL_RESOURCES_LOCALIZED,
+                 "LocalizedResourcesDir",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Music,
+                 CSIDL_MYMUSIC,
+                 "My Music",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Music",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{4BD8D571-6D19-48D3-BE97-422220080E43}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_MusicLibrary,
+                 NO_CSIDL,
+                 "MusicLibrary",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Libraries,
+                 "Music.library-ms",
+                 "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{2112AB0A-C86A-4ffe-A368-0DE96E47012E}\0\0",
+                 0,
+                 KFDF_PRECREATE | KFDF_STREAM),
+    KNOWN_FOLDER(FOLDERID_NetHood,
+                 CSIDL_NETHOOD,
+                 "NetHood",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\Network Shortcuts",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_NetworkFolder,
+                 CSIDL_NETWORK,
+                 "NetworkPlacesFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{F02C1A0D-BE21-4350-88B0-7367FC96EF3C}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_OriginalImages,
+                 NO_CSIDL,
+                 "Original Images",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Microsoft\\Windows Photo Gallery\\Original Images",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_PhotoAlbums,
+                 NO_CSIDL,
+                 "PhotoAlbums",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Pictures,
+                 "Slide Shows",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Pictures,
+                 CSIDL_MYPICTURES,
+                 "My Pictures",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Pictures",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{33E28130-4E1E-4676-835A-98395C3BC3BB}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PicturesLibrary,
+                 NO_CSIDL,
+                 "PicturesLibrary",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Libraries,
+                 "Pictures.library-ms",
+                 "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{A990AE9F-A03B-4e80-94BC-9912D7504104}\0\0",
+                 0,
+                 KFDF_PRECREATE | KFDF_STREAM),
+    KNOWN_FOLDER(FOLDERID_Playlists,
+                 NO_CSIDL,
+                 "Playlists",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Music,
+                 "Playlists",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 0),
+    KNOWN_FOLDER(FOLDERID_PrintersFolder,
+                 CSIDL_PRINTERS,
+                 "PrintersFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{2227A280-3AEA-1069-A2DE-08002B30309D}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_PrintHood,
+                 CSIDL_PRINTHOOD,
+                 "PrintHood",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\Printer Shortcuts",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Profile,
+                 CSIDL_PROFILE,
+                 "Profile",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ProgramData,
+                 CSIDL_COMMON_APPDATA,
+                 "Common AppData",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ProgramFiles,
+                 CSIDL_PROGRAM_FILES,
+                 "ProgramFiles",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE
+                ),
+    KNOWN_FOLDER(FOLDERID_ProgramFilesCommon,
+                 CSIDL_PROGRAM_FILES_COMMON,
+                 "ProgramFilesCommon",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ProgramFilesCommonX64,
+                 NO_CSIDL,
+                 "ProgramFilesCommonX64",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ProgramFilesCommonX86,
+                 NO_CSIDL,
+                 "ProgramFilesCommonX86",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ProgramFilesX64,
+                 NO_CSIDL,
+                 "ProgramFilesX64",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ProgramFilesX86,
+                 CSIDL_PROGRAM_FILESX86,
+                 "ProgramFilesX86",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_Programs,
+                 CSIDL_PROGRAMS,
+                 "Programs",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_StartMenu,
+                 "Programs",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_Public,
+                 NO_CSIDL,
+                 "Public",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 "::{4336a54d-038b-4685-ab02-99bb52d3fb8b}\0"
+                 "(null)\0\0" /* 6.1 */,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicDesktop,
+                 CSIDL_COMMON_DESKTOPDIRECTORY,
+                 "Common Desktop",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_Public,
+                 "Desktop",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicDocuments,
+                 CSIDL_COMMON_DOCUMENTS,
+                 "Common Documents",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_Public,
+                 "Documents",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicDownloads,
+                 NO_CSIDL,
+                 "CommonDownloads",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_Public,
+                 "Downloads",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicGameTasks,
+                 NO_CSIDL,
+                 "PublicGameTasks",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_ProgramData,
+                 "Microsoft\\Windows\\GameExplorer",
+                 NULL,
+                 0,
+                 KFDF_LOCAL_REDIRECT_ONLY),
+    KNOWN_FOLDER(FOLDERID_PublicLibraries,
+                 NO_CSIDL,
+                 "PublicLibraries",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_Public,
+                 "Libraries",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicMusic,
+                 CSIDL_COMMON_MUSIC,
+                 "CommonMusic",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_Public,
+                 "Music",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicPictures,
+                 CSIDL_COMMON_PICTURES,
+                 "CommonPictures",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_Public,
+                 "Pictures",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicRingtones,
+                 NO_CSIDL,
+                 "CommonRingtones",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_ProgramData,
+                 "Microsoft\\Windows\\Ringtones",
+                 NULL,
+                 0,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_PublicVideos,
+                 CSIDL_COMMON_VIDEO,
+                 "CommonVideo",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_Public,
+                 "Videos",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_QuickLaunch,
+                 NO_CSIDL,
+                 "Quick Launch",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Internet Explorer\\Quick Launch",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Recent,
+                 CSIDL_RECENT,
+                 "Recent",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\Recent",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_RecordedTVLibrary,
+                 NO_CSIDL,
+                 "RecordedTVLibrary",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_PublicLibraries,
+                 "RecordedTV.library-ms",
+                 NULL,
+                 0,
+                 KFDF_PRECREATE | KFDF_STREAM),
+    KNOWN_FOLDER(FOLDERID_RecycleBinFolder,
+                 CSIDL_BITBUCKET,
+                 "RecycleBinFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{645FF040-5081-101B-9F08-00AA002F954E}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_ResourceDir,
+                 CSIDL_RESOURCES,
+                 "ResourceDir",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Ringtones,
+                 NO_CSIDL,
+                 "Ringtones",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Microsoft\\Windows\\Ringtones",
+                 NULL,
+                 0,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_RoamingAppData,
+                 CSIDL_APPDATA,
+                 "AppData",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "AppData\\Roaming",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SampleMusic,
+                 NO_CSIDL,
+                 "SampleMusic",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_PublicMusic,
+                 "Sample Music",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_SamplePictures,
+                 NO_CSIDL,
+                 "SamplePictures",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_PublicPictures,
+                 "Sample Pictures",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_SamplePlaylists,
+                 NO_CSIDL,
+                 "SamplePlaylists",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_PublicMusic,
+                 "Sample Playlists",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SampleVideos,
+                 NO_CSIDL,
+                 "SampleVideos",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_PublicVideos,
+                 "Sample Videos",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_SavedGames,
+                 NO_CSIDL,
+                 "SavedGames",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Saved Games",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{4C5C32FF-BB9D-43b0-B5B4-2D72E54EAAA4}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_SavedSearches,
+                 NO_CSIDL,
+                 "Searches",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Searches",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{7d1d3a04-debb-4115-95cf-2f29da2920da}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE | KFDF_PUBLISHEXPANDEDPATH),
+    KNOWN_FOLDER(FOLDERID_SEARCH_CSC,
+                 NO_CSIDL,
+                 "CSCFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "shell:::{BD7A2E7B-21CB-41b2-A086-B309680C6B7E}\\*\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SearchHome,
+                 NO_CSIDL,
+                 "SearchHomeFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{9343812e-1c37-4a49-a12e-4b2d810d956b}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SEARCH_MAPI,
+                 NO_CSIDL,
+                 "MAPIFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "shell:::{89D83576-6BD1-4C86-9454-BEB04E94C819}\\*\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SendTo,
+                 CSIDL_SENDTO,
+                 "SendTo",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\SendTo",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SidebarDefaultParts,
+                 NO_CSIDL,
+                 "Default Gadgets",
+                 KF_CATEGORY_COMMON,
+                 FOLDERID_ProgramFiles,
+                 "Windows Sidebar\\Gadgets",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SidebarParts,
+                 NO_CSIDL,
+                 "Gadgets",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Microsoft\\Windows Sidebar\\Gadgets",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_StartMenu,
+                 CSIDL_STARTMENU,
+                 "Start Menu",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\Start Menu",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_Startup,
+                 CSIDL_STARTUP,
+                 "Startup",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Programs,
+                 "StartUp",
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_SyncManagerFolder,
+                 NO_CSIDL,
+                 "SyncCenterFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\0\0" /* 6.1 */,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SyncResultsFolder,
+                 NO_CSIDL,
+                 "SyncResultsFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{BC48B32F-5910-47F5-8570-5074A8A5636A},\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{BC48B32F-5910-47F5-8570-5074A8A5636A},\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SyncSetupFolder,
+                 NO_CSIDL,
+                 "SyncSetupFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{21EC2020-3AEA-1069-A2DD-08002B30309D}\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{F1390A9A-A3F4-4E5D-9C5F-98F3BD8D935C},\0"
+                 "::{26EE0668-A00A-44D7-9371-BEB064C98683}\\0\\::{9C73F5E5-7AE7-4E32-A8E8-8D23B85255BF}\\::{F1390A9A-A3F4-4E5D-9C5F-98F3BD8D935C},\0\0" /* 6.1 */,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_System,
+                 CSIDL_SYSTEM,
+                 "System",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_SystemX86,
+                 CSIDL_SYSTEMX86,
+                 "SystemX86",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Templates,
+                 CSIDL_TEMPLATES,
+                 "Templates",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_RoamingAppData,
+                 "Microsoft\\Windows\\Templates",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_UserPinned,
+                 NO_CSIDL,
+                 "User Pinned",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_QuickLaunch,
+                 "User Pinned",
+                 NULL,
+                 FILE_ATTRIBUTE_HIDDEN,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_UserProfiles,
+                 NO_CSIDL,
+                 "UserProfiles",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_UserProgramFiles,
+                 NO_CSIDL,
+                 "UserProgramFiles",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData,
+                 "Programs",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_UserProgramFilesCommon,
+                 NO_CSIDL,
+                 "UserProgramFilesCommon",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_UserProgramFiles,
+                 "Common",
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_UsersFiles,
+                 NO_CSIDL,
+                 "UsersFilesFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_UsersLibraries,
+                 NO_CSIDL,
+                 "UsersLibrariesFolder",
+                 KF_CATEGORY_VIRTUAL,
+                 GUID_NULL,
+                 NULL,
+                 "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\0\0",
+                 0,
+                 0),
+    KNOWN_FOLDER(FOLDERID_Videos,
+                 CSIDL_MYVIDEO,
+                 "My Video",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Profile,
+                 "Videos",
+                 "::{59031a47-3f72-44a7-89c5-5595fe6b30ee}\\{18989B1D-99B5-455B-841C-AB7C74E4DDFC}\0\0",
+                 FILE_ATTRIBUTE_READONLY,
+                 KFDF_ROAMABLE | KFDF_PRECREATE),
+    KNOWN_FOLDER(FOLDERID_VideosLibrary,
+                 NO_CSIDL,
+                 "VideosLibrary",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_Libraries,
+                 "Videos.library-ms",
+                 "::{031E4825-7B94-4dc3-B131-E946B44C8DD5}\\{491E922F-5643-4af4-A7EB-4E7A138D8174}\0\0",
+                 0,
+                 KFDF_PRECREATE | KFDF_STREAM),
+    KNOWN_FOLDER(FOLDERID_Windows,
+                 CSIDL_WINDOWS,
+                 "Windows",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(_FOLDERID_CredentialManager,
+                 NO_CSIDL,
+                 "CredentialManager",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(_FOLDERID_CryptoKeys,
+                 NO_CSIDL,
+                 "CryptoKeys",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(_FOLDERID_DpapiKeys,
+                 NO_CSIDL,
+                 "DpapiKeys",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    KNOWN_FOLDER(_FOLDERID_SystemCertificates,
+                 NO_CSIDL,
+                 "SystemCertificates",
+                 KF_CATEGORY_FIXED,
+                 GUID_NULL,
+                 NULL,
+                 NULL,
+                 0,
+                 0),
+    { NULL, NULL, 0, NULL, NULL, 0, 0 }
+};
+#undef KNOWN_FOLDER
+BOOL known_folder_found[sizeof(known_folders)/sizeof(known_folders[0])-1];
+
+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], sRelativePath[MAX_PATH], sParsingName[MAX_PATH];
+    BOOL validPath;
+    char sParentGuid[39];
+    BOOL *current_known_folder_found = &known_folder_found[0];
+    BOOL found = FALSE;
+    const char *srcParsingName;
+
+    while(known_folder->folderId != NULL)
+    {
+        if(IsEqualGUID(known_folder->folderId, folderId))
+        {
+            *current_known_folder_found = TRUE;
+            found = TRUE;
+            /* verify CSIDL */
+            if(known_folder->csidl != NO_CSIDL)
+            {
+                expectedCsidl = known_folder->csidl & (~CSIDL_TODO_WINE);
+
+                hr = IKnownFolderManager_FolderIdToCsidl(mgr, folderId, &csidl);
+                ok_(__FILE__, known_folder->line)(hr == S_OK, "cannot retrieve CSIDL for folder %s\n", known_folder->sFolderId);
+
+                if(known_folder->csidl & CSIDL_TODO_WINE)
+                    todo_wine ok_(__FILE__, known_folder->line)(csidl == expectedCsidl, "invalid CSIDL retrieved for folder %s. %d (%s) expected, but %d found\n", known_folder->sFolderId, expectedCsidl, known_folder->sCsidl, csidl);
+                else
+                    ok_(__FILE__, known_folder->line)(csidl == expectedCsidl, "invalid CSIDL retrieved for folder %s. %d (%s) expected, but %d found\n", known_folder->sFolderId, expectedCsidl, known_folder->sCsidl, csidl);
+            }
+
+            hr = IKnownFolderManager_GetFolder(mgr, folderId, &folder);
+            ok_(__FILE__, known_folder->line)(hr == S_OK, "cannot get known folder for %s\n", known_folder->sFolderId);
+            if(SUCCEEDED(hr))
+            {
+                hr = IKnownFolder_GetFolderDefinition(folder, &kfd);
+                todo_wine
+                ok_(__FILE__, known_folder->line)(hr == S_OK, "cannot get known folder definition for %s\n", known_folder->sFolderId);
+                if(SUCCEEDED(hr))
+                {
+                    ret = MultiByteToWideChar(CP_ACP, 0, known_folder->sName, -1,  sName, sizeof(sName)/sizeof(sName[0]));
+                    ok_(__FILE__, known_folder->line)(ret != 0, "cannot convert known folder name \"%s\" to wide characters\n", known_folder->sName);
+
+                    todo_wine
+                    ok_(__FILE__, known_folder->line)(lstrcmpW(kfd.pszName, sName)==0, "invalid known folder name returned for %s: %s expected, but %s retrieved\n", known_folder->sFolderId, wine_dbgstr_w(sName), wine_dbgstr_w(kfd.pszName));
+
+                    ok_(__FILE__, known_folder->line)(kfd.category == known_folder->category, "invalid known folder category for %s: %d expected, but %d retrieved\n", known_folder->sFolderId, known_folder->category, kfd.category);
+
+                    printGUID(&kfd.fidParent, sParentGuid);
+                    ok_(__FILE__, known_folder->line)(IsEqualGUID(known_folder->fidParent, &kfd.fidParent), "invalid known folder parent for %s: %s expected, but %s retrieved\n", known_folder->sFolderId, known_folder->sParent, sParentGuid);
+
+                    if(!known_folder->sRelativePath)
+                        validPath = (kfd.pszRelativePath==NULL);
+                    else
+                    {
+                        ret = MultiByteToWideChar(CP_ACP, 0, known_folder->sRelativePath, -1, sRelativePath, sizeof(sRelativePath)/sizeof(sRelativePath[0]));
+                        ok_(__FILE__, known_folder->line)(ret != 0, "cannot convert known folder path \"%s\" to wide characters\n", known_folder->sRelativePath);
+
+                        validPath = (lstrcmpW(kfd.pszRelativePath, sRelativePath)==0);
+                    }
+
+                    ok_(__FILE__, known_folder->line)(validPath, "invalid known folder relative path returned for %s: %s expected, but %s retrieved\n", known_folder->sFolderId, known_folder->sRelativePath, wine_dbgstr_w(kfd.pszRelativePath));
+
+                    /* to check parsing name, we need to iterate list */
+                    srcParsingName = known_folder->sParsingName;
+
+                    /* if we expect NULL, then we don't even check the list */
+                    validPath = (srcParsingName==NULL) && (kfd.pszParsingName==NULL);
+
+                    if(srcParsingName)
+                        while(*srcParsingName && !validPath)
+                        {
+                            /* when NULL is only one of possible value, we mark path as valid */
+                            validPath = (strcmp(srcParsingName, "(null)")==0) && (kfd.pszParsingName==NULL);
+
+                            /* in the other case, we compare string from list with retrieved value */
+                            if(!validPath)
+                            {
+                                ret = MultiByteToWideChar(CP_ACP, 0, srcParsingName, -1, sParsingName, sizeof(sParsingName)/sizeof(sParsingName[0]));
+                                ok_(__FILE__, known_folder->line)(ret != 0, "cannot convert known folder path \"%s\" to wide characters\n", srcParsingName);
+
+                                validPath = (lstrcmpW(kfd.pszParsingName, sParsingName)==0);
+                            }
+
+                            srcParsingName += strlen(srcParsingName)+1;
+                        }
+
+                    ok_(__FILE__, known_folder->line)(validPath, "invalid known folder parsing name returned for %s: %s retrieved\n", known_folder->sFolderId, wine_dbgstr_w(kfd.pszParsingName));
+
+                    ok_(__FILE__, known_folder->line)(known_folder->attributes == kfd.dwAttributes, "invalid known folder attributes for %s: 0x%08x expected, but 0x%08x retrieved\n", known_folder->sFolderId, known_folder->attributes, kfd.dwAttributes);
+
+                    ok_(__FILE__, known_folder->line)(!(kfd.kfdFlags & (~known_folder->definitionFlags)), "invalid known folder flags for %s: 0x%08x expected, but 0x%08x retrieved\n", known_folder->sFolderId, known_folder->definitionFlags, kfd.kfdFlags);
+
+                    FreeKnownFolderDefinitionFields(&kfd);
+                }
+
+            IKnownFolder_Release(folder);
+            }
+
+            break;
+        }
+        known_folder++;
+        current_known_folder_found++;
+    }
+
+    if(!found)
+    {
+        printGUID(folderId, sParentGuid);
+        trace("unknown known folder found: %s\n", sParentGuid);
+
+        hr = IKnownFolderManager_GetFolder(mgr, folderId, &folder);
+        ok(hr == S_OK, "cannot get known folder for %s\n", sParentGuid);
+        if(SUCCEEDED(hr))
+        {
+            hr = IKnownFolder_GetFolderDefinition(folder, &kfd);
+            todo_wine
+            ok(hr == S_OK, "cannot get known folder definition for %s\n", sParentGuid);
+            if(SUCCEEDED(hr))
+            {
+                trace("  category: %d\n", kfd.category);
+                trace("  name: %s\n", wine_dbgstr_w(kfd.pszName));
+                trace("  description: %s\n", wine_dbgstr_w(kfd.pszDescription));
+                printGUID(&kfd.fidParent, sParentGuid);
+                trace("  parent: %s\n", sParentGuid);
+                trace("  relative path: %s\n", wine_dbgstr_w(kfd.pszRelativePath));
+                trace("  parsing name: %s\n", wine_dbgstr_w(kfd.pszParsingName));
+                trace("  tooltip: %s\n", wine_dbgstr_w(kfd.pszTooltip));
+                trace("  localized name: %s\n", wine_dbgstr_w(kfd.pszLocalizedName));
+                trace("  icon: %s\n", wine_dbgstr_w(kfd.pszIcon));
+                trace("  security: %s\n", wine_dbgstr_w(kfd.pszSecurity));
+                trace("  attributes: 0x%08x\n", kfd.dwAttributes);
+                trace("  flags: 0x%08x\n", kfd.kfdFlags);
+                printGUID(&kfd.ftidType, sParentGuid);
+                trace("  type: %s\n", sParentGuid);
+                FreeKnownFolderDefinitionFields(&kfd);
+            }
+
+            IKnownFolder_Release(folder);
+        }
+    }
+}
+#undef NO_CSIDL
+#undef CSIDL_TODO_WINE
+
+static void test_knownFolders(void)
+{
+    static const WCHAR sWindows[] = {'W','i','n','d','o','w','s',0};
+    static const WCHAR sExample[] = {'E','x','a','m','p','l','e',0};
+    static const WCHAR sExample2[] = {'E','x','a','m','p','l','e','2',0};
+    static const WCHAR sSubFolder[] = {'S','u','b','F','o','l','d','e','r',0};
+    static const WCHAR sBackslash[] = {'\\',0};
+    static const KNOWNFOLDERID newFolderId = {0x01234567, 0x89AB, 0xCDEF, {0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x01} };
+    static const KNOWNFOLDERID subFolderId = {0xFEDCBA98, 0x7654, 0x3210, {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF} };
+    HRESULT hr;
+    IKnownFolderManager *mgr = NULL;
+    IKnownFolder *folder = NULL, *subFolder = NULL;
+    KNOWNFOLDERID folderId, *folders;
+    KF_CATEGORY cat = 0;
+    KNOWNFOLDER_DEFINITION kfDefinition, kfSubDefinition;
+    int csidl, i;
+    UINT nCount = 0;
+    LPWSTR folderPath, errorMsg;
+    KF_REDIRECTION_CAPABILITIES redirectionCapabilities = 1;
+    WCHAR sWinDir[MAX_PATH], sExamplePath[MAX_PATH], sExample2Path[MAX_PATH], sSubFolderPath[MAX_PATH], sSubFolder2Path[MAX_PATH];
+    BOOL bRes;
+    DWORD dwAttributes;
+
+    GetWindowsDirectoryW( sWinDir, MAX_PATH );
+
+    GetTempPathW(sizeof(sExamplePath)/sizeof(sExamplePath[0]), sExamplePath);
+    lstrcatW(sExamplePath, sExample);
+
+    GetTempPathW(sizeof(sExample2Path)/sizeof(sExample2Path[0]), sExample2Path);
+    lstrcatW(sExample2Path, sExample2);
+
+    lstrcpyW(sSubFolderPath, sExamplePath);
+    lstrcatW(sSubFolderPath, sBackslash);
+    lstrcatW(sSubFolderPath, sSubFolder);
+
+    lstrcpyW(sSubFolder2Path, sExample2Path);
+    lstrcatW(sSubFolder2Path, sBackslash);
+    lstrcatW(sSubFolder2Path, sSubFolder);
+
+    CoInitialize(NULL);
+
+    hr = CoCreateInstance(&CLSID_KnownFolderManager, NULL, CLSCTX_INPROC_SERVER,
+                          &IID_IKnownFolderManager, (LPVOID*)&mgr);
+    if(hr == REGDB_E_CLASSNOTREG)
+        win_skip("IKnownFolderManager unavailable\n");
+    else
+    {
+        ok(hr == S_OK, "failed to create KnownFolderManager instance: 0x%08x\n", hr);
+
+        hr = IKnownFolderManager_FolderIdFromCsidl(mgr, CSIDL_WINDOWS, &folderId);
+        ok(hr == S_OK, "failed to convert CSIDL to KNOWNFOLDERID: 0x%08x\n", hr);
+        ok(IsEqualGUID(&folderId, &FOLDERID_Windows)==TRUE, "invalid KNOWNFOLDERID returned\n");
+
+        hr = IKnownFolderManager_FolderIdToCsidl(mgr, &FOLDERID_Windows, &csidl);
+        ok(hr == S_OK, "failed to convert CSIDL to KNOWNFOLDERID: 0x%08x\n", hr);
+        ok(csidl == CSIDL_WINDOWS, "invalid CSIDL returned\n");
+
+        hr = IKnownFolderManager_GetFolder(mgr, &FOLDERID_Windows, &folder);
+        ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = IKnownFolder_GetCategory(folder, &cat);
+            todo_wine
+            ok(hr == S_OK, "failed to get folder category: 0x%08x\n", hr);
+            todo_wine
+            ok(cat==KF_CATEGORY_FIXED, "invalid folder category: %d\n", cat);
+
+            hr = IKnownFolder_GetId(folder, &folderId);
+            ok(hr == S_OK, "failed to get folder id: 0x%08x\n", hr);
+            ok(IsEqualGUID(&folderId, &FOLDERID_Windows)==TRUE, "invalid KNOWNFOLDERID returned\n");
+
+            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+            ok(lstrcmpiW(sWinDir, folderPath)==0, "invalid path returned: \"%s\", expected: \"%s\"\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sWinDir));
+            CoTaskMemFree(folderPath);
+
+            hr = IKnownFolder_GetRedirectionCapabilities(folder, &redirectionCapabilities);
+            todo_wine
+            ok(hr == S_OK, "failed to get redirection capabilities: 0x%08x\n", hr);
+            todo_wine
+            ok(redirectionCapabilities==0, "invalid redirection capabilities returned: %d\n", redirectionCapabilities);
+
+            hr = IKnownFolder_SetPath(folder, 0, sWinDir);
+            todo_wine
+            ok(hr == E_INVALIDARG, "unexpected value from SetPath: 0x%08x\n", hr);
+
+            hr = IKnownFolder_GetFolderDefinition(folder, &kfDefinition);
+            todo_wine
+            ok(hr == S_OK, "failed to get folder definition: 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                todo_wine
+                ok(kfDefinition.category==KF_CATEGORY_FIXED, "invalid folder category: 0x%08x\n", kfDefinition.category);
+                todo_wine
+                ok(lstrcmpW(kfDefinition.pszName, sWindows)==0, "invalid folder name: %s\n", wine_dbgstr_w(kfDefinition.pszName));
+                todo_wine
+                ok(kfDefinition.dwAttributes==0, "invalid folder attributes: %d\n", kfDefinition.dwAttributes);
+                FreeKnownFolderDefinitionFields(&kfDefinition);
+            }
+
+            hr = IKnownFolder_Release(folder);
+            ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
+        }
+
+        hr = IKnownFolderManager_GetFolderByName(mgr, sWindows, &folder);
+        todo_wine
+        ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = IKnownFolder_GetId(folder, &folderId);
+            ok(hr == S_OK, "failed to get folder id: 0x%08x\n", hr);
+            ok(IsEqualGUID(&folderId, &FOLDERID_Windows)==TRUE, "invalid KNOWNFOLDERID returned\n");
+
+            hr = IKnownFolder_Release(folder);
+            ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
+        }
+
+        for(i=0; i<sizeof(known_folder_found)/sizeof(known_folder_found[0]); ++i)
+            known_folder_found[i] = FALSE;
+
+        hr = IKnownFolderManager_GetFolderIds(mgr, &folders, &nCount);
+        ok(hr == S_OK, "failed to get known folders: 0x%08x\n", hr);
+        for(i=0;i<nCount;++i)
+            check_known_folder(mgr, &folders[i]);
+
+        for(i=0; i<sizeof(known_folder_found)/sizeof(known_folder_found[0]); ++i)
+            if(!known_folder_found[i])
+                trace("Known folder %s not found on current platform\n", known_folders[i].sFolderId);
+
+        CoTaskMemFree(folders);
+
+        /* test of registering new known folders */
+        bRes = CreateDirectoryW(sExamplePath, NULL);
+        ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sExamplePath));
+        bRes = CreateDirectoryW(sExample2Path, NULL);
+        ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sExample2Path));
+        bRes = CreateDirectoryW(sSubFolderPath, NULL);
+        ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sSubFolderPath));
+
+        ZeroMemory(&kfDefinition, sizeof(kfDefinition));
+        kfDefinition.category = KF_CATEGORY_PERUSER;
+        kfDefinition.pszName = CoTaskMemAlloc(sizeof(sExample));
+        lstrcpyW(kfDefinition.pszName, sExample);
+        kfDefinition.pszDescription = CoTaskMemAlloc(sizeof(sExample));
+        lstrcpyW(kfDefinition.pszDescription, sExample);
+        kfDefinition.pszRelativePath = CoTaskMemAlloc(sizeof(sExamplePath));
+        lstrcpyW(kfDefinition.pszRelativePath, sExamplePath);
+
+        hr = IKnownFolderManager_RegisterFolder(mgr, &newFolderId, &kfDefinition);
+        if(hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED))
+            win_skip("No permissions required to register custom known folder\n");
+        else
+        {
+            ok(hr == S_OK, "failed to register known folder: 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                hr = IKnownFolderManager_GetFolder(mgr, &newFolderId, &folder);
+                ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
+                if(SUCCEEDED(hr))
+                {
+                    hr = IKnownFolder_GetCategory(folder, &cat);
+                    ok(hr == S_OK, "failed to get folder category: hr=0x%0x\n", hr);
+                    ok(cat == KF_CATEGORY_PERUSER, "invalid category returned: %d, while %d (KF_CATEGORY_PERUSER) expected\n", cat, KF_CATEGORY_PERUSER);
+
+                    hr = IKnownFolder_GetId(folder, &folderId);
+                    ok(hr == S_OK, "failed to get folder id: 0x%08x\n", hr);
+                    ok(IsEqualGUID(&folderId, &newFolderId)==TRUE, "invalid KNOWNFOLDERID returned\n");
+
+                    /* current path should be Temp\Example */
+                    hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                    ok(hr == S_OK, "failed to get path from known folder: 0x%08x\n", hr);
+                    ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
+                    CoTaskMemFree(folderPath);
+
+                    /* register sub-folder and mark it as child of Example folder */
+                    ZeroMemory(&kfSubDefinition, sizeof(kfSubDefinition));
+                    kfSubDefinition.category = KF_CATEGORY_PERUSER;
+                    kfSubDefinition.pszName = CoTaskMemAlloc(sizeof(sSubFolder));
+                    lstrcpyW(kfSubDefinition.pszName, sSubFolder);
+                    kfSubDefinition.pszDescription = CoTaskMemAlloc(sizeof(sSubFolder));
+                    lstrcpyW(kfSubDefinition.pszDescription, sSubFolder);
+                    kfSubDefinition.pszRelativePath = CoTaskMemAlloc(sizeof(sSubFolder));
+                    lstrcpyW(kfSubDefinition.pszRelativePath, sSubFolder);
+                    kfSubDefinition.fidParent = newFolderId;
+
+                    hr = IKnownFolderManager_RegisterFolder(mgr, &subFolderId, &kfSubDefinition);
+                    ok(hr == S_OK, "failed to register known folder: 0x%08x\n", hr);
+                    if(SUCCEEDED(hr))
+                    {
+
+                        hr = IKnownFolderManager_GetFolder(mgr, &subFolderId, &subFolder);
+                        ok(hr == S_OK, "failed to get known folder: 0x%08x\n", hr);
+                        if(SUCCEEDED(hr))
+                        {
+                            /* check sub folder path */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
+                            CoTaskMemFree(folderPath);
+
+
+                            /* try to redirect Example to Temp\Example2  */
+                            hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, 0, sExample2Path, 0, NULL, &errorMsg);
+                            ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder - it should fail now, as we redirected it's parent folder, but we have no sub folder in new location */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), "unexpected value from GetPath(): 0x%08x\n", hr);
+                            ok(folderPath==NULL, "invalid known folder path retrieved: \"%s\" when NULL pointer was expected\n", wine_dbgstr_w(folderPath));
+                            CoTaskMemFree(folderPath);
+
+
+                            /* set Example path to original. Using SetPath() is valid here, as it also uses redirection internally */
+                            hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
+                            ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
+                            CoTaskMemFree(folderPath);
+
+
+                            /* create sub folder in Temp\Example2 */
+                            bRes = CreateDirectoryW(sSubFolder2Path, NULL);
+                            ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sSubFolder2Path));
+
+                            /* again perform that same redirection */
+                            hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, 0, sExample2Path, 0, NULL, &errorMsg);
+                            ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
+
+                            /* verify sub folder. It should succeed now, as the required sub folder exists */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* remove newly created directory */
+                            RemoveDirectoryW(sSubFolder2Path);
+
+                            /* verify sub folder. It still succeedes, so Windows does not check folder presence each time */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            todo_wine
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            todo_wine
+                            ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
+                            CoTaskMemFree(folderPath);
+
+
+                            /* set Example path to original */
+                            hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
+                            ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
+                            CoTaskMemFree(folderPath);
+
+
+                            /* create sub folder in Temp\Example2 */
+                            bRes = CreateDirectoryW(sSubFolder2Path, NULL);
+                            ok(bRes, "cannot create example directory: %s\n", wine_dbgstr_w(sSubFolder2Path));
+
+                            /* do that same redirection, but try to exclude sub-folder */
+                            hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, 0, sExample2Path, 1, &subFolderId, &errorMsg);
+                            ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder. Unexpectedly, this path was also changed. So, exclusion seems to be ignored (Windows bug)? This test however will let us know, if this behavior is changed */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* remove newly created directory */
+                            RemoveDirectoryW(sSubFolder2Path);
+
+
+                            /* set Example path to original */
+                            hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
+                            ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
+                            CoTaskMemFree(folderPath);
+
+
+                            /* do that same redirection again, but set it to copy content. It should also copy the sub folder, so checking it would succeed now */
+                            hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, KF_REDIRECT_COPY_CONTENTS, sExample2Path, 0, NULL, &errorMsg);
+                            ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* remove copied directory */
+                            RemoveDirectoryW(sSubFolder2Path);
+
+
+                            /* set Example path to original */
+                            hr = IKnownFolder_SetPath(folder, 0, sExamplePath);
+                            ok(hr == S_OK, "SetPath() failed: 0x%08x\n", hr);
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
+                            CoTaskMemFree(folderPath);
+
+
+                            /* redirect again, set it to copy content and remove originals */
+                            hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, KF_REDIRECT_COPY_CONTENTS | KF_REDIRECT_DEL_SOURCE_CONTENTS, sExample2Path, 0, NULL, &errorMsg);
+                            ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExample2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExample2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolder2Path)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolder2Path));
+                            CoTaskMemFree(folderPath);
+
+                            /* check if original directory was really removed */
+                            dwAttributes = GetFileAttributesW(sExamplePath);
+                            ok(dwAttributes==INVALID_FILE_ATTRIBUTES, "directory should not exist, but has attributes: 0x%08x\n", dwAttributes );
+
+
+                            /* redirect (with copy) to original path */
+                            hr = IKnownFolderManager_Redirect(mgr, &newFolderId, NULL, KF_REDIRECT_COPY_CONTENTS,  sExamplePath, 0, NULL, &errorMsg);
+                            ok(hr == S_OK, "failed to redirect known folder: 0x%08x, errorMsg: %s\n", hr, wine_dbgstr_w(errorMsg));
+
+                            /* verify */
+                            hr = IKnownFolder_GetPath(folder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sExamplePath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sExamplePath));
+                            CoTaskMemFree(folderPath);
+
+                            /* verify sub folder */
+                            hr = IKnownFolder_GetPath(subFolder, 0, &folderPath);
+                            ok(hr == S_OK, "failed to get known folder path: 0x%08x\n", hr);
+                            ok(lstrcmpiW(folderPath, sSubFolderPath)==0, "invalid known folder path retrieved: \"%s\" when \"%s\" was expected\n", wine_dbgstr_w(folderPath), wine_dbgstr_w(sSubFolderPath));
+                            CoTaskMemFree(folderPath);
+
+                            /* check shell utility functions */
+                            if(!pSHGetKnownFolderPath || !pSHSetKnownFolderPath)
+                                todo_wine
+                                win_skip("cannot get SHGet/SetKnownFolderPath routines\n");
+                            else
+                            {
+                                /* try to get current known folder path */
+                                hr = pSHGetKnownFolderPath(&newFolderId, 0, NULL, &folderPath);
+                                todo_wine
+                                ok(hr==S_OK, "cannot get known folder path: hr=0x%0x\n", hr);
+                                todo_wine
+                                ok(lstrcmpW(folderPath, sExamplePath)==0, "invalid path returned: %s\n", wine_dbgstr_w(folderPath));
+
+                                /* set it to new value */
+                                hr = pSHSetKnownFolderPath(&newFolderId, 0, NULL, sExample2Path);
+                                todo_wine
+                                ok(hr==S_OK, "cannot set known folder path: hr=0x%0x\n", hr);
+
+                                /* check if it changed */
+                                hr = pSHGetKnownFolderPath(&newFolderId, 0, NULL, &folderPath);
+                                todo_wine
+                                ok(hr==S_OK, "cannot get known folder path: hr=0x%0x\n", hr);
+                                todo_wine
+                                ok(lstrcmpW(folderPath, sExample2Path)==0, "invalid path returned: %s\n", wine_dbgstr_w(folderPath));
+
+                                /* set it back */
+                                hr = pSHSetKnownFolderPath(&newFolderId, 0, NULL, sExamplePath);
+                                todo_wine
+                                ok(hr==S_OK, "cannot set known folder path: hr=0x%0x\n", hr);
+                            }
+
+                            IKnownFolder_Release(subFolder);
+                        }
+
+                        hr = IKnownFolderManager_UnregisterFolder(mgr, &subFolderId);
+                        ok(hr == S_OK, "failed to unregister folder: 0x%08x\n", hr);
+                    }
+
+                    FreeKnownFolderDefinitionFields(&kfSubDefinition);
+
+                    hr = IKnownFolder_Release(folder);
+                    ok(hr == S_OK, "failed to release KnownFolder instance: 0x%08x\n", hr);
+                }
+
+                hr = IKnownFolderManager_UnregisterFolder(mgr, &newFolderId);
+                ok(hr == S_OK, "failed to unregister folder: 0x%08x\n", hr);
+            }
+        }
+        FreeKnownFolderDefinitionFields(&kfDefinition);
+
+        RemoveDirectoryW(sSubFolder2Path);
+        RemoveDirectoryW(sSubFolderPath);
+        RemoveDirectoryW(sExamplePath);
+        RemoveDirectoryW(sExample2Path);
+
+        hr = IKnownFolderManager_Release(mgr);
+        ok(hr == S_OK, "failed to release KnownFolderManager instance: 0x%08x\n", hr);
+    }
+    CoUninitialize();
+}
+
 START_TEST(shellpath)
 {
     if (!init()) return;
@@ -858,5 +2513,7 @@ START_TEST(shellpath)
         testWinDir();
         testSystemDir();
         test_NonExistentPath();
+        test_SHGetFolderPathEx();
+        test_knownFolders();
     }
 }
diff --git a/rostests/winetests/shell32/shfldr_special.c b/rostests/winetests/shell32/shfldr_special.c
index 24374bc0843..cfb31bec7e8 100644
--- a/rostests/winetests/shell32/shfldr_special.c
+++ b/rostests/winetests/shell32/shfldr_special.c
@@ -150,9 +150,9 @@ static void test_printers_folder(void)
 if (0)
 {
     /* crashes on XP */
-    hr = IShellFolder2_GetDetailsOf(folder, NULL, 0, NULL);
-    hr = IShellFolder2_GetDefaultColumnState(folder, 0, NULL);
-    hr = IPersistFolder2_GetCurFolder(pf, NULL);
+    IShellFolder2_GetDetailsOf(folder, NULL, 0, NULL);
+    IShellFolder2_GetDefaultColumnState(folder, 0, NULL);
+    IPersistFolder2_GetCurFolder(pf, NULL);
 }
 
     /* 5 columns defined */
@@ -162,8 +162,11 @@ if (0)
     hr = IShellFolder2_GetDefaultColumnState(folder, 6, &state);
     ok(broken(hr == E_NOTIMPL) || hr == E_INVALIDARG /* Win7 */, "got 0x%08x\n", hr);
 
+    details.str.u.pOleStr = NULL;
     hr = IShellFolder2_GetDetailsOf(folder, NULL, 0, &details);
     ok(hr == S_OK || broken(E_NOTIMPL) /* W2K */, "got 0x%08x\n", hr);
+    if (SHELL_OsIsUnicode()) SHFree(details.str.u.pOleStr);
+
     /* test every column if method is implemented */
     if (hr == S_OK)
     {
diff --git a/rostests/winetests/shell32/shlexec.c b/rostests/winetests/shell32/shlexec.c
index b883d0bcbf9..9c0bc582861 100755
--- a/rostests/winetests/shell32/shlexec.c
+++ b/rostests/winetests/shell32/shlexec.c
@@ -57,6 +57,7 @@ static char tmpdir[MAX_PATH];
 static char child_file[MAX_PATH];
 static DLLVERSIONINFO dllver;
 static BOOL skip_noassoc_tests = FALSE;
+static HANDLE dde_ready_event;
 
 
 /***
@@ -526,7 +527,7 @@ static void CALLBACK childTimeout(HWND wnd, UINT msg, UINT_PTR timer, DWORD time
 
 static void doChild(int argc, char** argv)
 {
-    char* filename;
+    char *filename, longpath[MAX_PATH] = "";
     HANDLE hFile, map;
     int i;
     int rc;
@@ -552,6 +553,8 @@ static void doChild(int argc, char** argv)
             trace("argvA%d=%s\n", i, argv[i]);
         childPrintf(hFile, "argvA%d=%s\r\n", i, encodeA(argv[i]));
     }
+    GetModuleFileNameA(GetModuleHandleA(NULL), longpath, MAX_PATH);
+    childPrintf(hFile, "longPath=%s\r\n", encodeA(longpath));
 
     map = OpenFileMappingA(FILE_MAP_READ, FALSE, "winetest_shlexec_dde_map");
     if (map != NULL)
@@ -572,13 +575,14 @@ static void doChild(int argc, char** argv)
 
             timer = SetTimer(NULL, 0, 2500, childTimeout);
 
-            dde_ready = CreateEvent(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready");
+            dde_ready = OpenEvent(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready");
             SetEvent(dde_ready);
             CloseHandle(dde_ready);
 
             while (GetMessage(&msg, NULL, 0, 0))
                 DispatchMessage(&msg);
 
+            Sleep(500);
             KillTimer(NULL, timer);
             assert(DdeNameService(ddeInst, hszApplication, 0L, DNS_UNREGISTER));
             assert(DdeFreeStringHandle(ddeInst, hszTopic));
@@ -587,7 +591,7 @@ static void doChild(int argc, char** argv)
         }
         else
         {
-            dde_ready = CreateEvent(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready");
+            dde_ready = OpenEvent(EVENT_MODIFY_STATE, FALSE, "winetest_shlexec_dde_ready");
             SetEvent(dde_ready);
             CloseHandle(dde_ready);
         }
@@ -676,6 +680,11 @@ static void _okChildString(const char* file, int line, const char* key, const ch
 {
     char* result;
     result=getChildString("Arguments", key);
+    if (!result)
+    {
+        ok_(file, line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected);
+        return;
+    }
     ok_(file, line)(lstrcmpiA(result, expected) == 0,
                     "%s expected '%s', got '%s'\n", key, expected, result);
 }
@@ -684,6 +693,11 @@ static void _okChildPath(const char* file, int line, const char* key, const char
 {
     char* result;
     result=getChildString("Arguments", key);
+    if (!result)
+    {
+        ok_(file, line)(FALSE, "%s expected '%s', but key not found or empty\n", key, expected);
+        return;
+    }
     ok_(file, line)(StrCmpPath(result, expected) == 0,
                     "%s expected '%s', got '%s'\n", key, expected, result);
 }
@@ -774,6 +788,26 @@ static DWORD get_long_path_name(const char* shortpath, char* longpath, DWORD lon
     return tmplen;
 }
 
+/***
+ *
+ * PathFindFileNameA equivalent that supports WinNT
+ *
+ ***/
+
+static LPSTR path_find_file_name(LPCSTR lpszPath)
+{
+  LPCSTR lastSlash = lpszPath;
+
+  while (lpszPath && *lpszPath)
+  {
+    if ((*lpszPath == '\\' || *lpszPath == '/' || *lpszPath == ':') &&
+        lpszPath[1] && lpszPath[1] != '\\' && lpszPath[1] != '/')
+      lastSlash = lpszPath + 1;
+    lpszPath = CharNext(lpszPath);
+  }
+  return (LPSTR)lastSlash;
+}
+
 /***
  *
  * Tests
@@ -1613,14 +1647,7 @@ static dde_tests_t dde_tests[] =
 
 static DWORD WINAPI hooked_WaitForInputIdle(HANDLE process, DWORD timeout)
 {
-    HANDLE dde_ready;
-    DWORD wait_result;
-
-    dde_ready = CreateEventA(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready");
-    wait_result = WaitForSingleObject(dde_ready, timeout);
-    CloseHandle(dde_ready);
-
-    return wait_result;
+    return WaitForSingleObject(dde_ready_event, timeout);
 }
 
 /*
@@ -1714,7 +1741,7 @@ static void test_dde(void)
     {
         if (!create_test_association(".sde"))
         {
-            skip("Unable to create association for '.sfe'\n");
+            skip("Unable to create association for '.sde'\n");
             return;
         }
         create_test_verb_dde(".sde", "Open", 0, test->command, test->ddeexec,
@@ -1732,7 +1759,9 @@ static void test_dde(void)
         }
         ddeExec[0] = 0;
 
+        dde_ready_event = CreateEventA(NULL, FALSE, FALSE, "winetest_shlexec_dde_ready");
         rc = shell_execute_ex(SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI, NULL, filename, NULL, NULL);
+        CloseHandle(dde_ready_event);
         if ((test->todo & 0x1)==0)
         {
             ok(32 < rc, "%s failed: rc=%d err=%d\n", shell_call,
@@ -2118,8 +2147,9 @@ static void test_commandline(void)
     static const WCHAR chkfmt3[] = {'\\','\"','%','s','\"',0};
     static const WCHAR chkfmt4[] = {'%','s','=','%','s','\"',' ','%','s','\"',0};
     WCHAR cmdline[255];
-    LPWSTR *args = (LPWSTR*)0xdeadcafe;
+    LPWSTR *args = (LPWSTR*)0xdeadcafe, pbuf;
     INT numargs = -1;
+    size_t buflen;
 
     wsprintfW(cmdline,fmt1,one,two,three,four);
     args=CommandLineToArgvW(cmdline,&numargs);
@@ -2170,6 +2200,46 @@ static void test_commandline(void)
     wsprintfW(cmdline,fmt6);
     args=CommandLineToArgvW(cmdline,&numargs);
     ok(numargs == 1, "expected 1 args, got %i\n",numargs);
+    if (numargs == 1) {
+        buflen = max(lstrlenW(args[0])+1,256);
+        pbuf = HeapAlloc(GetProcessHeap(), 0, buflen*sizeof(pbuf[0]));
+        GetModuleFileNameW(NULL, pbuf, buflen);
+        pbuf[buflen-1] = 0;
+        /* check args[0] is module file name */
+        ok(lstrcmpW(args[0],pbuf)==0, "wrong path to the current executable\n");
+        HeapFree(GetProcessHeap(), 0, pbuf);
+    }
+}
+
+static void test_directory(void)
+{
+    char path[MAX_PATH], newdir[MAX_PATH];
+    char params[1024];
+    int rc;
+
+    /* copy this executable to a new folder and cd to it */
+    sprintf(newdir, "%s\\newfolder", tmpdir);
+    rc = CreateDirectoryA( newdir, NULL );
+    ok( rc, "failed to create %s err %u\n", newdir, GetLastError() );
+    sprintf(path, "%s\\%s", newdir, path_find_file_name(argv0));
+    CopyFileA(argv0, path, FALSE);
+    SetCurrentDirectory(tmpdir);
+
+    sprintf(params, "shlexec \"%s\" Exec", child_file);
+
+    rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI,
+                        NULL, path_find_file_name(argv0), params, NULL);
+    todo_wine ok(rc == SE_ERR_FNF, "%s returned %d\n", shell_call, rc);
+
+    rc=shell_execute_ex(SEE_MASK_NOZONECHECKS|SEE_MASK_FLAG_NO_UI,
+                        NULL, path_find_file_name(argv0), params, newdir);
+    ok(rc > 32, "%s returned %d\n", shell_call, rc);
+    okChildInt("argcA", 4);
+    okChildString("argvA3", "Exec");
+    todo_wine okChildPath("longPath", path);
+
+    DeleteFile(path);
+    RemoveDirectoryA(newdir);
 }
 
 START_TEST(shlexec)
@@ -2194,6 +2264,7 @@ START_TEST(shlexec)
     test_dde();
     test_dde_default_app();
     test_commandline();
+    test_directory();
 
     cleanup_test();
 }
diff --git a/rostests/winetests/shell32/shlfileop.c b/rostests/winetests/shell32/shlfileop.c
index 3e9a2e49e14..f1e2a3ed18e 100644
--- a/rostests/winetests/shell32/shlfileop.c
+++ b/rostests/winetests/shell32/shlfileop.c
@@ -820,6 +820,7 @@ static void test_copy(void)
     DWORD retval;
     LPSTR ptr;
     BOOL on_nt4 = FALSE;
+    BOOL ret;
 
     if (old_shell32)
     {
@@ -973,16 +974,16 @@ static void test_copy(void)
     shfo.pTo = "test2.txt\0";
     /* suppress the error-dialog in win9x here */
     shfo.fFlags = FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT;
-    ok(SetFileAttributesA(shfo.pTo, FILE_ATTRIBUTE_READONLY),
-        "Failure to set file attributes (error %x)\n", GetLastError());
+    ret = SetFileAttributesA(shfo.pTo, FILE_ATTRIBUTE_READONLY);
+    ok(ret, "Failure to set file attributes (error %x)\n", GetLastError());
     retval = CopyFileA(shfo.pFrom, shfo.pTo, FALSE);
     ok(!retval && GetLastError() == ERROR_ACCESS_DENIED, "CopyFileA should have fail with ERROR_ACCESS_DENIED\n");
     retval = SHFileOperationA(&shfo);
     /* Does not work on Win95, Win95B, NT4WS and NT4SRV */
     ok(!retval || broken(retval == DE_OPCANCELLED), "SHFileOperationA failed to copy (error %x)\n", retval);
     /* Set back normal attributes to make the file deletion succeed */
-    ok(SetFileAttributesA(shfo.pTo, FILE_ATTRIBUTE_NORMAL),
-        "Failure to set file attributes (error %x)\n", GetLastError());
+    ret = SetFileAttributesA(shfo.pTo, FILE_ATTRIBUTE_NORMAL);
+    ok(ret, "Failure to set file attributes (error %x)\n", GetLastError());
     shfo.fFlags = tmp_flags;
 
     /* try to copy files to a file */
@@ -1715,11 +1716,11 @@ static void test_copy(void)
     {
         ok(DeleteFileA("threedir\\two.txt"), "Expected file to exist\n");
         ok(!DeleteFileA("fourdir"), "Expected file to not exist\n");
-        ok(!RemoveDirectoryA("fourdir"), "Expected dit to not exist\n");
+        ok(!RemoveDirectoryA("fourdir"), "Expected dir to not exist\n");
     }
     ok(RemoveDirectoryA("threedir"), "Expected dir to exist\n");
     ok(!DeleteFileA("five"), "Expected file to not exist\n");
-    ok(!RemoveDirectoryA("five"), "Expected dit to not exist\n");
+    ok(!RemoveDirectoryA("five"), "Expected dir to not exist\n");
 
     createTestFile("aa.txt");
     createTestFile("ab.txt");
@@ -2057,6 +2058,7 @@ static void test_sh_create_dir(void)
     ok(ERROR_ALREADY_EXISTS == ret, "SHCreateDirectoryEx should fail to create existing directory, ret = %d\n", ret);
 
     ret = pSHCreateDirectoryExA(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");
 }
 
@@ -2065,6 +2067,7 @@ static void test_sh_path_prepare(void)
     HRESULT res;
     CHAR path[MAX_PATH];
     CHAR UNICODE_PATH_A[MAX_PATH];
+    BOOL UsedDefaultChar;
 
     if(!pSHPathPrepareForWriteA)
     {
@@ -2156,7 +2159,19 @@ static void test_sh_path_prepare(void)
         win_skip("Skipping SHPathPrepareForWriteW tests\n");
         return;
     }
-    WideCharToMultiByte(CP_ACP, 0, UNICODE_PATH, -1, UNICODE_PATH_A, sizeof(UNICODE_PATH_A), NULL, NULL);
+
+    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)
+    {
+        win_skip("Could not convert Unicode path name to multibyte (%d)\n", GetLastError());
+        return;
+    }
+    if (UsedDefaultChar)
+    {
+        win_skip("Could not find unique multibyte representation for directory name using default codepage\n");
+        return;
+    }
 
     /* unicode directory doesn't exist, SHPPFW_NONE */
     RemoveDirectoryA(UNICODE_PATH_A);
diff --git a/rostests/winetests/shell32/shlfolder.c b/rostests/winetests/shell32/shlfolder.c
index 085c91e064e..fb634b45348 100644
--- a/rostests/winetests/shell32/shlfolder.c
+++ b/rostests/winetests/shell32/shlfolder.c
@@ -39,6 +39,9 @@
 
 #include "wine/test.h"
 
+#include <initguid.h>
+DEFINE_GUID(IID_IParentAndItem, 0xB3A4B685, 0xB685, 0x4805, 0x99,0xD9, 0x5D,0xEA,0xD2,0x87,0x32,0x36);
+DEFINE_GUID(CLSID_ShellDocObjView, 0xe7e4bc40, 0xe76a, 0x11ce, 0xa9,0xbb, 0x00,0xaa,0x00,0x4a,0xe8,0x37);
 
 static IMalloc *ppM;
 
@@ -46,15 +49,56 @@ static HRESULT (WINAPI *pSHBindToParent)(LPCITEMIDLIST, REFIID, LPVOID*, LPCITEM
 static HRESULT (WINAPI *pSHGetFolderPathA)(HWND, int, HANDLE, DWORD, LPSTR);
 static HRESULT (WINAPI *pSHGetFolderPathAndSubDirA)(HWND, int, HANDLE, DWORD, LPCSTR, LPSTR);
 static BOOL (WINAPI *pSHGetPathFromIDListW)(LPCITEMIDLIST,LPWSTR);
+static HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
 static BOOL (WINAPI *pSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL);
 static BOOL (WINAPI *pSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL);
 static HRESULT (WINAPI *pStrRetToBufW)(STRRET*,LPCITEMIDLIST,LPWSTR,UINT);
 static LPITEMIDLIST (WINAPI *pILFindLastID)(LPCITEMIDLIST);
 static void (WINAPI *pILFree)(LPITEMIDLIST);
 static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
+static HRESULT (WINAPI *pSHCreateItemFromIDList)(PCIDLIST_ABSOLUTE pidl, REFIID riid, void **ppv);
+static HRESULT (WINAPI *pSHCreateItemFromParsingName)(PCWSTR,IBindCtx*,REFIID,void**);
 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
+static HRESULT (WINAPI *pSHCreateShellItemArray)(LPCITEMIDLIST,IShellFolder*,UINT,LPCITEMIDLIST*,IShellItemArray**);
+static HRESULT (WINAPI *pSHCreateShellItemArrayFromDataObject)(IDataObject*, REFIID, void **);
+static HRESULT (WINAPI *pSHCreateShellItemArrayFromShellItem)(IShellItem*, REFIID, void **);
 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
+static LPITEMIDLIST (WINAPI *pSHSimpleIDListFromPathAW)(LPCVOID);
+static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
+static HRESULT (WINAPI *pSHGetItemFromDataObject)(IDataObject*,DATAOBJ_GET_ITEM_FLAGS,REFIID,void**);
+static HRESULT (WINAPI *pSHGetIDListFromObject)(IUnknown*, PIDLIST_ABSOLUTE*);
+static HRESULT (WINAPI *pSHGetItemFromObject)(IUnknown*,REFIID,void**);
+static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
+static UINT (WINAPI *pGetSystemWow64DirectoryW)(LPWSTR, UINT);
+static HRESULT (WINAPI *pSHCreateDefaultContextMenu)(const DEFCONTEXTMENU*,REFIID,void**);
+
+static WCHAR *make_wstr(const char *str)
+{
+    WCHAR *ret;
+    int len;
+
+    if(!str || strlen(str) == 0)
+        return NULL;
+
+    len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
+    if(!len || len < 0)
+        return NULL;
+
+    ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if(!ret)
+        return NULL;
+
+    MultiByteToWideChar(CP_ACP, 0, str, -1, ret, len);
+    return ret;
+}
+
+static int strcmp_wa(LPCWSTR strw, const char *stra)
+{
+    CHAR buf[512];
+    WideCharToMultiByte(CP_ACP, 0, strw, -1, buf, sizeof(buf), NULL, NULL);
+    return lstrcmpA(stra, buf);
+}
 
 static void init_function_pointers(void)
 {
@@ -66,13 +110,24 @@ static void init_function_pointers(void)
 
 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hmod, #f))
     MAKEFUNC(SHBindToParent);
+    MAKEFUNC(SHCreateItemFromIDList);
+    MAKEFUNC(SHCreateItemFromParsingName);
     MAKEFUNC(SHCreateShellItem);
+    MAKEFUNC(SHCreateShellItemArray);
+    MAKEFUNC(SHCreateShellItemArrayFromDataObject);
+    MAKEFUNC(SHCreateShellItemArrayFromShellItem);
     MAKEFUNC(SHGetFolderPathA);
     MAKEFUNC(SHGetFolderPathAndSubDirA);
     MAKEFUNC(SHGetPathFromIDListW);
     MAKEFUNC(SHGetSpecialFolderPathA);
     MAKEFUNC(SHGetSpecialFolderPathW);
+    MAKEFUNC(SHGetSpecialFolderLocation);
     MAKEFUNC(SHParseDisplayName);
+    MAKEFUNC(SHGetNameFromIDList);
+    MAKEFUNC(SHGetItemFromDataObject);
+    MAKEFUNC(SHGetIDListFromObject);
+    MAKEFUNC(SHGetItemFromObject);
+    MAKEFUNC(SHCreateDefaultContextMenu);
 #undef MAKEFUNC
 
 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
@@ -80,6 +135,7 @@ static void init_function_pointers(void)
     MAKEFUNC_ORD(ILIsEqual, 21);
     MAKEFUNC_ORD(ILCombine, 25);
     MAKEFUNC_ORD(ILFree, 155);
+    MAKEFUNC_ORD(SHSimpleIDListFromPathAW, 162);
 #undef MAKEFUNC_ORD
 
     /* test named exports */
@@ -112,10 +168,34 @@ static void init_function_pointers(void)
     hmod = GetModuleHandleA("shlwapi.dll");
     pStrRetToBufW = (void*)GetProcAddress(hmod, "StrRetToBufW");
 
+    hmod = GetModuleHandleA("kernel32.dll");
+    pIsWow64Process = (void*)GetProcAddress(hmod, "IsWow64Process");
+    pGetSystemWow64DirectoryW = (void*)GetProcAddress(hmod, "GetSystemWow64DirectoryW");
+
     hr = SHGetMalloc(&ppM);
     ok(hr == S_OK, "SHGetMalloc failed %08x\n", hr);
 }
 
+/* Based on PathAddBackslashW from dlls/shlwapi/path.c */
+static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
+{
+  size_t iLen;
+
+  if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
+    return NULL;
+
+  if (iLen)
+  {
+    lpszPath += iLen;
+    if (lpszPath[-1] != '\\')
+    {
+      *lpszPath++ = '\\';
+      *lpszPath = '\0';
+    }
+  }
+  return lpszPath;
+}
+
 static void test_ParseDisplayName(void)
 {
     HRESULT hr;
@@ -361,12 +441,19 @@ static void test_BindToObject(void)
     UINT cChars;
     IShellFolder *psfDesktop, *psfChild, *psfMyComputer, *psfSystemDir;
     SHITEMID emptyitem = { 0, { 0 } };
-    LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidlEmpty = (LPITEMIDLIST)&emptyitem;
+    LPITEMIDLIST pidlMyComputer, pidlSystemDir, pidl, pidlEmpty = (LPITEMIDLIST)&emptyitem;
     WCHAR wszSystemDir[MAX_PATH];
     char szSystemDir[MAX_PATH];
+    char buf[MAX_PATH];
+    WCHAR path[MAX_PATH];
+    CHAR pathA[MAX_PATH];
+    HANDLE hfile;
     WCHAR wszMyComputer[] = { 
         ':',':','{','2','0','D','0','4','F','E','0','-','3','A','E','A','-','1','0','6','9','-',
         'A','2','D','8','-','0','8','0','0','2','B','3','0','3','0','9','D','}',0 };
+    static const CHAR filename_html[] = "winetest.html";
+    static const CHAR filename_txt[] = "winetest.txt";
+    static const CHAR filename_foo[] = "winetest.foo";
 
     /* The following tests shows that BindToObject should fail with E_INVALIDARG if called
      * with an empty pidl. This is tested for Desktop, MyComputer and the FS ShellFolder
@@ -438,26 +525,168 @@ if (0)
 }
 
     IShellFolder_Release(psfSystemDir);
-}
 
-/* Based on PathAddBackslashW from dlls/shlwapi/path.c */
-static LPWSTR myPathAddBackslashW( LPWSTR lpszPath )
-{
-  size_t iLen;
-
-  if (!lpszPath || (iLen = lstrlenW(lpszPath)) >= MAX_PATH)
-    return NULL;
-
-  if (iLen)
-  {
-    lpszPath += iLen;
-    if (lpszPath[-1] != '\\')
+    GetCurrentDirectoryA(MAX_PATH, buf);
+    if(!lstrlenA(buf))
     {
-      *lpszPath++ = '\\';
-      *lpszPath = '\0';
+        skip("Failed to get current directory, skipping tests.\n");
+        return;
     }
-  }
-  return lpszPath;
+
+    SHGetDesktopFolder(&psfDesktop);
+
+    /* Attempt BindToObject on files. */
+
+    /* .html */
+    lstrcpyA(pathA, buf);
+    lstrcatA(pathA, "\\");
+    lstrcatA(pathA, filename_html);
+    hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+    if(hfile != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hfile);
+        MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
+        hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
+            ok(hr == S_OK ||
+               hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
+               "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                IPersist *pp;
+                hr = IShellFolder_QueryInterface(psfChild, &IID_IPersist, (void**)&pp);
+                ok(hr == S_OK ||
+                   broken(hr == E_NOINTERFACE), /* Win9x, NT4, W2K */
+                   "Got 0x%08x\n", hr);
+                if(SUCCEEDED(hr))
+                {
+                    CLSID id;
+                    hr = IPersist_GetClassID(pp, &id);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    ok(IsEqualIID(&id, &CLSID_ShellDocObjView), "Unexpected classid\n");
+                    IPersist_Release(pp);
+                }
+
+                IShellFolder_Release(psfChild);
+            }
+            pILFree(pidl);
+        }
+        DeleteFileA(pathA);
+    }
+    else
+        win_skip("Failed to create .html testfile.\n");
+
+    /* .txt */
+    lstrcpyA(pathA, buf);
+    lstrcatA(pathA, "\\");
+    lstrcatA(pathA, filename_txt);
+    hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+    if(hfile != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hfile);
+        MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
+        hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
+            ok(hr == E_FAIL || /* Vista+ */
+               hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
+               broken(hr == S_OK), /* Win9x, NT4, W2K */
+               "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
+            pILFree(pidl);
+        }
+        DeleteFileA(pathA);
+    }
+    else
+        win_skip("Failed to create .txt testfile.\n");
+
+    /* .foo */
+    lstrcpyA(pathA, buf);
+    lstrcatA(pathA, "\\");
+    lstrcatA(pathA, filename_foo);
+    hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+    if(hfile != INVALID_HANDLE_VALUE)
+    {
+        CloseHandle(hfile);
+        MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
+        hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
+            ok(hr == E_FAIL || /* Vista+ */
+               hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
+               broken(hr == S_OK), /* Win9x, NT4, W2K */
+               "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
+            pILFree(pidl);
+        }
+        DeleteFileA(pathA);
+    }
+    else
+        win_skip("Failed to create .foo testfile.\n");
+
+    /* And on the desktop */
+    if(pSHGetSpecialFolderPathA)
+    {
+        pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
+        lstrcatA(pathA, "\\");
+        lstrcatA(pathA, filename_html);
+        hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+        if(hfile != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle(hfile);
+            MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
+            hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
+                ok(hr == S_OK ||
+                   hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), /* XP, W2K3 */
+                   "Got 0x%08x\n", hr);
+                if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
+                pILFree(pidl);
+            }
+            if(!DeleteFileA(pathA))
+                trace("Failed to delete: %d\n", GetLastError());
+
+        }
+        else
+            win_skip("Failed to create .html testfile.\n");
+
+        pSHGetSpecialFolderPathA(NULL, pathA, CSIDL_DESKTOP, FALSE);
+        lstrcatA(pathA, "\\");
+        lstrcatA(pathA, filename_foo);
+        hfile = CreateFileA(pathA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+        if(hfile != INVALID_HANDLE_VALUE)
+        {
+            CloseHandle(hfile);
+            MultiByteToWideChar(CP_ACP, 0, pathA, -1, path, MAX_PATH);
+            hr = IShellFolder_ParseDisplayName(psfDesktop, NULL, NULL, path, NULL, &pidl, NULL);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                hr = IShellFolder_BindToObject(psfDesktop, pidl, NULL, &IID_IShellFolder, (void**)&psfChild);
+                ok(hr == E_FAIL || /* Vista+ */
+                   hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) || /* XP, W2K3 */
+                   broken(hr == S_OK), /* Win9x, NT4, W2K */
+                   "Got 0x%08x\n", hr);
+                if(SUCCEEDED(hr)) IShellFolder_Release(psfChild);
+                pILFree(pidl);
+            }
+            DeleteFileA(pathA);
+        }
+        else
+            win_skip("Failed to create .foo testfile.\n");
+    }
+
+    IShellFolder_Release(psfDesktop);
 }
 
 static void test_GetDisplayName(void)
@@ -548,7 +777,6 @@ static void test_GetDisplayName(void)
     /* It seems as if we cannot bind to regular files on windows, but only directories. 
      */
     hr = IShellFolder_BindToObject(psfDesktop, pidlTestFile, NULL, &IID_IUnknown, (VOID**)&psfFile);
-    todo_wine
     ok (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) ||
         hr == E_NOTIMPL || /* Vista */
         broken(hr == S_OK), /* Win9x, W2K */
@@ -985,9 +1213,7 @@ static void test_SHGetPathFromIDList(void)
     STRRET strret;
     static WCHAR wszTestFile[] = {
         'w','i','n','e','t','e','s','t','.','f','o','o',0 };
-	HRESULT (WINAPI *pSHGetSpecialFolderLocation)(HWND, int, LPITEMIDLIST *);
-	HMODULE hShell32;
-	LPITEMIDLIST pidlPrograms;
+    LPITEMIDLIST pidlPrograms;
 
     if(!pSHGetPathFromIDListW || !pSHGetSpecialFolderPathW)
     {
@@ -1099,10 +1325,7 @@ static void test_SHGetPathFromIDList(void)
     ok(0 == lstrcmpW(wszFileName, wszPath), "SHGetPathFromIDListW returned incorrect path for file placed on desktop\n");
 
 
-	/* Test if we can get the path from the start menu "program files" PIDL. */
-    hShell32 = GetModuleHandleA("shell32");
-    pSHGetSpecialFolderLocation = (void *)GetProcAddress(hShell32, "SHGetSpecialFolderLocation");
-
+    /* Test if we can get the path from the start menu "program files" PIDL. */
     hr = pSHGetSpecialFolderLocation(NULL, CSIDL_PROGRAM_FILES, &pidlPrograms);
     ok(hr == S_OK, "SHGetFolderLocation failed: 0x%08x\n", hr);
 
@@ -1555,7 +1778,7 @@ static void test_ITEMIDLIST_format(void) {
             /* WinXP stores a derived 8.3 dos name (LONGER~1.8_3) here. We probably
              * can't implement this correctly, since unix filesystems don't support
              * this nasty short/long filename stuff. So we'll probably stay with our
-             * current habbit of storing the long filename here, which seems to work
+             * current habit of storing the long filename here, which seems to work
              * just fine. */
             todo_wine
             ok(pidlFile->mkid.abID[18] == '~' ||
@@ -1632,6 +1855,93 @@ static void test_ITEMIDLIST_format(void) {
     IShellFolder_Release(psfPersonal);
 }
 
+static void test_SHGetFolderPathA(void)
+{
+    static const BOOL is_win64 = sizeof(void *) > sizeof(int);
+    BOOL is_wow64;
+    char path[MAX_PATH];
+    char path_x86[MAX_PATH];
+    char path_key[MAX_PATH];
+    HRESULT hr;
+    HKEY key;
+
+    if (!pSHGetFolderPathA)
+    {
+        win_skip("SHGetFolderPathA not present\n");
+        return;
+    }
+    if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
+
+    hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES, 0, SHGFP_TYPE_CURRENT, path );
+    ok( !hr, "SHGetFolderPathA failed %x\n", hr );
+    hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILESX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
+    if (hr == E_FAIL)
+    {
+        win_skip( "Program Files (x86) not supported\n" );
+        return;
+    }
+    ok( !hr, "SHGetFolderPathA failed %x\n", hr );
+    if (is_win64)
+    {
+        ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
+        ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
+        ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
+    }
+    else
+    {
+        ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
+        if (is_wow64)
+            ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
+        else
+            ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
+    }
+    if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
+    {
+        DWORD type, count = sizeof(path_x86);
+        if (!RegQueryValueExA( key, "ProgramFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
+        {
+            ok( is_win64 || is_wow64, "ProgramFilesDir (x86) exists on 32-bit setup\n" );
+            ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
+        }
+        else ok( !is_win64 && !is_wow64, "ProgramFilesDir (x86) should exist on 64-bit setup\n" );
+        RegCloseKey( key );
+    }
+
+    hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMON, 0, SHGFP_TYPE_CURRENT, path );
+    ok( !hr, "SHGetFolderPathA failed %x\n", hr );
+    hr = pSHGetFolderPathA( 0, CSIDL_PROGRAM_FILES_COMMONX86, 0, SHGFP_TYPE_CURRENT, path_x86 );
+    if (hr == E_FAIL)
+    {
+        win_skip( "Common Files (x86) not supported\n" );
+        return;
+    }
+    ok( !hr, "SHGetFolderPathA failed %x\n", hr );
+    if (is_win64)
+    {
+        ok( lstrcmpiA( path, path_x86 ), "paths are identical '%s'\n", path );
+        ok( strstr( path, "x86" ) == NULL, "64-bit path '%s' contains x86\n", path );
+        ok( strstr( path_x86, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path_x86 );
+    }
+    else
+    {
+        ok( !lstrcmpiA( path, path_x86 ), "paths differ '%s' != '%s'\n", path, path_x86 );
+        if (is_wow64)
+            ok( strstr( path, "x86" ) != NULL, "32-bit path '%s' doesn't contain x86\n", path );
+        else
+            ok( strstr( path, "x86" ) == NULL, "32-bit path '%s' contains x86\n", path );
+    }
+    if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion", &key ))
+    {
+        DWORD type, count = sizeof(path_x86);
+        if (!RegQueryValueExA( key, "CommonFilesDir (x86)", NULL, &type, (BYTE *)path_key, &count ))
+        {
+            ok( is_win64 || is_wow64, "CommonFilesDir (x86) exists on 32-bit setup\n" );
+            ok( !lstrcmpiA( path_key, path_x86 ), "paths differ '%s' != '%s'\n", path_key, path_x86 );
+        }
+        else ok( !is_win64 && !is_wow64, "CommonFilesDir (x86) should exist on 64-bit setup\n" );
+    }
+}
+
 static void test_SHGetFolderPathAndSubDirA(void)
 {
     HRESULT ret;
@@ -1756,6 +2066,7 @@ static void test_LocalizedNames(void)
     DWORD res;
     HANDLE file;
     STRRET strret;
+    BOOL ret;
 
     static const char desktopini_contents1[] =
         "[.ShellClassInfo]\r\n"
@@ -1775,10 +2086,10 @@ static void test_LocalizedNames(void)
     file = CreateFileA(".\\testfolder\\desktop.ini", GENERIC_WRITE, 0, NULL,
                          CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     ok(file != INVALID_HANDLE_VALUE, "CreateFileA failed %i\n", GetLastError());
-    ok(WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
-       WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
-       WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL),
-       "WriteFile failed %i\n", GetLastError());
+    ret = WriteFile(file, desktopini_contents1, strlen(desktopini_contents1), &res, NULL) &&
+          WriteFile(file, resourcefile, strlen(resourcefile), &res, NULL) &&
+          WriteFile(file, desktopini_contents2, strlen(desktopini_contents2), &res, NULL);
+    ok(ret, "WriteFile failed %i\n", GetLastError());
     CloseHandle(file);
 
     /* get IShellFolder for parent */
@@ -1862,10 +2173,11 @@ static void test_SHCreateShellItem(void)
 {
     IShellItem *shellitem, *shellitem2;
     IPersistIDList *persistidl;
-    LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test;
+    LPITEMIDLIST pidl_cwd=NULL, pidl_testfile, pidl_abstestfile, pidl_test, pidl_desktop;
     HRESULT ret;
     char curdirA[MAX_PATH];
     WCHAR curdirW[MAX_PATH];
+    WCHAR fnbufW[MAX_PATH];
     IShellFolder *desktopfolder=NULL, *currentfolder=NULL;
     static WCHAR testfileW[] = {'t','e','s','t','f','i','l','e',0};
 
@@ -1883,6 +2195,17 @@ static void test_SHCreateShellItem(void)
         return;
     }
 
+    if(pSHGetSpecialFolderLocation)
+    {
+        ret = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
+        ok(ret == S_OK, "Got 0x%08x\n", ret);
+    }
+    else
+    {
+        win_skip("pSHGetSpecialFolderLocation missing.\n");
+        pidl_desktop = NULL;
+    }
+
     MultiByteToWideChar(CP_ACP, 0, curdirA, -1, curdirW, MAX_PATH);
 
     ret = SHGetDesktopFolder(&desktopfolder);
@@ -2014,14 +2337,1394 @@ static void test_SHCreateShellItem(void)
         IShellItem_Release(shellitem);
     }
 
+    ret = pSHCreateShellItem(NULL, desktopfolder, pidl_testfile, &shellitem);
+    ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
+    if (SUCCEEDED(ret))
+    {
+        ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
+        ok(SUCCEEDED(ret), "QueryInterface returned %x\n", ret);
+        if (SUCCEEDED(ret))
+        {
+            ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
+            ok(SUCCEEDED(ret), "GetIDList returned %x\n", ret);
+            if (SUCCEEDED(ret))
+            {
+                ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
+                pILFree(pidl_test);
+            }
+            IPersistIDList_Release(persistidl);
+        }
+
+        IShellItem_Release(shellitem);
+    }
+
+    ret = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
+    ok(SUCCEEDED(ret), "SHCreateShellItem returned %x\n", ret);
+    if (SUCCEEDED(ret))
+    {
+        ret = IShellItem_GetParent(shellitem, &shellitem2);
+        ok(FAILED(ret), "Got 0x%08x\n", ret);
+        if(SUCCEEDED(ret)) IShellItem_Release(shellitem2);
+        IShellItem_Release(shellitem);
+    }
+
+    /* SHCreateItemFromParsingName */
+    if(pSHCreateItemFromParsingName)
+    {
+        if(0)
+        {
+            /* Crashes under windows 7 */
+            pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, NULL);
+        }
+
+        shellitem = (void*)0xdeadbeef;
+        ret = pSHCreateItemFromParsingName(NULL, NULL, &IID_IShellItem, (void**)&shellitem);
+        ok(ret == E_INVALIDARG, "SHCreateItemFromParsingName returned %x\n", ret);
+        ok(shellitem == NULL, "shellitem was %p.\n", shellitem);
+
+        ret = pSHCreateItemFromParsingName(testfileW, NULL, &IID_IShellItem, (void**)&shellitem);
+        ok(ret == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND),
+           "SHCreateItemFromParsingName returned %x\n", ret);
+        if(SUCCEEDED(ret)) IShellItem_Release(shellitem);
+
+        lstrcpyW(fnbufW, curdirW);
+        myPathAddBackslashW(fnbufW);
+        lstrcatW(fnbufW, testfileW);
+
+        ret = pSHCreateItemFromParsingName(fnbufW, NULL, &IID_IShellItem, (void**)&shellitem);
+        ok(ret == S_OK, "SHCreateItemFromParsingName returned %x\n", ret);
+        if(SUCCEEDED(ret))
+        {
+            LPWSTR tmp_fname;
+            ret = IShellItem_GetDisplayName(shellitem, SIGDN_FILESYSPATH, &tmp_fname);
+            ok(ret == S_OK, "GetDisplayName returned %x\n", ret);
+            if(SUCCEEDED(ret))
+            {
+                ok(!lstrcmpW(fnbufW, tmp_fname), "strings not equal\n");
+                CoTaskMemFree(tmp_fname);
+            }
+            IShellItem_Release(shellitem);
+        }
+    }
+    else
+        win_skip("No SHCreateItemFromParsingName\n");
+
+
+    /* SHCreateItemFromIDList */
+    if(pSHCreateItemFromIDList)
+    {
+        if(0)
+        {
+            /* Crashes under win7 */
+            pSHCreateItemFromIDList(NULL, &IID_IShellItem, NULL);
+        }
+
+        ret = pSHCreateItemFromIDList(NULL, &IID_IShellItem, (void**)&shellitem);
+        ok(ret == E_INVALIDARG, "SHCreateItemFromIDList returned %x\n", ret);
+
+        ret = pSHCreateItemFromIDList(pidl_cwd, &IID_IShellItem, (void**)&shellitem);
+        ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
+        if (SUCCEEDED(ret))
+        {
+            ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
+            ok(ret == S_OK, "QueryInterface returned %x\n", ret);
+            if (SUCCEEDED(ret))
+            {
+                ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
+                ok(ret == S_OK, "GetIDList returned %x\n", ret);
+                if (SUCCEEDED(ret))
+                {
+                    ok(ILIsEqual(pidl_cwd, pidl_test), "id lists are not equal\n");
+                    pILFree(pidl_test);
+                }
+                IPersistIDList_Release(persistidl);
+            }
+            IShellItem_Release(shellitem);
+        }
+
+        ret = pSHCreateItemFromIDList(pidl_testfile, &IID_IShellItem, (void**)&shellitem);
+        ok(ret == S_OK, "SHCreateItemFromIDList returned %x\n", ret);
+        if (SUCCEEDED(ret))
+        {
+            ret = IShellItem_QueryInterface(shellitem, &IID_IPersistIDList, (void**)&persistidl);
+            ok(ret == S_OK, "QueryInterface returned %x\n", ret);
+            if (SUCCEEDED(ret))
+            {
+                ret = IPersistIDList_GetIDList(persistidl, &pidl_test);
+                ok(ret == S_OK, "GetIDList returned %x\n", ret);
+                if (SUCCEEDED(ret))
+                {
+                    ok(ILIsEqual(pidl_testfile, pidl_test), "id lists are not equal\n");
+                    pILFree(pidl_test);
+                }
+                IPersistIDList_Release(persistidl);
+            }
+            IShellItem_Release(shellitem);
+        }
+    }
+    else
+        win_skip("No SHCreateItemFromIDList\n");
+
     DeleteFileA(".\\testfile");
     pILFree(pidl_abstestfile);
     pILFree(pidl_testfile);
+    pILFree(pidl_desktop);
     pILFree(pidl_cwd);
     IShellFolder_Release(currentfolder);
     IShellFolder_Release(desktopfolder);
 }
 
+static void test_SHGetNameFromIDList(void)
+{
+    IShellItem *shellitem;
+    LPITEMIDLIST pidl;
+    LPWSTR name_string;
+    HRESULT hres;
+    UINT i;
+    static const DWORD flags[] = {
+        SIGDN_NORMALDISPLAY, SIGDN_PARENTRELATIVEPARSING,
+        SIGDN_DESKTOPABSOLUTEPARSING,SIGDN_PARENTRELATIVEEDITING,
+        SIGDN_DESKTOPABSOLUTEEDITING, /*SIGDN_FILESYSPATH, SIGDN_URL, */
+        SIGDN_PARENTRELATIVEFORADDRESSBAR,SIGDN_PARENTRELATIVE, -1234};
+
+    if(!pSHGetNameFromIDList)
+    {
+        win_skip("SHGetNameFromIDList missing.\n");
+        return;
+    }
+
+    /* These should be available on any platform that passed the above test. */
+    ok(pSHCreateShellItem != NULL, "SHCreateShellItem missing.\n");
+    ok(pSHBindToParent != NULL, "SHBindToParent missing.\n");
+    ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
+    ok(pStrRetToBufW != NULL, "StrRetToBufW missing.\n");
+
+    if(0)
+    {
+        /* Crashes under win7 */
+        pSHGetNameFromIDList(NULL, 0, NULL);
+    }
+
+    hres = pSHGetNameFromIDList(NULL, 0, &name_string);
+    ok(hres == E_INVALIDARG, "Got 0x%08x\n", hres);
+
+    /* Test the desktop */
+    hres = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
+    ok(hres == S_OK, "Got 0x%08x\n", hres);
+    hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
+    ok(hres == S_OK, "Got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        WCHAR *nameSI, *nameSH;
+        WCHAR buf[MAX_PATH];
+        HRESULT hrSI, hrSH, hrSF;
+        STRRET strret;
+        IShellFolder *psf;
+        BOOL res;
+
+        SHGetDesktopFolder(&psf);
+        for(i = 0; flags[i] != -1234; i++)
+        {
+            hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
+            ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
+            hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
+            ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
+            hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
+            ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
+
+            if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
+                ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
+
+            if(SUCCEEDED(hrSF))
+            {
+                pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
+                if(SUCCEEDED(hrSI))
+                    ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
+                if(SUCCEEDED(hrSF))
+                    ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
+            }
+            if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
+            if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
+        }
+        IShellFolder_Release(psf);
+
+        if(pSHGetPathFromIDListW){
+            hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
+            ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
+            res = pSHGetPathFromIDListW(pidl, buf);
+            ok(res == TRUE, "Got %d\n", res);
+            if(SUCCEEDED(hrSI) && res)
+                ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
+            if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
+        }else
+            win_skip("pSHGetPathFromIDListW not available\n");
+
+        hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
+        todo_wine ok(hres == S_OK, "Got 0x%08x\n", hres);
+        if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
+
+        IShellItem_Release(shellitem);
+    }
+    pILFree(pidl);
+
+    /* Test the control panel */
+    hres = pSHGetSpecialFolderLocation(NULL, CSIDL_CONTROLS, &pidl);
+    ok(hres == S_OK, "Got 0x%08x\n", hres);
+    hres = pSHCreateShellItem(NULL, NULL, pidl, &shellitem);
+    ok(hres == S_OK, "Got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        WCHAR *nameSI, *nameSH;
+        WCHAR buf[MAX_PATH];
+        HRESULT hrSI, hrSH, hrSF;
+        STRRET strret;
+        IShellFolder *psf;
+        BOOL res;
+
+        SHGetDesktopFolder(&psf);
+        for(i = 0; flags[i] != -1234; i++)
+        {
+            hrSI = IShellItem_GetDisplayName(shellitem, flags[i], &nameSI);
+            ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
+            hrSH = pSHGetNameFromIDList(pidl, flags[i], &nameSH);
+            ok(hrSH == S_OK, "Got 0x%08x\n", hrSH);
+            hrSF = IShellFolder_GetDisplayNameOf(psf, pidl, flags[i] & 0xffff, &strret);
+            ok(hrSF == S_OK, "Got 0x%08x\n", hrSF);
+
+            if(SUCCEEDED(hrSI) && SUCCEEDED(hrSH))
+                ok(!lstrcmpW(nameSI, nameSH), "Strings differ.\n");
+
+            if(SUCCEEDED(hrSF))
+            {
+                pStrRetToBufW(&strret, NULL, buf, MAX_PATH);
+                if(SUCCEEDED(hrSI))
+                    ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
+                if(SUCCEEDED(hrSF))
+                    ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
+            }
+            if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
+            if(SUCCEEDED(hrSH)) CoTaskMemFree(nameSH);
+        }
+        IShellFolder_Release(psf);
+
+        if(pSHGetPathFromIDListW){
+            hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
+            ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
+            res = pSHGetPathFromIDListW(pidl, buf);
+            ok(res == FALSE, "Got %d\n", res);
+            if(SUCCEEDED(hrSI) && res)
+                ok(!lstrcmpW(nameSI, buf), "Strings differ.\n");
+            if(SUCCEEDED(hrSI)) CoTaskMemFree(nameSI);
+        }else
+            win_skip("pSHGetPathFromIDListW not available\n");
+
+        hres = pSHGetNameFromIDList(pidl, SIGDN_URL, &name_string);
+        todo_wine ok(hres == E_NOTIMPL /* Win7 */ || hres == S_OK /* Vista */,
+                     "Got 0x%08x\n", hres);
+        if(SUCCEEDED(hres)) CoTaskMemFree(name_string);
+
+        IShellItem_Release(shellitem);
+    }
+    pILFree(pidl);
+}
+
+static void test_SHGetItemFromDataObject(void)
+{
+    IShellFolder *psfdesktop;
+    IShellItem *psi;
+    IShellView *psv;
+    HRESULT hres;
+
+    if(!pSHGetItemFromDataObject)
+    {
+        win_skip("No SHGetItemFromDataObject.\n");
+        return;
+    }
+
+    if(0)
+    {
+        /* Crashes under win7 */
+        pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, NULL);
+    }
+
+    hres = pSHGetItemFromDataObject(NULL, 0, &IID_IShellItem, (void**)&psv);
+    ok(hres == E_INVALIDARG, "got 0x%08x\n", hres);
+
+    SHGetDesktopFolder(&psfdesktop);
+
+    hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        IEnumIDList *peidl;
+        IDataObject *pdo;
+        SHCONTF enum_flags;
+
+        enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
+        hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            LPITEMIDLIST apidl[5];
+            UINT count = 0, i;
+
+            for(count = 0; count < 5; count++)
+                if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
+                    break;
+
+            if(count)
+            {
+                hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
+                                                  &IID_IDataObject, NULL, (void**)&pdo);
+                ok(hres == S_OK, "got 0x%08x\n", hres);
+                if(SUCCEEDED(hres))
+                {
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+
+                    IDataObject_Release(pdo);
+                }
+            }
+            else
+                skip("No file(s) found - skipping single-file test.\n");
+
+            if(count > 1)
+            {
+                hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
+                                                  &IID_IDataObject, NULL, (void**)&pdo);
+                ok(hres == S_OK, "got 0x%08x\n", hres);
+                if(SUCCEEDED(hres))
+                {
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_DEFAULT, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_TRAVERSE_LINK, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_HDROP, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_NO_URL, &IID_IShellItem, (void**)&psi);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    hres = pSHGetItemFromDataObject(pdo, DOGIF_ONLY_IF_ONE, &IID_IShellItem, (void**)&psi);
+                    ok(hres == E_FAIL, "got 0x%08x\n", hres);
+                    if(SUCCEEDED(hres)) IShellItem_Release(psi);
+                    IDataObject_Release(pdo);
+                }
+            }
+            else
+                skip("zero or one file found - skipping multi-file test.\n");
+
+            for(i = 0; i < count; i++)
+                pILFree(apidl[i]);
+
+            IEnumIDList_Release(peidl);
+        }
+
+        IShellView_Release(psv);
+    }
+
+    IShellFolder_Release(psfdesktop);
+}
+
+static void test_ShellItemCompare(void)
+{
+    IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */
+    IShellItem *psi_a = NULL, *psi_b = NULL, *psi_c = NULL;
+    IShellFolder *psf_desktop, *psf_current;
+    LPITEMIDLIST pidl_cwd;
+    WCHAR curdirW[MAX_PATH];
+    BOOL failed;
+    HRESULT hr;
+    static const WCHAR filesW[][9] = {
+        {'a','\\','a',0}, {'a','\\','b',0}, {'a','\\','c',0},
+        {'b','\\','a',0}, {'b','\\','b',0}, {'b','\\','c',0},
+        {'c','\\','a',0}, {'c','\\','b',0}, {'c','\\','c',0} };
+    int order;
+    UINT i;
+
+    if(!pSHCreateShellItem)
+    {
+        win_skip("SHCreateShellItem missing.\n");
+        return;
+    }
+
+    GetCurrentDirectoryW(MAX_PATH, curdirW);
+    if(!lstrlenW(curdirW))
+    {
+        skip("Failed to get current directory, skipping.\n");
+        return;
+    }
+
+    CreateDirectoryA(".\\a", NULL);
+    CreateDirectoryA(".\\b", NULL);
+    CreateDirectoryA(".\\c", NULL);
+    CreateTestFile(".\\a\\a");
+    CreateTestFile(".\\a\\b");
+    CreateTestFile(".\\a\\c");
+    CreateTestFile(".\\b\\a");
+    CreateTestFile(".\\b\\b");
+    CreateTestFile(".\\b\\c");
+    CreateTestFile(".\\c\\a");
+    CreateTestFile(".\\c\\b");
+    CreateTestFile(".\\c\\c");
+
+    SHGetDesktopFolder(&psf_desktop);
+    hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, curdirW, NULL, &pidl_cwd, NULL);
+    ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
+    hr = IShellFolder_BindToObject(psf_desktop, pidl_cwd, NULL, &IID_IShellFolder, (void**)&psf_current);
+    ok(SUCCEEDED(hr), "BindToObject returned %x\n", hr);
+    IShellFolder_Release(psf_desktop);
+    ILFree(pidl_cwd);
+
+    /* Generate ShellItems for the files */
+    memset(&psi, 0, sizeof(psi));
+    failed = FALSE;
+    for(i = 0; i < 9; i++)
+    {
+        LPITEMIDLIST pidl_testfile = NULL;
+
+        hr = IShellFolder_ParseDisplayName(psf_current, NULL, NULL, (LPWSTR)filesW[i],
+                                           NULL, &pidl_testfile, NULL);
+        ok(SUCCEEDED(hr), "ParseDisplayName returned %x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = pSHCreateShellItem(NULL, NULL, pidl_testfile, &psi[i]);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            pILFree(pidl_testfile);
+        }
+        if(FAILED(hr)) failed = TRUE;
+    }
+    if(failed)
+    {
+        skip("Failed to create all shellitems.\n");
+        goto cleanup;
+    }
+
+    /* Generate ShellItems for the folders */
+    hr = IShellItem_GetParent(psi[0], &psi_a);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(FAILED(hr)) failed = TRUE;
+    hr = IShellItem_GetParent(psi[3], &psi_b);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(FAILED(hr)) failed = TRUE;
+    hr = IShellItem_GetParent(psi[6], &psi_c);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(FAILED(hr)) failed = TRUE;
+
+    if(failed)
+    {
+        skip("Failed to create shellitems.\n");
+        goto cleanup;
+    }
+
+    if(0)
+    {
+        /* Crashes on native (win7, winxp) */
+        IShellItem_Compare(psi_a, NULL, 0, NULL);
+        IShellItem_Compare(psi_a, psi_b, 0, NULL);
+        IShellItem_Compare(psi_a, NULL, 0, &order);
+    }
+
+    /* Basics */
+    for(i = 0; i < 9; i++)
+    {
+        hr = IShellItem_Compare(psi[i], psi[i], SICHINT_DISPLAY, &order);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        ok(order == 0, "Got order %d\n", order);
+        hr = IShellItem_Compare(psi[i], psi[i], SICHINT_CANONICAL, &order);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        ok(order == 0, "Got order %d\n", order);
+        hr = IShellItem_Compare(psi[i], psi[i], SICHINT_ALLFIELDS, &order);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        ok(order == 0, "Got order %d\n", order);
+    }
+
+    /* Order */
+    /* a\b:a\a , a\b:a\c, a\b:a\b */
+    hr = IShellItem_Compare(psi[1], psi[0], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[1], psi[2], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[1], psi[1], SICHINT_DISPLAY, &order);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(order == 0, "Got order %d\n", order);
+
+    /* b\b:a\b, b\b:c\b, b\b:c\b */
+    hr = IShellItem_Compare(psi[4], psi[1], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[4], psi[7], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[4], psi[4], SICHINT_DISPLAY, &order);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(order == 0, "Got order %d\n", order);
+
+    /* b:a\a, b:a\c, b:a\b */
+    hr = IShellItem_Compare(psi_b, psi[0], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    todo_wine ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[2], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    todo_wine ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[1], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    todo_wine ok(order == 1, "Got order %d\n", order);
+
+    /* b:c\a, b:c\c, b:c\b */
+    hr = IShellItem_Compare(psi_b, psi[6], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[8], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[7], SICHINT_DISPLAY, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+
+    /* a\b:a\a , a\b:a\c, a\b:a\b */
+    hr = IShellItem_Compare(psi[1], psi[0], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[1], psi[2], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[1], psi[1], SICHINT_CANONICAL, &order);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(order == 0, "Got order %d\n", order);
+
+    /* b\b:a\b, b\b:c\b, b\b:c\b */
+    hr = IShellItem_Compare(psi[4], psi[1], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[4], psi[7], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi[4], psi[4], SICHINT_CANONICAL, &order);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    ok(order == 0, "Got order %d\n", order);
+
+    /* b:a\a, b:a\c, b:a\b */
+    hr = IShellItem_Compare(psi_b, psi[0], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    todo_wine ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[2], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    todo_wine ok(order == 1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[1], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    todo_wine ok(order == 1, "Got order %d\n", order);
+
+    /* b:c\a, b:c\c, b:c\b */
+    hr = IShellItem_Compare(psi_b, psi[6], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[8], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+    hr = IShellItem_Compare(psi_b, psi[7], SICHINT_CANONICAL, &order);
+    ok(hr == S_FALSE, "Got 0x%08x\n", hr);
+    ok(order == -1, "Got order %d\n", order);
+
+cleanup:
+    IShellFolder_Release(psf_current);
+
+    DeleteFileA(".\\a\\a");
+    DeleteFileA(".\\a\\b");
+    DeleteFileA(".\\a\\c");
+    DeleteFileA(".\\b\\a");
+    DeleteFileA(".\\b\\b");
+    DeleteFileA(".\\b\\c");
+    DeleteFileA(".\\c\\a");
+    DeleteFileA(".\\c\\b");
+    DeleteFileA(".\\c\\c");
+    RemoveDirectoryA(".\\a");
+    RemoveDirectoryA(".\\b");
+    RemoveDirectoryA(".\\c");
+
+    if(psi_a) IShellItem_Release(psi_a);
+    if(psi_b) IShellItem_Release(psi_b);
+    if(psi_c) IShellItem_Release(psi_c);
+
+    for(i = 0; i < 9; i++)
+        if(psi[i]) IShellItem_Release(psi[i]);
+}
+
+/**************************************************************/
+/* IUnknown implementation for counting QueryInterface calls. */
+typedef struct {
+    IUnknown IUnknown_iface;
+    struct if_count {
+        REFIID id;
+        LONG count;
+    } *ifaces;
+    LONG unknown;
+} IUnknownImpl;
+
+static inline IUnknownImpl *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, IUnknownImpl, IUnknown_iface);
+}
+
+static HRESULT WINAPI unk_fnQueryInterface(IUnknown *iunk, REFIID riid, void** punk)
+{
+    IUnknownImpl *This = impl_from_IUnknown(iunk);
+    UINT i, found;
+    for(i = found = 0; This->ifaces[i].id != NULL; i++)
+    {
+        if(IsEqualIID(This->ifaces[i].id, riid))
+        {
+            This->ifaces[i].count++;
+            found = 1;
+            break;
+        }
+    }
+    if(!found)
+        This->unknown++;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI unk_fnAddRef(IUnknown *iunk)
+{
+    return 2;
+}
+
+static ULONG WINAPI unk_fnRelease(IUnknown *iunk)
+{
+    return 1;
+}
+
+static const IUnknownVtbl vt_IUnknown = {
+    unk_fnQueryInterface,
+    unk_fnAddRef,
+    unk_fnRelease
+};
+
+static void test_SHGetIDListFromObject(void)
+{
+    IUnknownImpl *punkimpl;
+    IShellFolder *psfdesktop;
+    IShellView *psv;
+    LPITEMIDLIST pidl, pidl_desktop;
+    HRESULT hres;
+    UINT i;
+    struct if_count ifaces[] =
+        { {&IID_IPersistIDList, 0},
+          {&IID_IPersistFolder2, 0},
+          {&IID_IDataObject, 0},
+          {&IID_IParentAndItem, 0},
+          {&IID_IFolderView, 0},
+          {NULL, 0} };
+
+    if(!pSHGetIDListFromObject)
+    {
+        win_skip("SHGetIDListFromObject missing.\n");
+        return;
+    }
+
+    ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
+
+    if(0)
+    {
+        /* Crashes native */
+        pSHGetIDListFromObject(NULL, NULL);
+        pSHGetIDListFromObject((void*)0xDEADBEEF, NULL);
+    }
+
+    hres = pSHGetIDListFromObject(NULL, &pidl);
+    ok(hres == E_NOINTERFACE, "Got %x\n", hres);
+
+    punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
+    punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
+    punkimpl->ifaces = ifaces;
+    punkimpl->unknown = 0;
+
+    hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
+    ok(hres == E_NOINTERFACE, "Got %x\n", hres);
+    ok(ifaces[0].count, "interface not requested.\n");
+    ok(ifaces[1].count, "interface not requested.\n");
+    ok(ifaces[2].count, "interface not requested.\n");
+    todo_wine
+        ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
+           "interface not requested.\n");
+    ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
+       "interface not requested.\n");
+
+    ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
+    HeapFree(GetProcessHeap(), 0, punkimpl);
+
+    pidl_desktop = NULL;
+    pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
+    ok(pidl_desktop != NULL, "Failed to get desktop pidl.\n");
+
+    SHGetDesktopFolder(&psfdesktop);
+
+    /* Test IShellItem */
+    if(pSHCreateShellItem)
+    {
+        IShellItem *shellitem;
+        hres = pSHCreateShellItem(NULL, NULL, pidl_desktop, &shellitem);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            hres = pSHGetIDListFromObject((IUnknown*)shellitem, &pidl);
+            ok(hres == S_OK, "got 0x%08x\n", hres);
+            if(SUCCEEDED(hres))
+            {
+                ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
+                pILFree(pidl);
+            }
+            IShellItem_Release(shellitem);
+        }
+    }
+    else
+        skip("no SHCreateShellItem.\n");
+
+    /* Test IShellFolder */
+    hres = pSHGetIDListFromObject((IUnknown*)psfdesktop, &pidl);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
+        pILFree(pidl);
+    }
+
+    hres = IShellFolder_CreateViewObject(psfdesktop, NULL, &IID_IShellView, (void**)&psv);
+    ok(hres == S_OK, "got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        IEnumIDList *peidl;
+        IDataObject *pdo;
+        SHCONTF enum_flags;
+
+        /* Test IFolderView */
+        hres = pSHGetIDListFromObject((IUnknown*)psv, &pidl);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            ok(ILIsEqual(pidl_desktop, pidl), "pidl not equal.\n");
+            pILFree(pidl);
+        }
+
+        /* Test IDataObject */
+        enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
+        hres = IShellFolder_EnumObjects(psfdesktop, NULL, enum_flags, &peidl);
+        ok(hres == S_OK, "got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            LPITEMIDLIST apidl[5];
+            UINT count = 0;
+            for(count = 0; count < 5; count++)
+                if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
+                    break;
+
+            if(count)
+            {
+                hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, 1, (LPCITEMIDLIST*)apidl,
+                                                  &IID_IDataObject, NULL, (void**)&pdo);
+                ok(hres == S_OK, "got 0x%08x\n", hres);
+                if(SUCCEEDED(hres))
+                {
+                    pidl = (void*)0xDEADBEEF;
+                    hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
+                    ok(hres == S_OK, "got 0x%08x\n", hres);
+                    ok(pidl != NULL, "pidl is NULL.\n");
+                    ok(ILIsEqual(pidl, apidl[0]), "pidl not equal.\n");
+                    pILFree(pidl);
+
+                    IDataObject_Release(pdo);
+                }
+            }
+            else
+                skip("No files found - skipping single-file test.\n");
+
+            if(count > 1)
+            {
+                hres = IShellFolder_GetUIObjectOf(psfdesktop, NULL, count, (LPCITEMIDLIST*)apidl,
+                                                  &IID_IDataObject, NULL, (void**)&pdo);
+                ok(hres == S_OK, "got 0x%08x\n", hres);
+                if(SUCCEEDED(hres))
+                {
+                    pidl = (void*)0xDEADBEEF;
+                    hres = pSHGetIDListFromObject((IUnknown*)pdo, &pidl);
+                    ok(hres == E_NOINTERFACE || hres == E_FAIL /*Vista*/,
+                       "got 0x%08x\n", hres);
+                    ok(pidl == NULL, "pidl is not NULL.\n");
+
+                    IDataObject_Release(pdo);
+                }
+            }
+            else
+                skip("zero or one file found - skipping multi-file test.\n");
+
+            for(i = 0; i < count; i++)
+                pILFree(apidl[i]);
+
+            IEnumIDList_Release(peidl);
+        }
+
+        IShellView_Release(psv);
+    }
+
+    IShellFolder_Release(psfdesktop);
+    pILFree(pidl_desktop);
+}
+
+static void test_SHGetItemFromObject(void)
+{
+    IUnknownImpl *punkimpl;
+    IShellFolder *psfdesktop;
+    LPITEMIDLIST pidl;
+    IShellItem *psi;
+    IUnknown *punk;
+    HRESULT hres;
+    struct if_count ifaces[] =
+        { {&IID_IPersistIDList, 0},
+          {&IID_IPersistFolder2, 0},
+          {&IID_IDataObject, 0},
+          {&IID_IParentAndItem, 0},
+          {&IID_IFolderView, 0},
+          {NULL, 0} };
+
+    if(!pSHGetItemFromObject)
+    {
+        skip("No SHGetItemFromObject.\n");
+        return;
+    }
+
+    SHGetDesktopFolder(&psfdesktop);
+
+    if(0)
+    {
+        /* Crashes with Windows 7 */
+        pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IUnknown, NULL);
+        pSHGetItemFromObject(NULL, &IID_IUnknown, NULL);
+        pSHGetItemFromObject((IUnknown*)psfdesktop, NULL, (void**)&punk);
+    }
+
+    hres = pSHGetItemFromObject(NULL, &IID_IUnknown, (void**)&punk);
+    ok(hres == E_NOINTERFACE, "Got 0x%08x\n", hres);
+
+    punkimpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IUnknownImpl));
+    punkimpl->IUnknown_iface.lpVtbl = &vt_IUnknown;
+    punkimpl->ifaces = ifaces;
+    punkimpl->unknown = 0;
+
+    /* The same as SHGetIDListFromObject */
+    hres = pSHGetIDListFromObject((IUnknown*)punkimpl, &pidl);
+    ok(hres == E_NOINTERFACE, "Got %x\n", hres);
+    ok(ifaces[0].count, "interface not requested.\n");
+    ok(ifaces[1].count, "interface not requested.\n");
+    ok(ifaces[2].count, "interface not requested.\n");
+    todo_wine
+        ok(ifaces[3].count || broken(!ifaces[3].count /*vista*/),
+           "interface not requested.\n");
+    ok(ifaces[4].count || broken(!ifaces[4].count /*vista*/),
+       "interface not requested.\n");
+
+    ok(!punkimpl->unknown, "Got %d unknown.\n", punkimpl->unknown);
+    HeapFree(GetProcessHeap(), 0, punkimpl);
+
+    /* Test IShellItem */
+    hres = pSHGetItemFromObject((IUnknown*)psfdesktop, &IID_IShellItem, (void**)&psi);
+    ok(hres == S_OK, "Got 0x%08x\n", hres);
+    if(SUCCEEDED(hres))
+    {
+        IShellItem *psi2;
+        hres = pSHGetItemFromObject((IUnknown*)psi, &IID_IShellItem, (void**)&psi2);
+        ok(hres == S_OK, "Got 0x%08x\n", hres);
+        if(SUCCEEDED(hres))
+        {
+            todo_wine
+                ok(psi == psi2, "Different instances (%p != %p).\n", psi, psi2);
+            IShellItem_Release(psi2);
+        }
+        IShellItem_Release(psi);
+    }
+
+    IShellFolder_Release(psfdesktop);
+}
+
+static void test_SHCreateShellItemArray(void)
+{
+    IShellFolder *pdesktopsf, *psf;
+    IShellItemArray *psia;
+    IEnumIDList *peidl;
+    HRESULT hr;
+    WCHAR cTestDirW[MAX_PATH];
+    LPITEMIDLIST pidl_testdir, pidl;
+    static const WCHAR testdirW[] = {'t','e','s','t','d','i','r',0};
+
+    if(!pSHCreateShellItemArray) {
+        skip("No pSHCreateShellItemArray!\n");
+        return;
+    }
+
+    ok(pSHGetSpecialFolderLocation != NULL, "SHGetSpecialFolderLocation missing.\n");
+
+    if(0)
+    {
+        /* Crashes under native */
+        pSHCreateShellItemArray(NULL, NULL, 0, NULL, NULL);
+        pSHCreateShellItemArray(NULL, NULL, 1, NULL, NULL);
+        pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, NULL);
+        pSHCreateShellItemArray(pidl, NULL, 0, NULL, NULL);
+    }
+
+    hr = pSHCreateShellItemArray(NULL, NULL, 0, NULL, &psia);
+    ok(hr == E_POINTER, "got 0x%08x\n", hr);
+
+    SHGetDesktopFolder(&pdesktopsf);
+    hr = pSHCreateShellItemArray(NULL, pdesktopsf, 0, NULL, &psia);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    hr = pSHCreateShellItemArray(NULL, pdesktopsf, 1, NULL, &psia);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+
+    pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl);
+    hr = pSHCreateShellItemArray(pidl, NULL, 0, NULL, &psia);
+    ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+    pILFree(pidl);
+
+    GetCurrentDirectoryW(MAX_PATH, cTestDirW);
+    myPathAddBackslashW(cTestDirW);
+    lstrcatW(cTestDirW, testdirW);
+
+    CreateFilesFolders();
+
+    hr = IShellFolder_ParseDisplayName(pdesktopsf, NULL, NULL, cTestDirW, NULL, &pidl_testdir, 0);
+    ok(hr == S_OK, "got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        hr = IShellFolder_BindToObject(pdesktopsf, pidl_testdir, NULL, (REFIID)&IID_IShellFolder,
+                                       (void**)&psf);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+    }
+    IShellFolder_Release(pdesktopsf);
+
+    if(FAILED(hr))
+    {
+        skip("Failed to set up environment for SHCreateShellItemArray tests.\n");
+        pILFree(pidl_testdir);
+        Cleanup();
+        return;
+    }
+
+    hr = IShellFolder_EnumObjects(psf, NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &peidl);
+    ok(hr == S_OK, "Got %08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        LPITEMIDLIST apidl[5];
+        UINT done, numitems, i;
+
+        for(done = 0; done < 5; done++)
+            if(IEnumIDList_Next(peidl, 1, &apidl[done], NULL) != S_OK)
+                break;
+        ok(done == 5, "Got %d pidls\n", done);
+        IEnumIDList_Release(peidl);
+
+        /* Create a ShellItemArray */
+        hr = pSHCreateShellItemArray(NULL, psf, done, (LPCITEMIDLIST*)apidl, &psia);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            IShellItem *psi;
+
+            if(0)
+            {
+                /* Crashes in Windows 7 */
+                IShellItemArray_GetCount(psia, NULL);
+            }
+
+            IShellItemArray_GetCount(psia, &numitems);
+            ok(numitems == done, "Got %d, expected %d\n", numitems, done);
+
+            hr = IShellItemArray_GetItemAt(psia, numitems, &psi);
+            ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+
+            /* Compare all the items */
+            for(i = 0; i < numitems; i++)
+            {
+                LPITEMIDLIST pidl_abs;
+                pidl_abs = ILCombine(pidl_testdir, apidl[i]);
+
+                hr = IShellItemArray_GetItemAt(psia, i, &psi);
+                ok(hr == S_OK, "(%d) Failed with 0x%08x\n", i, hr);
+                if(SUCCEEDED(hr))
+                {
+                    hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    if(SUCCEEDED(hr))
+                    {
+                        ok(ILIsEqual(pidl_abs, pidl), "Pidl not equal.\n");
+                        pILFree(pidl);
+                    }
+                    IShellItem_Release(psi);
+                }
+                pILFree(pidl_abs);
+            }
+            for(i = 0; i < done; i++)
+                pILFree(apidl[i]);
+            IShellItemArray_Release(psia);
+        }
+    }
+
+    /* SHCreateShellItemArrayFromShellItem */
+    if(pSHCreateShellItemArrayFromShellItem)
+    {
+        IShellItem *psi;
+
+        if(0)
+        {
+            /* Crashes under Windows 7 */
+            pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, NULL);
+            pSHCreateShellItemArrayFromShellItem(NULL, &IID_IShellItemArray, (void**)&psia);
+            pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, NULL);
+        }
+
+        hr = pSHCreateItemFromIDList(pidl_testdir, &IID_IShellItem, (void**)&psi);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = pSHCreateShellItemArrayFromShellItem(psi, &IID_IShellItemArray, (void**)&psia);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                IShellItem *psi2;
+                UINT count;
+                hr = IShellItemArray_GetCount(psia, &count);
+                ok(hr == S_OK, "Got 0x%08x\n", hr);
+                ok(count == 1, "Got count %d\n", count);
+                hr = IShellItemArray_GetItemAt(psia, 0, &psi2);
+                ok(hr == S_OK, "Got 0x%08x\n", hr);
+                todo_wine
+                    ok(psi != psi2, "ShellItems are of the same instance.\n");
+                if(SUCCEEDED(hr))
+                {
+                    LPITEMIDLIST pidl1, pidl2;
+                    hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl1);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    ok(pidl1 != NULL, "pidl1 was null.\n");
+                    hr = pSHGetIDListFromObject((IUnknown*)psi2, &pidl2);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    ok(pidl2 != NULL, "pidl2 was null.\n");
+                    ok(ILIsEqual(pidl1, pidl2), "pidls not equal.\n");
+                    pILFree(pidl1);
+                    pILFree(pidl2);
+                    IShellItem_Release(psi2);
+                }
+                hr = IShellItemArray_GetItemAt(psia, 1, &psi2);
+                ok(hr == E_FAIL, "Got 0x%08x\n", hr);
+                IShellItemArray_Release(psia);
+            }
+            IShellItem_Release(psi);
+        }
+    }
+    else
+        skip("No SHCreateShellItemArrayFromShellItem.\n");
+
+    if(pSHCreateShellItemArrayFromDataObject)
+    {
+        IShellView *psv;
+
+        if(0)
+        {
+            /* Crashes under Windows 7 */
+            pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, NULL);
+        }
+        hr = pSHCreateShellItemArrayFromDataObject(NULL, &IID_IShellItemArray, (void**)&psia);
+        ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
+
+        hr = IShellFolder_CreateViewObject(psf, NULL, &IID_IShellView, (void**)&psv);
+        ok(hr == S_OK, "got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            IEnumIDList *peidl;
+            IDataObject *pdo;
+            SHCONTF enum_flags;
+
+            enum_flags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS | SHCONTF_INCLUDEHIDDEN;
+            hr = IShellFolder_EnumObjects(psf, NULL, enum_flags, &peidl);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                LPITEMIDLIST apidl[5];
+                UINT count, i;
+
+                for(count = 0; count < 5; count++)
+                    if(IEnumIDList_Next(peidl, 1, &apidl[count], NULL) != S_OK)
+                        break;
+                ok(count == 5, "Got %d\n", count);
+
+                if(count)
+                {
+                    hr = IShellFolder_GetUIObjectOf(psf, NULL, count, (LPCITEMIDLIST*)apidl,
+                                                    &IID_IDataObject, NULL, (void**)&pdo);
+                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                    if(SUCCEEDED(hr))
+                    {
+                        hr = pSHCreateShellItemArrayFromDataObject(pdo, &IID_IShellItemArray,
+                                                                   (void**)&psia);
+                        ok(hr == S_OK, "Got 0x%08x\n", hr);
+                        if(SUCCEEDED(hr))
+                        {
+                            UINT count_sia, i;
+                            hr = IShellItemArray_GetCount(psia, &count_sia);
+                            ok(hr == S_OK, "Got 0x%08x\n", hr);
+                            ok(count_sia == count, "Counts differ (%d, %d)\n", count, count_sia);
+                            for(i = 0; i < count_sia; i++)
+                            {
+                                LPITEMIDLIST pidl_abs = ILCombine(pidl_testdir, apidl[i]);
+                                IShellItem *psi;
+                                hr = IShellItemArray_GetItemAt(psia, i, &psi);
+                                ok(hr == S_OK, "Got 0x%08x\n", hr);
+                                if(SUCCEEDED(hr))
+                                {
+                                    LPITEMIDLIST pidl;
+                                    hr = pSHGetIDListFromObject((IUnknown*)psi, &pidl);
+                                    ok(hr == S_OK, "Got 0x%08x\n", hr);
+                                    ok(pidl != NULL, "pidl as NULL.\n");
+                                    ok(ILIsEqual(pidl, pidl_abs), "pidls differ.\n");
+                                    pILFree(pidl);
+                                    IShellItem_Release(psi);
+                                }
+                                pILFree(pidl_abs);
+                            }
+
+                            IShellItemArray_Release(psia);
+                        }
+
+                        IDataObject_Release(pdo);
+                    }
+                    for(i = 0; i < count; i++)
+                        pILFree(apidl[i]);
+                }
+                else
+                    skip("No files found - skipping test.\n");
+
+                IEnumIDList_Release(peidl);
+            }
+            IShellView_Release(psv);
+        }
+    }
+    else
+        skip("No SHCreateShellItemArrayFromDataObject.\n");
+
+    IShellFolder_Release(psf);
+    pILFree(pidl_testdir);
+    Cleanup();
+}
+
+static void test_ShellItemBindToHandler(void)
+{
+    IShellItem *psi;
+    LPITEMIDLIST pidl_desktop;
+    HRESULT hr;
+
+    if(!pSHCreateShellItem)
+    {
+        skip("SHCreateShellItem missing.\n");
+        return;
+    }
+
+    hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+    }
+    if(SUCCEEDED(hr))
+    {
+        IPersistFolder2 *ppf2;
+        IUnknown *punk;
+
+        if(0)
+        {
+            /* Crashes under Windows 7 */
+            IShellItem_BindToHandler(psi, NULL, NULL, NULL, NULL);
+            IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, NULL);
+        }
+        hr = IShellItem_BindToHandler(psi, NULL, &IID_IUnknown, &IID_IUnknown, (void**)&punk);
+        ok(hr == MK_E_NOOBJECT, "Got 0x%08x\n", hr);
+
+        /* BHID_SFObject */
+        hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IShellFolder, (void**)&punk);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr)) IUnknown_Release(punk);
+        hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFObject, &IID_IPersistFolder2, (void**)&ppf2);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            LPITEMIDLIST pidl_tmp;
+            hr = IPersistFolder2_GetCurFolder(ppf2, &pidl_tmp);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                ok(ILIsEqual(pidl_desktop, pidl_tmp), "Pidl not equal (%p, %p)\n", pidl_desktop, pidl_tmp);
+                pILFree(pidl_tmp);
+            }
+            IPersistFolder2_Release(ppf2);
+        }
+
+        /* BHID_SFUIObject */
+        hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IDataObject, (void**)&punk);
+        ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr)) IUnknown_Release(punk);
+        hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFUIObject, &IID_IContextMenu, (void**)&punk);
+        ok(hr == S_OK || broken(hr == E_NOINTERFACE /* XP */), "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+        /* BHID_DataObject */
+        hr = IShellItem_BindToHandler(psi, NULL, &BHID_DataObject, &IID_IDataObject, (void**)&punk);
+        ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+        todo_wine
+        {
+            /* BHID_SFViewObject */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellView, (void**)&punk);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_SFViewObject, &IID_IShellFolderView, (void**)&punk);
+            ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_Storage */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IStream, (void**)&punk);
+            ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_Storage, &IID_IUnknown, (void**)&punk);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_Stream */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IStream, (void**)&punk);
+            ok(hr == E_NOINTERFACE, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_Stream, &IID_IUnknown, (void**)&punk);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_StorageEnum */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_StorageEnum, &IID_IEnumShellItems, (void**)&punk);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_Transfer */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_Transfer, &IID_IUnknown, (void**)&punk);
+            ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_EnumItems */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumItems, &IID_IEnumShellItems, (void**)&punk);
+            ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_Filter */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_Filter, &IID_IUnknown, (void**)&punk);
+            ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_LinkTargetItem */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IShellItem, (void**)&punk);
+            ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_LinkTargetItem, &IID_IUnknown, (void**)&punk);
+            ok(hr == E_NOINTERFACE || broken(hr == E_INVALIDARG /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_PropertyStore */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStore, (void**)&punk);
+            ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_PropertyStore, &IID_IPropertyStoreFactory, (void**)&punk);
+            ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_ThumbnailHandler */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_ThumbnailHandler, &IID_IUnknown, (void**)&punk);
+            ok(hr == E_INVALIDARG || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_AssociationArray */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_AssociationArray, &IID_IQueryAssociations, (void**)&punk);
+            ok(hr == S_OK || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+
+            /* BHID_EnumAssocHandlers */
+            hr = IShellItem_BindToHandler(psi, NULL, &BHID_EnumAssocHandlers, &IID_IUnknown, (void**)&punk);
+            ok(hr == E_NOINTERFACE || broken(hr == MK_E_NOOBJECT /* XP */), "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr)) IUnknown_Release(punk);
+        }
+
+        IShellItem_Release(psi);
+    }
+    else
+        skip("Failed to create ShellItem.\n");
+
+    pILFree(pidl_desktop);
+}
+
+static void test_ShellItemGetAttributes(void)
+{
+    IShellItem *psi;
+    LPITEMIDLIST pidl_desktop;
+    SFGAOF sfgao;
+    HRESULT hr;
+
+    if(!pSHCreateShellItem)
+    {
+        skip("SHCreateShellItem missing.\n");
+        return;
+    }
+
+    hr = pSHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &pidl_desktop);
+    ok(hr == S_OK, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        hr = pSHCreateShellItem(NULL, NULL, pidl_desktop, &psi);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        pILFree(pidl_desktop);
+    }
+    if(FAILED(hr))
+    {
+        skip("Skipping tests.\n");
+        return;
+    }
+
+    if(0)
+    {
+        /* Crashes on native (Win 7) */
+        IShellItem_GetAttributes(psi, 0, NULL);
+    }
+
+    /* Test GetAttributes on the desktop folder. */
+    sfgao = 0xdeadbeef;
+    hr = IShellItem_GetAttributes(psi, SFGAO_FOLDER, &sfgao);
+    ok(hr == S_OK || broken(hr == E_FAIL) /* <Vista */, "Got 0x%08x\n", hr);
+    ok(sfgao == SFGAO_FOLDER || broken(sfgao == 0) /* <Vista */, "Got 0x%08x\n", sfgao);
+
+    IShellItem_Release(psi);
+}
+
 static void test_SHParseDisplayName(void)
 {
     LPITEMIDLIST pidl1, pidl2;
@@ -2029,7 +3732,7 @@ static void test_SHParseDisplayName(void)
     WCHAR dirW[MAX_PATH];
     WCHAR nameW[10];
     HRESULT hr;
-    BOOL ret;
+    BOOL ret, is_wow64;
 
     if (!pSHParseDisplayName)
     {
@@ -2040,9 +3743,9 @@ static void test_SHParseDisplayName(void)
 if (0)
 {
     /* crashes on native */
-    hr = pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
+    pSHParseDisplayName(NULL, NULL, NULL, 0, NULL);
     nameW[0] = 0;
-    hr = pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
+    pSHParseDisplayName(nameW, NULL, NULL, 0, NULL);
 }
 
     pidl1 = (LPITEMIDLIST)0xdeadbeef;
@@ -2077,6 +3780,24 @@ if (0)
     pILFree(pidl1);
     pILFree(pidl2);
 
+    /* system32 is not redirected to syswow64 on WOW64 */
+    if (!pIsWow64Process || !pIsWow64Process( GetCurrentProcess(), &is_wow64 )) is_wow64 = FALSE;
+    if (is_wow64 && pGetSystemWow64DirectoryW)
+    {
+        *dirW = 0;
+        ok(GetSystemDirectoryW(dirW, MAX_PATH) > 0, "GetSystemDirectoryW failed: %u\n", GetLastError());
+        hr = pSHParseDisplayName(dirW, NULL, &pidl1, 0, NULL);
+        ok(hr == S_OK, "failed %08x\n", hr);
+        *dirW = 0;
+        ok(pGetSystemWow64DirectoryW(dirW, MAX_PATH) > 0, "GetSystemWow64DirectoryW failed: %u\n", GetLastError());
+        hr = pSHParseDisplayName(dirW, NULL, &pidl2, 0, NULL);
+        ok(hr == S_OK, "failed %08x\n", hr);
+        ret = pILIsEqual(pidl1, pidl2);
+        ok(ret == FALSE, "expected different idls\n");
+        pILFree(pidl1);
+        pILFree(pidl2);
+    }
+
     IShellFolder_Release(desktop);
 }
 
@@ -2084,6 +3805,7 @@ static void test_desktop_IPersist(void)
 {
     IShellFolder *desktop;
     IPersist *persist;
+    IPersistFolder2 *ppf2;
     CLSID clsid;
     HRESULT hr;
 
@@ -2098,7 +3820,7 @@ static void test_desktop_IPersist(void)
     if (0)
     {
         /* crashes on native */
-        hr = IPersist_GetClassID(persist, NULL);
+        IPersist_GetClassID(persist, NULL);
     }
         memset(&clsid, 0, sizeof(clsid));
         hr = IPersist_GetClassID(persist, &clsid);
@@ -2107,9 +3829,755 @@ static void test_desktop_IPersist(void)
         IPersist_Release(persist);
     }
 
+    hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder2, (void**)&ppf2);
+    ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* pre-Vista */, "failed %08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        IPersistFolder *ppf;
+        LPITEMIDLIST pidl;
+        hr = IShellFolder_QueryInterface(desktop, &IID_IPersistFolder, (void**)&ppf);
+        ok(hr == S_OK, "IID_IPersistFolder2 without IID_IPersistFolder.\n");
+        if(SUCCEEDED(hr))
+            IPersistFolder_Release(ppf);
+
+        todo_wine {
+            hr = IPersistFolder2_Initialize(ppf2, NULL);
+            ok(hr == S_OK, "got %08x\n", hr);
+        }
+
+        pidl = NULL;
+        hr = IPersistFolder2_GetCurFolder(ppf2, &pidl);
+        ok(hr == S_OK, "got %08x\n", hr);
+        ok(pidl != NULL, "pidl was NULL.\n");
+        if(SUCCEEDED(hr)) pILFree(pidl);
+
+        IPersistFolder2_Release(ppf2);
+    }
+
     IShellFolder_Release(desktop);
 }
 
+static void test_GetUIObject(void)
+{
+    IShellFolder *psf_desktop;
+    IContextMenu *pcm;
+    LPITEMIDLIST pidl;
+    HRESULT hr;
+    WCHAR path[MAX_PATH];
+    const WCHAR filename[] =
+        {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
+
+    if(!pSHBindToParent)
+    {
+        win_skip("SHBindToParent missing.\n");
+        return;
+    }
+
+    GetCurrentDirectoryW(MAX_PATH, path);
+    if(!lstrlenW(path))
+    {
+        skip("GetCurrentDirectoryW returned an empty string.\n");
+        return;
+    }
+    lstrcatW(path, filename);
+    SHGetDesktopFolder(&psf_desktop);
+
+    CreateFilesFolders();
+
+    hr = IShellFolder_ParseDisplayName(psf_desktop, NULL, NULL, path, NULL, &pidl, 0);
+    ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        IShellFolder *psf;
+        LPCITEMIDLIST pidl_child;
+        hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&psf, &pidl_child);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            hr = IShellFolder_GetUIObjectOf(psf, NULL, 1, &pidl_child, &IID_IContextMenu, NULL,
+                                            (void**)&pcm);
+            ok(hr == S_OK, "Got 0x%08x\n", hr);
+            if(SUCCEEDED(hr))
+            {
+                HMENU hmenu = CreatePopupMenu();
+                INT max_id, max_id_check;
+                UINT count, i;
+                const int id_upper_limit = 32767;
+                hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, 0, id_upper_limit, CMF_NORMAL);
+                ok(SUCCEEDED(hr), "Got 0x%08x\n", hr);
+                max_id = HRESULT_CODE(hr) - 1; /* returns max_id + 1 */
+                ok(max_id <= id_upper_limit, "Got %d\n", max_id);
+                count = GetMenuItemCount(hmenu);
+                ok(count, "Got %d\n", count);
+
+                max_id_check = 0;
+                for(i = 0; i < count; i++)
+                {
+                    MENUITEMINFOA mii;
+                    INT res;
+                    ZeroMemory(&mii, sizeof(MENUITEMINFOA));
+                    mii.cbSize = sizeof(MENUITEMINFOA);
+                    mii.fMask = MIIM_ID | MIIM_FTYPE;
+
+                    SetLastError(0);
+                    res = GetMenuItemInfoA(hmenu, i, TRUE, &mii);
+                    ok(res, "Failed (last error: %d).\n", GetLastError());
+
+                    ok( (mii.wID <= id_upper_limit) || (mii.fType & MFT_SEPARATOR),
+                        "Got non-separator ID out of range: %d (type: %x)\n", mii.wID, mii.fType);
+                    if(!(mii.fType & MFT_SEPARATOR))
+                        max_id_check = (mii.wID>max_id_check)?mii.wID:max_id_check;
+                }
+                ok((max_id_check == max_id) ||
+                   (max_id_check == max_id-1 /* Win 7 */),
+                   "Not equal (or near equal), got %d and %d\n", max_id_check, max_id);
+
+#define is_win2k() (pSHGetFolderPathA && !pSHGetFolderPathAndSubDirA)
+
+                if(count && !is_win2k())   /* Test is interactive on w2k, so skip */
+                {
+                    CMINVOKECOMMANDINFO cmi;
+                    ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
+                    cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
+
+                    /* Attempt to execute a nonexistent command */
+                    cmi.lpVerb = MAKEINTRESOURCEA(9999);
+                    hr = IContextMenu_InvokeCommand(pcm, &cmi);
+                    ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
+
+                    cmi.lpVerb = "foobar_wine_test";
+                    hr = IContextMenu_InvokeCommand(pcm, &cmi);
+                    ok( (hr == E_INVALIDARG) || (hr == E_FAIL /* Win7 */) ||
+                        (hr == HRESULT_FROM_WIN32(ERROR_NO_ASSOCIATION) /* Vista */),
+                        "Got 0x%08x\n", hr);
+                }
+#undef is_win2k
+
+                DestroyMenu(hmenu);
+                IContextMenu_Release(pcm);
+            }
+            IShellFolder_Release(psf);
+        }
+        if(pILFree) pILFree(pidl);
+    }
+
+    IShellFolder_Release(psf_desktop);
+    Cleanup();
+}
+
+#define verify_pidl(i,p) r_verify_pidl(__LINE__, i, p)
+static void r_verify_pidl(unsigned l, LPCITEMIDLIST pidl, const WCHAR *path)
+{
+    LPCITEMIDLIST child;
+    IShellFolder *parent;
+    STRRET filename;
+    HRESULT hr;
+
+    if(!pSHBindToParent){
+        win_skip("SHBindToParent is not available, not performing full PIDL verification\n");
+        if(path)
+            ok_(__FILE__,l)(pidl != NULL, "Expected PIDL to be non-NULL\n");
+        else
+            ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
+        return;
+    }
+
+    if(path){
+        if(!pidl){
+            ok_(__FILE__,l)(0, "didn't get expected path (%s), instead: NULL\n", wine_dbgstr_w(path));
+            return;
+        }
+
+        hr = pSHBindToParent(pidl, &IID_IShellFolder, (LPVOID*)&parent, &child);
+        ok_(__FILE__,l)(hr == S_OK, "SHBindToParent failed: 0x%08x\n", hr);
+        if(FAILED(hr))
+            return;
+
+        hr = IShellFolder_GetDisplayNameOf(parent, child, SHGDN_FORPARSING, &filename);
+        ok_(__FILE__,l)(hr == S_OK, "GetDisplayNameOf failed: 0x%08x\n", hr);
+        if(FAILED(hr)){
+            IShellFolder_Release(parent);
+            return;
+        }
+
+        ok_(__FILE__,l)(filename.uType == STRRET_WSTR || filename.uType == STRRET_CSTR,
+                "Got unexpected string type: %d\n", filename.uType);
+        if(filename.uType == STRRET_WSTR){
+            ok_(__FILE__,l)(lstrcmpW(path, U(filename).pOleStr) == 0,
+                    "didn't get expected path (%s), instead: %s\n",
+                     wine_dbgstr_w(path), wine_dbgstr_w(U(filename).pOleStr));
+            SHFree(U(filename).pOleStr);
+        }else if(filename.uType == STRRET_CSTR){
+            ok_(__FILE__,l)(strcmp_wa(path, U(filename).cStr) == 0,
+                    "didn't get expected path (%s), instead: %s\n",
+                     wine_dbgstr_w(path), U(filename).cStr);
+        }
+
+        IShellFolder_Release(parent);
+    }else
+        ok_(__FILE__,l)(pidl == NULL, "Expected PIDL to be NULL\n");
+}
+
+static void test_SHSimpleIDListFromPath(void)
+{
+    const WCHAR adirW[] = {'C',':','\\','s','i','d','l','f','p','d','i','r',0};
+    const CHAR adirA[] = "C:\\sidlfpdir";
+    BOOL br, is_unicode = !(GetVersion() & 0x80000000);
+
+    LPITEMIDLIST pidl = NULL;
+
+    if(!pSHSimpleIDListFromPathAW){
+        win_skip("SHSimpleIDListFromPathAW not available\n");
+        return;
+    }
+
+    br = CreateDirectoryA(adirA, NULL);
+    ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
+
+    if(is_unicode)
+        pidl = pSHSimpleIDListFromPathAW(adirW);
+    else
+        pidl = pSHSimpleIDListFromPathAW(adirA);
+    verify_pidl(pidl, adirW);
+    pILFree(pidl);
+
+    br = RemoveDirectoryA(adirA);
+    ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
+
+    if(is_unicode)
+        pidl = pSHSimpleIDListFromPathAW(adirW);
+    else
+        pidl = pSHSimpleIDListFromPathAW(adirA);
+    verify_pidl(pidl, adirW);
+    pILFree(pidl);
+}
+
+/* IFileSystemBindData impl */
+static HRESULT WINAPI fsbd_QueryInterface(IFileSystemBindData *fsbd,
+        REFIID riid, void **ppv)
+{
+    if(IsEqualIID(riid, &IID_IFileSystemBindData) ||
+            IsEqualIID(riid, &IID_IUnknown)){
+        *ppv = fsbd;
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI fsbd_AddRef(IFileSystemBindData *fsbd)
+{
+    return 2;
+}
+
+static ULONG WINAPI fsbd_Release(IFileSystemBindData *fsbd)
+{
+    return 1;
+}
+
+static HRESULT WINAPI fsbd_SetFindData(IFileSystemBindData *fsbd,
+        const WIN32_FIND_DATAW *pfd)
+{
+    ok(0, "SetFindData called\n");
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI fsbd_GetFindData_nul(IFileSystemBindData *fsbd,
+        WIN32_FIND_DATAW *pfd)
+{
+    memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
+    return S_OK;
+}
+
+static HRESULT WINAPI fsbd_GetFindData_junk(IFileSystemBindData *fsbd,
+        WIN32_FIND_DATAW *pfd)
+{
+    memset(pfd, 0xef, sizeof(WIN32_FIND_DATAW));
+    return S_OK;
+}
+
+static HRESULT WINAPI fsbd_GetFindData_invalid(IFileSystemBindData *fsbd,
+        WIN32_FIND_DATAW *pfd)
+{
+    memset(pfd, 0, sizeof(WIN32_FIND_DATAW));
+    *pfd->cFileName = 'a';
+    *pfd->cAlternateFileName = 'a';
+    return S_OK;
+}
+
+static HRESULT WINAPI fsbd_GetFindData_valid(IFileSystemBindData *fsbd,
+        WIN32_FIND_DATAW *pfd)
+{
+    static const WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
+    HANDLE handle = FindFirstFileW(adirW, pfd);
+    FindClose(handle);
+    return S_OK;
+}
+
+static HRESULT WINAPI fsbd_GetFindData_fail(IFileSystemBindData *fsbd,
+        WIN32_FIND_DATAW *pfd)
+{
+    return E_FAIL;
+}
+
+static IFileSystemBindDataVtbl fsbdVtbl = {
+    fsbd_QueryInterface,
+    fsbd_AddRef,
+    fsbd_Release,
+    fsbd_SetFindData,
+    NULL
+};
+
+static IFileSystemBindData fsbd = { &fsbdVtbl };
+
+static void test_ParseDisplayNamePBC(void)
+{
+    WCHAR wFileSystemBindData[] =
+        {'F','i','l','e',' ','S','y','s','t','e','m',' ','B','i','n','d',' ','D','a','t','a',0};
+    WCHAR adirW[] = {'C',':','\\','f','s','b','d','d','i','r',0};
+    WCHAR afileW[] = {'C',':','\\','f','s','b','d','d','i','r','\\','f','i','l','e','.','t','x','t',0};
+    WCHAR afile2W[] = {'C',':','\\','f','s','b','d','d','i','r','\\','s','\\','f','i','l','e','.','t','x','t',0};
+    const HRESULT exp_err = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+
+    IShellFolder *psf;
+    IBindCtx *pbc;
+    HRESULT hres;
+    ITEMIDLIST *pidl;
+
+    /* Check if we support WCHAR functions */
+    SetLastError(0xdeadbeef);
+    lstrcmpiW(adirW, adirW);
+    if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED){
+        win_skip("Most W-calls are not implemented\n");
+        return;
+    }
+
+    hres = SHGetDesktopFolder(&psf);
+    ok(hres == S_OK, "SHGetDesktopFolder failed: 0x%08x\n", hres);
+    if(FAILED(hres)){
+        win_skip("Failed to get IShellFolder, can't run tests\n");
+        return;
+    }
+
+    /* fails on unknown dir with no IBindCtx */
+    hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, adirW, NULL, &pidl, NULL);
+    ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
+    hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afileW, NULL, &pidl, NULL);
+    ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
+    hres = IShellFolder_ParseDisplayName(psf, NULL, NULL, afile2W, NULL, &pidl, NULL);
+    ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
+
+    /* fails on unknown dir with IBindCtx with no IFileSystemBindData */
+    hres = CreateBindCtx(0, &pbc);
+    ok(hres == S_OK, "CreateBindCtx failed: 0x%08x\n", hres);
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
+    ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
+    ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
+    ok(hres == exp_err || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed with wrong error: 0x%08x\n", hres);
+
+    /* unknown dir with IBindCtx with IFileSystemBindData */
+    hres = IBindCtx_RegisterObjectParam(pbc, wFileSystemBindData, (IUnknown*)&fsbd);
+    ok(hres == S_OK, "RegisterObjectParam failed: 0x%08x\n", hres);
+
+    /* return E_FAIL from GetFindData */
+    pidl = (ITEMIDLIST*)0xdeadbeef;
+    fsbdVtbl.GetFindData = fsbd_GetFindData_fail;
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, adirW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afileW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afile2W);
+        ILFree(pidl);
+    }
+
+    /* set FIND_DATA struct to NULLs */
+    pidl = (ITEMIDLIST*)0xdeadbeef;
+    fsbdVtbl.GetFindData = fsbd_GetFindData_nul;
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, adirW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afileW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afile2W);
+        ILFree(pidl);
+    }
+
+    /* set FIND_DATA struct to junk */
+    pidl = (ITEMIDLIST*)0xdeadbeef;
+    fsbdVtbl.GetFindData = fsbd_GetFindData_junk;
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, adirW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afileW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afile2W);
+        ILFree(pidl);
+    }
+
+    /* set FIND_DATA struct to invalid data */
+    pidl = (ITEMIDLIST*)0xdeadbeef;
+    fsbdVtbl.GetFindData = fsbd_GetFindData_invalid;
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, adirW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afileW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afile2W);
+        ILFree(pidl);
+    }
+
+    /* set FIND_DATA struct to valid data */
+    pidl = (ITEMIDLIST*)0xdeadbeef;
+    fsbdVtbl.GetFindData = fsbd_GetFindData_valid;
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, adirW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, adirW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afileW, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afileW);
+        ILFree(pidl);
+    }
+
+    hres = IShellFolder_ParseDisplayName(psf, NULL, pbc, afile2W, NULL, &pidl, NULL);
+    ok(hres == S_OK || broken(hres == E_FAIL) /* NT4 */,
+            "ParseDisplayName failed: 0x%08x\n", hres);
+    if(SUCCEEDED(hres)){
+        verify_pidl(pidl, afile2W);
+        ILFree(pidl);
+    }
+
+    IBindCtx_Release(pbc);
+    IShellFolder_Release(psf);
+}
+
+static const CHAR testwindow_class[] = "testwindow";
+#define WM_USER_NOTIFY (WM_APP+1)
+
+struct ChNotifyTest {
+    const char id[256];
+    const UINT notify_count;
+    UINT missing_events;
+    UINT signal;
+    const char path_1[256];
+    const char path_2[256];
+} chnotify_tests[] = {
+    {"MKDIR", 1, 0, SHCNE_MKDIR, "C:\\shell32_cn_test\\test", ""},
+    {"CREATE", 1, 0, SHCNE_CREATE, "C:\\shell32_cn_test\\test\\file.txt", ""},
+    {"RMDIR", 1, 0, SHCNE_RMDIR, "C:\\shell32_cn_test\\test", ""},
+};
+
+struct ChNotifyTest *exp_data;
+BOOL test_new_delivery_flag;
+
+static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
+{
+    LONG signal = (LONG)lparam;
+
+    switch(msg){
+    case WM_USER_NOTIFY:
+        if(exp_data->missing_events > 0) {
+            WCHAR *path1, *path2;
+            LPITEMIDLIST *pidls = (LPITEMIDLIST*)wparam;
+            HANDLE hLock = NULL;
+
+            if(test_new_delivery_flag) {
+                hLock = SHChangeNotification_Lock((HANDLE)wparam, lparam, &pidls, &signal);
+                ok(hLock != NULL, "SHChangeNotification_Lock returned NULL\n");
+            }
+
+            ok(exp_data->signal == signal,
+                    "%s: expected notification type %x, got: %x\n",
+                    exp_data->id, exp_data->signal, signal);
+
+            trace("verifying pidls for: %s\n", exp_data->id);
+            path1 = make_wstr(exp_data->path_1);
+            path2 = make_wstr(exp_data->path_2);
+            verify_pidl(pidls[0], path1);
+            verify_pidl(pidls[1], path2);
+            HeapFree(GetProcessHeap(), 0, path1);
+            HeapFree(GetProcessHeap(), 0, path2);
+
+            exp_data->missing_events--;
+
+            if(test_new_delivery_flag)
+                SHChangeNotification_Unlock(hLock);
+        }else
+            ok(0, "Didn't expect a WM_USER_NOTIFY message (event: %x)\n", signal);
+        return 0;
+    }
+    return DefWindowProc(hwnd, msg, wparam, lparam);
+}
+
+static void register_testwindow_class(void)
+{
+    WNDCLASSEXA cls;
+    ATOM ret;
+
+    ZeroMemory(&cls, sizeof(cls));
+    cls.cbSize = sizeof(cls);
+    cls.style = 0;
+    cls.lpfnWndProc = testwindow_wndproc;
+    cls.hInstance = GetModuleHandleA(NULL);
+    cls.lpszClassName = testwindow_class;
+
+    SetLastError(0);
+    ret = RegisterClassExA(&cls);
+    ok(ret != 0, "RegisterClassExA failed: %d\n", GetLastError());
+}
+
+/* SHCNF_FLUSH doesn't seem to work as advertised for SHCNF_PATHA, so we
+ * have to poll repeatedly for the message to appear */
+static void do_events(void)
+{
+    int c = 0;
+    while (exp_data->missing_events && (c++ < 10)){
+        MSG msg;
+        while(PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)){
+            TranslateMessage(&msg);
+            DispatchMessageA(&msg);
+        }
+        if(exp_data->missing_events)
+            Sleep(500);
+    }
+    trace("%s: took %d tries\n", exp_data->id, c);
+}
+
+static void test_SHChangeNotify(BOOL test_new_delivery)
+{
+    HWND wnd;
+    ULONG notifyID, i;
+    HRESULT hr;
+    BOOL br, has_unicode;
+    SHChangeNotifyEntry entries[1];
+    const CHAR root_dirA[] = "C:\\shell32_cn_test";
+    const WCHAR root_dirW[] = {'C',':','\\','s','h','e','l','l','3','2','_','c','n','_','t','e','s','t',0};
+
+    trace("SHChangeNotify tests (%x)\n", test_new_delivery);
+
+    CreateDirectoryW(NULL, NULL);
+    has_unicode = !(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED);
+
+    test_new_delivery_flag = test_new_delivery;
+    if(!test_new_delivery)
+        register_testwindow_class();
+
+    wnd = CreateWindowExA(0, testwindow_class, testwindow_class, 0,
+            CW_USEDEFAULT, CW_USEDEFAULT, 130, 105,
+            NULL, NULL, GetModuleHandleA(NULL), 0);
+    ok(wnd != NULL, "Failed to make a window\n");
+
+    br = CreateDirectoryA(root_dirA, NULL);
+    ok(br == TRUE, "CreateDirectory failed: %d\n", GetLastError());
+
+    entries[0].pidl = NULL;
+    if(has_unicode)
+        hr = SHILCreateFromPath(root_dirW, (LPITEMIDLIST*)&entries[0].pidl, 0);
+    else
+        hr = SHILCreateFromPath((LPCVOID)root_dirA, (LPITEMIDLIST*)&entries[0].pidl, 0);
+    ok(hr == S_OK, "SHILCreateFromPath failed: 0x%08x\n", hr);
+    entries[0].fRecursive = TRUE;
+
+    notifyID = SHChangeNotifyRegister(wnd, !test_new_delivery ? SHCNRF_ShellLevel : SHCNRF_ShellLevel|SHCNRF_NewDelivery,
+            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){
+        exp_data = chnotify_tests + i;
+
+        exp_data->missing_events = exp_data->notify_count;
+        SHChangeNotify(exp_data->signal, SHCNF_PATHA | SHCNF_FLUSH,
+                strlen(exp_data->path_1) > 0 ? exp_data->path_1 : NULL,
+                strlen(exp_data->path_2) > 0 ? exp_data->path_2 : NULL);
+        do_events();
+        ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
+
+        if(has_unicode){
+            WCHAR *path1, *path2;
+
+            path1 = make_wstr(exp_data->path_1);
+            path2 = make_wstr(exp_data->path_2);
+
+            exp_data->missing_events = exp_data->notify_count;
+            SHChangeNotify(exp_data->signal, SHCNF_PATHW | SHCNF_FLUSH, path1, path2);
+            do_events();
+            ok(exp_data->missing_events == 0, "%s: Expected wndproc to be called\n", exp_data->id);
+
+            HeapFree(GetProcessHeap(), 0, path1);
+            HeapFree(GetProcessHeap(), 0, path2);
+        }
+    }
+
+    SHChangeNotifyDeregister(notifyID);
+    DestroyWindow(wnd);
+
+    ILFree((LPITEMIDLIST)entries[0].pidl);
+    br = RemoveDirectoryA(root_dirA);
+    ok(br == TRUE, "RemoveDirectory failed: %d\n", GetLastError());
+}
+
+static void test_SHCreateDefaultContextMenu(void)
+{
+    HKEY keys[16];
+    WCHAR path[MAX_PATH];
+    IShellFolder *desktop,*folder;
+    IPersistFolder2 *persist;
+    IContextMenu *cmenu;
+    LONG status;
+    LPITEMIDLIST pidlFolder, pidl_child, pidl;
+    DEFCONTEXTMENU cminfo;
+    HRESULT hr;
+    UINT i;
+    const WCHAR filename[] =
+        {'\\','t','e','s','t','d','i','r','\\','t','e','s','t','1','.','t','x','t',0};
+    if(!pSHCreateDefaultContextMenu)
+    {
+        win_skip("SHCreateDefaultContextMenu missing.\n");
+        return;
+    }
+
+    if(!pSHBindToParent)
+    {
+        skip("SHBindToParent missing.\n");
+        return;
+    }
+
+    GetCurrentDirectoryW(MAX_PATH, path);
+    if(!lstrlenW(path))
+    {
+        skip("GetCurrentDirectoryW returned an empty string.\n");
+        return;
+    }
+    lstrcatW(path, filename);
+    SHGetDesktopFolder(&desktop);
+
+    CreateFilesFolders();
+
+    hr = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &pidl, 0);
+    ok(hr == S_OK || broken(hr == E_FAIL) /* WinME */, "Got 0x%08x\n", hr);
+    if(SUCCEEDED(hr))
+    {
+
+        hr = pSHBindToParent(pidl, &IID_IShellFolder, (void**)&folder, (LPCITEMIDLIST*)&pidl_child);
+        ok(hr == S_OK, "Got 0x%08x\n", hr);
+
+        IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
+        IPersistFolder2_GetCurFolder(persist,&pidlFolder);
+        IPersistFolder2_Release(persist);
+        if(SUCCEEDED(hr))
+        {
+
+            cminfo.hwnd=NULL;
+            cminfo.pcmcb=NULL;
+            cminfo.psf=folder;
+            cminfo.pidlFolder=NULL;
+            cminfo.apidl=(LPCITEMIDLIST*)&pidl_child;
+            cminfo.cidl=1;
+            cminfo.aKeys=NULL;
+            cminfo.cKeys=0;
+            cminfo.punkAssociationInfo=NULL;
+            hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
+            ok(hr==S_OK,"Got 0x%08x\n", hr);
+            IContextMenu_Release(cmenu);
+            cminfo.pidlFolder=pidlFolder;
+            hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
+            ok(hr==S_OK,"Got 0x%08x\n", hr);
+            IContextMenu_Release(cmenu);
+            status = RegOpenKeyExA(HKEY_CLASSES_ROOT,"*",0,KEY_READ,keys);
+            if(status==ERROR_SUCCESS){
+                for(i=1;i<16;i++)
+                    keys[i]=keys[0];
+                cminfo.aKeys=keys;
+                cminfo.cKeys=16;
+                hr = pSHCreateDefaultContextMenu(&cminfo,&IID_IContextMenu,(void**)&cmenu);
+                RegCloseKey(keys[0]);
+                ok(hr==S_OK,"Got 0x%08x\n", hr);
+                IContextMenu_Release(cmenu);
+            }
+        }
+        ILFree(pidlFolder);
+        IShellFolder_Release(folder);
+    }
+    IShellFolder_Release(desktop);
+    ILFree(pidl);
+    Cleanup();
+}
+
 START_TEST(shlfolder)
 {
     init_function_pointers();
@@ -2127,10 +4595,25 @@ START_TEST(shlfolder)
     test_CallForAttributes();
     test_FolderShortcut();
     test_ITEMIDLIST_format();
+    test_SHGetFolderPathA();
     test_SHGetFolderPathAndSubDirA();
     test_LocalizedNames();
     test_SHCreateShellItem();
+    test_SHCreateShellItemArray();
     test_desktop_IPersist();
+    test_GetUIObject();
+    test_SHSimpleIDListFromPath();
+    test_ParseDisplayNamePBC();
+    test_SHGetNameFromIDList();
+    test_SHGetItemFromDataObject();
+    test_SHGetIDListFromObject();
+    test_SHGetItemFromObject();
+    test_ShellItemCompare();
+    test_SHChangeNotify(FALSE);
+    test_SHChangeNotify(TRUE);
+    test_ShellItemBindToHandler();
+    test_ShellItemGetAttributes();
+    test_SHCreateDefaultContextMenu();
 
     OleUninitialize();
 }
diff --git a/rostests/winetests/shell32/shlview.c b/rostests/winetests/shell32/shlview.c
index e3e0ef24ed5..6e974992159 100644
--- a/rostests/winetests/shell32/shlview.c
+++ b/rostests/winetests/shell32/shlview.c
@@ -78,6 +78,16 @@ static HWND subclass_listview(HWND hwnd)
 
     /* listview is a first child */
     listview = FindWindowExA(hwnd, NULL, WC_LISTVIEWA, NULL);
+    if(!listview)
+    {
+        /* .. except for some versions of Windows XP, where things
+           are slightly more complicated. */
+        HWND hwnd_tmp;
+        hwnd_tmp = FindWindowExA(hwnd, NULL, "DUIViewWndClassName", NULL);
+        hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "DirectUIHWND", NULL);
+        hwnd_tmp = FindWindowExA(hwnd_tmp, NULL, "CtrlNotifySink", NULL);
+        listview = FindWindowExA(hwnd_tmp, NULL, WC_LISTVIEWA, NULL);
+    }
 
     oldproc = (WNDPROC)SetWindowLongPtrA(listview, GWLP_WNDPROC,
                                         (LONG_PTR)listview_subclass_proc);
@@ -86,28 +96,71 @@ static HWND subclass_listview(HWND hwnd)
     return listview;
 }
 
+static UINT get_msg_count(struct msg_sequence **seq, int sequence_index, UINT message)
+{
+    struct msg_sequence *msg_seq = seq[sequence_index];
+    UINT i, count = 0;
+
+    for(i = 0; i < msg_seq->count ; i++)
+        if(msg_seq->sequence[i].message == message)
+            count++;
+
+    return count;
+}
+
+/* Checks that every message in the sequence seq is also present in
+ * the UINT array msgs */
+static void verify_msgs_in_(struct msg_sequence *seq, const UINT *msgs,
+                           const char *file, int line)
+{
+    UINT i, j, msg, failcount = 0;
+    for(i = 0; i < seq->count; i++)
+    {
+        BOOL found = FALSE;
+        msg = seq->sequence[i].message;
+        for(j = 0; msgs[j] != 0; j++)
+            if(msgs[j] == msg) found = TRUE;
+
+        if(!found)
+        {
+            failcount++;
+            trace("Unexpected message %d\n", msg);
+        }
+    }
+    ok_(file, line) (!failcount, "%d failures.\n", failcount);
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+}
+
+#define verify_msgs_in(seq, msgs)               \
+    verify_msgs_in_(seq, msgs, __FILE__, __LINE__)
+
 /* dummy IDataObject implementation */
 typedef struct {
-    const IDataObjectVtbl *lpVtbl;
+    IDataObject IDataObject_iface;
     LONG ref;
 } IDataObjectImpl;
 
 static const IDataObjectVtbl IDataObjectImpl_Vtbl;
 
+static inline IDataObjectImpl *impl_from_IDataObject(IDataObject *iface)
+{
+    return CONTAINING_RECORD(iface, IDataObjectImpl, IDataObject_iface);
+}
+
 static IDataObject* IDataObjectImpl_Construct(void)
 {
     IDataObjectImpl *obj;
 
     obj = HeapAlloc(GetProcessHeap(), 0, sizeof(*obj));
-    obj->lpVtbl = &IDataObjectImpl_Vtbl;
+    obj->IDataObject_iface.lpVtbl = &IDataObjectImpl_Vtbl;
     obj->ref = 1;
 
-    return (IDataObject*)obj;
+    return &obj->IDataObject_iface;
 }
 
 static HRESULT WINAPI IDataObjectImpl_QueryInterface(IDataObject *iface, REFIID riid, void **ppvObj)
 {
-    IDataObjectImpl *This = (IDataObjectImpl *)iface;
+    IDataObjectImpl *This = impl_from_IDataObject(iface);
 
     if (IsEqualIID(riid, &IID_IUnknown) ||
         IsEqualIID(riid, &IID_IDataObject))
@@ -126,13 +179,13 @@ static HRESULT WINAPI IDataObjectImpl_QueryInterface(IDataObject *iface, REFIID
 
 static ULONG WINAPI IDataObjectImpl_AddRef(IDataObject * iface)
 {
-    IDataObjectImpl *This = (IDataObjectImpl *)iface;
+    IDataObjectImpl *This = impl_from_IDataObject(iface);
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IDataObjectImpl_Release(IDataObject * iface)
 {
-    IDataObjectImpl *This = (IDataObjectImpl *)iface;
+    IDataObjectImpl *This = impl_from_IDataObject(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
@@ -210,28 +263,33 @@ static const IDataObjectVtbl IDataObjectImpl_Vtbl =
 
 /* dummy IShellBrowser implementation */
 typedef struct {
-    const IShellBrowserVtbl *lpVtbl;
+    IShellBrowser IShellBrowser_iface;
     LONG ref;
 } IShellBrowserImpl;
 
 static const IShellBrowserVtbl IShellBrowserImpl_Vtbl;
 
+static inline IShellBrowserImpl *impl_from_IShellBrowser(IShellBrowser *iface)
+{
+    return CONTAINING_RECORD(iface, IShellBrowserImpl, IShellBrowser_iface);
+}
+
 static IShellBrowser* IShellBrowserImpl_Construct(void)
 {
     IShellBrowserImpl *browser;
 
     browser = HeapAlloc(GetProcessHeap(), 0, sizeof(*browser));
-    browser->lpVtbl = &IShellBrowserImpl_Vtbl;
+    browser->IShellBrowser_iface.lpVtbl = &IShellBrowserImpl_Vtbl;
     browser->ref = 1;
 
-    return (IShellBrowser*)browser;
+    return &browser->IShellBrowser_iface;
 }
 
 static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
                                             REFIID riid,
                                             LPVOID *ppvObj)
 {
-    IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
+    IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
 
     *ppvObj = NULL;
 
@@ -253,13 +311,13 @@ static HRESULT WINAPI IShellBrowserImpl_QueryInterface(IShellBrowser *iface,
 
 static ULONG WINAPI IShellBrowserImpl_AddRef(IShellBrowser * iface)
 {
-    IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
+    IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
     return InterlockedIncrement(&This->ref);
 }
 
 static ULONG WINAPI IShellBrowserImpl_Release(IShellBrowser * iface)
 {
-    IShellBrowserImpl *This = (IShellBrowserImpl *)iface;
+    IShellBrowserImpl *This = impl_from_IShellBrowser(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     if (!ref)
@@ -423,7 +481,7 @@ static const struct message folderview_getselectionmarked_seq[] = {
 };
 
 static const struct message folderview_getfocused_seq[] = {
-    { LVM_GETNEXTITEM, sent|wparam|lparam, -1, LVNI_FOCUSED },
+    { LVM_GETNEXTITEM, sent|wparam|lparam|optional, -1, LVNI_FOCUSED },
     { 0 }
 };
 
@@ -451,7 +509,7 @@ static void test_IShellView_CreateViewWindow(void)
 if (0)
 {
     /* crashes on native */
-    hr = IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
+    IShellView_CreateViewWindow(view, NULL, &settings, NULL, NULL, NULL);
 }
 
     settings.ViewMode = FVM_ICON;
@@ -487,7 +545,7 @@ static void test_IFolderView(void)
     HWND hwnd_view, hwnd_list;
     PITEMID_CHILD pidl;
     HRESULT hr;
-    INT ret;
+    INT ret, count;
     POINT pt;
     LONG ref1, ref2;
     RECT r;
@@ -519,14 +577,14 @@ static void test_IFolderView(void)
 if (0)
 {
     /* crashes on Vista and Win2k8 - List not created yet case */
-    hr = IFolderView_GetSpacing(fv, &pt);
+    IFolderView_GetSpacing(fv, &pt);
 
     /* crashes on XP */
-    hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
-    hr = IFolderView_GetFocusedItem(fv, NULL);
+    IFolderView_GetSelectionMarkedItem(fv, NULL);
+    IFolderView_GetFocusedItem(fv, NULL);
 
     /* crashes on Vista+ */
-    hr = IFolderView_Item(fv, 0, NULL);
+    IFolderView_Item(fv, 0, NULL);
 }
 
     browser = IShellBrowserImpl_Construct();
@@ -570,32 +628,48 @@ if (0)
         ok(pt.x == LOWORD(ret) && pt.y == HIWORD(ret), "got (%d, %d)\n", LOWORD(ret), HIWORD(ret));
     }
 
+    /* IFolderView::ItemCount */
+if (0)
+{
+    /* crashes on XP */
+    IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
+}
+
+    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+    IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &count);
+
     /* IFolderView::GetSelectionMarkedItem */
 if (0)
 {
     /* crashes on XP */
-    hr = IFolderView_GetSelectionMarkedItem(fv, NULL);
+    IFolderView_GetSelectionMarkedItem(fv, NULL);
 }
 
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     hr = IFolderView_GetSelectionMarkedItem(fv, &ret);
-    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    if (count)
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    else
+        ok(hr == S_FALSE, "got (0x%08x)\n", hr);
     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getselectionmarked_seq,
-                                  "IFolderView::GetSelectionMarkedItem", FALSE);
+                "IFolderView::GetSelectionMarkedItem", FALSE);
 
     /* IFolderView::GetFocusedItem */
     flush_sequences(sequences, NUM_MSG_SEQUENCES);
     hr = IFolderView_GetFocusedItem(fv, &ret);
-    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    if (count)
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+    else
+        ok(hr == S_FALSE, "got (0x%08x)\n", hr);
     ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_getfocused_seq,
-                                  "IFolderView::GetFocusedItem", FALSE);
+                "IFolderView::GetFocusedItem", FALSE);
 
     /* IFolderView::GetFolder, just return pointer */
 if (0)
 {
     /* crashes on XP */
-    hr = IFolderView_GetFolder(fv, NULL, (void**)&folder);
-    hr = IFolderView_GetFolder(fv, NULL, NULL);
+    IFolderView_GetFolder(fv, NULL, (void**)&folder);
+    IFolderView_GetFolder(fv, NULL, NULL);
 }
 
     hr = IFolderView_GetFolder(fv, &IID_IShellFolder, NULL);
@@ -607,22 +681,10 @@ if (0)
     ok(hr == S_OK, "got (0x%08x)\n", hr);
     ref2 = IShellFolder_AddRef(desktop);
     IShellFolder_Release(desktop);
-    ok(ref1 == ref2, "expected same refcount, got %d\n", ref2);
+    ok(ref1 == ref2 || ref1 + 1 == ref2, /* >= vista */
+       "expected same refcount, got %d\n", ref2);
     ok(desktop == folder, "\n");
 
-    /* IFolderView::ItemCount */
-if (0)
-{
-    /* crashes on XP */
-    hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, NULL);
-}
-
-    flush_sequences(sequences, NUM_MSG_SEQUENCES);
-    hr = IFolderView_ItemCount(fv, SVGIO_ALLVIEW, &ret);
-    ok(hr == S_OK, "got (0x%08x)\n", hr);
-    ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_itemcount_seq,
-                                  "IFolderView::ItemCount", FALSE);
-
     IShellBrowser_Release(browser);
     IFolderView_Release(fv);
     IShellView_Release(view);
@@ -711,9 +773,9 @@ static void test_IShellFolderView(void)
     /* ::RemoveObject */
     i = 0xdeadbeef;
     hr = IShellFolderView_RemoveObject(folderview, NULL, &i);
-    ok(hr == S_OK, "got (0x%08x)\n", hr);
-    ok(i == 0 || i == -1 /* Win7 */ || broken(i == 0xdeadbeef) /* Vista, 2k8 */,
-        "got %d\n", i);
+    ok(hr == S_OK || hr == E_FAIL, "got (0x%08x)\n", hr);
+    if (hr == S_OK) ok(i == 0 || broken(i == 0xdeadbeef) /* Vista, 2k8 */,
+                       "got %d\n", i);
 
     IShellFolderView_Release(folderview);
 
@@ -743,6 +805,352 @@ static void test_IOleWindow(void)
     IShellFolder_Release(desktop);
 }
 
+static const struct message folderview_setcurrentviewmode1_2_prevista[] = {
+    { LVM_SETVIEW, sent|wparam, LV_VIEW_ICON},
+    { LVM_SETIMAGELIST, sent|wparam, 0},
+    { LVM_SETIMAGELIST, sent|wparam, 1},
+    { 0x105a, sent},
+    { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
+    { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
+    { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
+    { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
+    { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
+    { LVM_ARRANGE, sent },
+    { LVM_ARRANGE, sent|optional },       /* WinXP */
+    { 0 }
+};
+
+static const struct message folderview_setcurrentviewmode3_prevista[] = {
+    { LVM_SETVIEW, sent|wparam, LV_VIEW_LIST},
+    { LVM_SETIMAGELIST, sent|wparam, 0},
+    { LVM_SETIMAGELIST, sent|wparam, 1},
+    { 0x105a, sent},
+    { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
+    { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
+    { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
+    { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
+    { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
+    { 0 }
+};
+
+static const struct message folderview_setcurrentviewmode4_prevista[] = {
+    { LVM_GETHEADER, sent},
+    { LVM_GETITEMCOUNT, sent|optional },
+    { LVM_SETSELECTEDCOLUMN, sent},
+    { WM_NOTIFY, sent },
+    { WM_NOTIFY, sent },
+    { WM_NOTIFY, sent },
+    { WM_NOTIFY, sent },
+    { LVM_SETVIEW, sent|wparam, LV_VIEW_DETAILS},
+    { LVM_SETIMAGELIST, sent|wparam, 0},
+    { LVM_SETIMAGELIST, sent|wparam, 1},
+    { 0x105a, sent},
+    { LVM_SETBKIMAGEW, sent|optional},    /* w2k3 */
+    { LVM_GETBKCOLOR, sent|optional},     /* w2k3 */
+    { LVM_GETTEXTBKCOLOR, sent|optional}, /* w2k3 */
+    { LVM_GETTEXTCOLOR, sent|optional},   /* w2k3 */
+    { LVM_SETEXTENDEDLISTVIEWSTYLE, sent|optional|wparam, 0xc8}, /* w2k3 */
+    { 0 }
+};
+
+/* XP, SetCurrentViewMode(5)
+   108e - LVM_SETVIEW (LV_VIEW_ICON);
+   1036 - LVM_SETEXTEDEDLISTVIEWSTYLE (0x8000, 0)
+   100c/104c repeated X times
+   1003 - LVM_SETIMAGELIST
+   1035 - LVM_SETICONSPACING
+   1004 - LVM_GETITEMCOUNT
+   105a - ?
+   1016 - LVM_ARRANGE
+   1016 - LVM_ARRANGE
+*/
+
+/* XP, SetCurrentViewMode(6)
+   1036 - LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0)
+   1035 - LVM_SETICONSPACING
+   1003 - LVM_SETIMAGELIST
+   1003 - LVM_SETIMAGELIST
+   100c/104c repeated X times
+   10a2 - LVM_SETTILEVIEWINFO
+   108e - LVM_SETVIEW (LV_VIEW_TILE)
+   1003 - LVM_SETIMAGELIST
+   105a - ?
+   1016 - LVM_ARRANGE
+   1016 - LVM_ARRANGE
+*/
+
+/* XP, SetCurrentViewMode (7)
+   10a2 - LVM_SETTILEVIEWINFO
+   108e - LVM_SETVIEW (LV_VIEW_ICON)
+   1004/10a4 (LVM_GETITEMCOUNT/LVM_SETTILEINFO) X times
+   1016 - LVM_ARRANGE
+   1016 - LVM_ARRANGE
+   ...
+   LVM_SETEXTENDEDLISTVIEWSTYLE (0x40000, 0x40000)
+   ...
+   LVM_SETEXTENDEDLISTVIEWSTYLE (0x8000, 0x8000)
+*/
+
+static void test_GetSetCurrentViewMode(void)
+{
+    IShellFolder *desktop;
+    IShellView *sview;
+    IFolderView *fview;
+    IShellBrowser *browser;
+    FOLDERSETTINGS fs;
+    UINT viewmode;
+    HWND hwnd;
+    RECT rc = {0, 0, 10, 10};
+    HRESULT hr;
+    UINT i;
+    static const int winxp_res[11] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    static const int win2k3_res[11] = {0, 1, 2, 3, 4, 5, 6, 5, 8, 0, 0};
+    static const int vista_res[11] = {0, 1, 5, 3, 4, 5, 6, 7, 7, 0, 0};
+    static const int win7_res[11] = {1, 1, 1, 3, 4, 1, 6, 1, 8, 8, 8};
+
+    hr = SHGetDesktopFolder(&desktop);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    hr = IShellFolder_CreateViewObject(desktop, NULL, &IID_IShellView, (void**)&sview);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    fs.ViewMode = 1;
+    fs.fFlags = 0;
+    browser = IShellBrowserImpl_Construct();
+    hr = IShellView_CreateViewWindow(sview, NULL, &fs, browser, &rc, &hwnd);
+    ok(hr == S_OK || broken(hr == S_FALSE /*Win2k*/ ), "got (0x%08x)\n", hr);
+
+    hr = IShellView_QueryInterface(sview, &IID_IFolderView, (void**)&fview);
+    ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got (0x%08x)\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        HWND hwnd_lv;
+        UINT count;
+
+        if (0)
+        {
+            /* Crashes under Win7/WinXP */
+            IFolderView_GetCurrentViewMode(fview, NULL);
+        }
+
+        hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+        ok(viewmode == 1, "ViewMode was %d\n", viewmode);
+
+        hr = IFolderView_SetCurrentViewMode(fview, FVM_AUTO);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        hr = IFolderView_SetCurrentViewMode(fview, 0);
+        ok(hr == E_INVALIDARG || broken(hr == S_OK),
+           "got (0x%08x)\n", hr);
+
+        hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
+        ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+        for(i = 1; i < 9; i++)
+        {
+            hr = IFolderView_SetCurrentViewMode(fview, i);
+            ok(hr == S_OK || (i == 8 && hr == E_INVALIDARG /*Vista*/),
+               "(%d) got (0x%08x)\n", i, hr);
+
+            hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
+            ok(hr == S_OK, "(%d) got (0x%08x)\n", i, hr);
+
+            /* Wine currently behaves like winxp here. */
+            ok((viewmode == win7_res[i]) || (viewmode == vista_res[i]) ||
+               (viewmode == win2k3_res[i]) || (viewmode == winxp_res[i]),
+               "(%d) got %d\n",i , viewmode);
+        }
+
+        hr = IFolderView_SetCurrentViewMode(fview, 9);
+        ok(hr == E_INVALIDARG || broken(hr == S_OK),
+           "got (0x%08x)\n", hr);
+
+        /* Test messages */
+        hwnd_lv = subclass_listview(hwnd);
+        ok(hwnd_lv != NULL, "Failed to subclass listview\n");
+        if(hwnd_lv)
+        {
+            /* Vista seems to set the viewmode by other means than
+               sending messages. At least no related messages are
+               captured by subclassing.
+            */
+            BOOL vista_plus = FALSE;
+            static const UINT vista_plus_msgs[] = {
+                WM_SETREDRAW, WM_NOTIFY, WM_NOTIFYFORMAT, WM_QUERYUISTATE,
+                WM_MENUCHAR, WM_WINDOWPOSCHANGING, WM_NCCALCSIZE, WM_WINDOWPOSCHANGED,
+                WM_PARENTNOTIFY, LVM_GETHEADER, 0 };
+
+            flush_sequences(sequences, NUM_MSG_SEQUENCES);
+            hr = IFolderView_SetCurrentViewMode(fview, 1);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+
+            /* WM_SETREDRAW is not sent in versions before Vista. */
+            vista_plus = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, WM_SETREDRAW);
+            if(vista_plus)
+                verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+            else
+                ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
+                            "IFolderView::SetCurrentViewMode(1)", TRUE);
+
+            hr = IFolderView_SetCurrentViewMode(fview, 2);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+            if(vista_plus)
+                verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+            else
+                ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode1_2_prevista,
+                            "IFolderView::SetCurrentViewMode(2)", TRUE);
+
+            hr = IFolderView_SetCurrentViewMode(fview, 3);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+            if(vista_plus)
+                verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+            else
+                ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode3_prevista,
+                            "IFolderView::SetCurrentViewMode(3)", TRUE);
+
+            hr = IFolderView_SetCurrentViewMode(fview, 4);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+            if(vista_plus)
+                verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+            else
+                ok_sequence(sequences, LISTVIEW_SEQ_INDEX, folderview_setcurrentviewmode4_prevista,
+                            "IFolderView::SetCurrentViewMode(4)", TRUE);
+
+            hr = IFolderView_SetCurrentViewMode(fview, 5);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+            todo_wine
+            {
+                if(vista_plus)
+                {
+                    verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+                }
+                else
+                {
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
+                    ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
+                    ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
+                    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+                }
+            }
+
+            hr = IFolderView_SetCurrentViewMode(fview, 6);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+            todo_wine
+            {
+                if(vista_plus)
+                {
+                    verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+                }
+                else
+                {
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
+                    ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
+                    ok(count == 1 || count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
+                    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+                }
+            }
+
+            hr = IFolderView_SetCurrentViewMode(fview, 7);
+            ok(hr == S_OK, "got 0x%08x\n", hr);
+            todo_wine
+            {
+                if(vista_plus)
+                {
+                    verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+                }
+                else
+                {
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
+                    ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
+                    ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
+                    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+                }
+            }
+
+            hr = IFolderView_SetCurrentViewMode(fview, 8);
+            ok(hr == S_OK || broken(hr == E_INVALIDARG /* Vista */), "got 0x%08x\n", hr);
+            todo_wine
+            {
+                if(vista_plus)
+                {
+                    verify_msgs_in(sequences[LISTVIEW_SEQ_INDEX], vista_plus_msgs);
+                }
+                else
+                {
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETVIEW);
+                    ok(count == 1, "LVM_SETVIEW sent %d times.\n", count);
+                    count = get_msg_count(sequences, LISTVIEW_SEQ_INDEX, LVM_SETEXTENDEDLISTVIEWSTYLE);
+                    ok(count == 2, "LVM_SETEXTENDEDLISTVIEWSTYLE sent %d times.\n", count);
+                    flush_sequences(sequences, NUM_MSG_SEQUENCES);
+                }
+            }
+
+            hr = IFolderView_GetCurrentViewMode(fview, &viewmode);
+            ok(hr == S_OK, "Failed to get current viewmode.\n");
+            ok_sequence(sequences, LISTVIEW_SEQ_INDEX, empty_seq,
+                        "IFolderView::GetCurrentViewMode", FALSE);
+        }
+
+        IFolderView_Release(fview);
+    }
+    else
+    {
+        skip("No IFolderView for the desktop folder.\n");
+    }
+
+    IShellBrowser_Release(browser);
+    IShellView_DestroyViewWindow(sview);
+    IShellView_Release(sview);
+    IShellFolder_Release(desktop);
+}
+
+static void test_IOleCommandTarget(void)
+{
+    IShellFolder *psf_desktop;
+    IShellView *psv;
+    IOleCommandTarget *poct;
+    HRESULT hr;
+
+    hr = SHGetDesktopFolder(&psf_desktop);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+
+    hr = IShellFolder_CreateViewObject(psf_desktop, NULL, &IID_IShellView, (void**)&psv);
+    ok(hr == S_OK, "got (0x%08x)\n", hr);
+    if(SUCCEEDED(hr))
+    {
+        hr = IShellView_QueryInterface(psv, &IID_IOleCommandTarget, (void**)&poct);
+        ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* Win95/NT4 */, "Got 0x%08x\n", hr);
+        if(SUCCEEDED(hr))
+        {
+            OLECMD oc;
+
+            hr = IOleCommandTarget_QueryStatus(poct, NULL, 0, NULL, NULL);
+            ok(hr == E_INVALIDARG, "Got 0x%08x\n", hr);
+
+            oc.cmdID = 1;
+            hr = IOleCommandTarget_QueryStatus(poct, NULL, 0, &oc, NULL);
+            ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
+
+            oc.cmdID = 1;
+            hr = IOleCommandTarget_QueryStatus(poct, NULL, 1, &oc, NULL);
+            ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
+
+            hr = IOleCommandTarget_Exec(poct, NULL, 0, 0, NULL, NULL);
+            ok(hr == OLECMDERR_E_UNKNOWNGROUP, "Got 0x%08x\n", hr);
+
+            IOleCommandTarget_Release(poct);
+        }
+
+        IShellView_Release(psv);
+    }
+
+    IShellFolder_Release(psf_desktop);
+}
+
 START_TEST(shlview)
 {
     OleInitialize(NULL);
@@ -754,6 +1162,8 @@ START_TEST(shlview)
     test_GetItemObject();
     test_IShellFolderView();
     test_IOleWindow();
+    test_GetSetCurrentViewMode();
+    test_IOleCommandTarget();
 
     OleUninitialize();
 }
diff --git a/rostests/winetests/shell32/systray.c b/rostests/winetests/shell32/systray.c
index 1f505ecfca3..23d30341dad 100644
--- a/rostests/winetests/shell32/systray.c
+++ b/rostests/winetests/shell32/systray.c
@@ -45,19 +45,15 @@ static void test_cbsize(void)
         nidW.hIcon = LoadIcon(NULL, IDI_APPLICATION);
         nidW.uCallbackMessage = WM_USER+17;
         ret = pShell_NotifyIconW(NIM_ADD, &nidW);
-        if (ret)
-        {
-            /* using an invalid cbSize does work */
-            nidW.cbSize = 3;
-            nidW.hWnd = hMainWnd;
-            nidW.uID = 1;
-            ret = pShell_NotifyIconW(NIM_DELETE, &nidW);
-            ok( ret || broken(!ret), /* nt4 */ "NIM_DELETE failed!\n");
-            /* as icon doesn't exist anymore - now there will be an error */
-            nidW.cbSize = sizeof(nidW);
-            ok(!pShell_NotifyIconW(NIM_DELETE, &nidW) != !ret, "The icon was not deleted\n");
-        }
-        else win_skip( "Shell_NotifyIconW not working\n" );  /* win9x */
+        /* using an invalid cbSize does work */
+        nidW.cbSize = 3;
+        nidW.hWnd = hMainWnd;
+        nidW.uID = 1;
+        ret = pShell_NotifyIconW(NIM_DELETE, &nidW);
+        ok( ret || broken(!ret), /* nt4 */ "NIM_DELETE failed!\n");
+        /* as icon doesn't exist anymore - now there will be an error */
+        nidW.cbSize = sizeof(nidW);
+        ok(!pShell_NotifyIconW(NIM_DELETE, &nidW) != !ret, "The icon was not deleted\n");
     }
 
     /* same for Shell_NotifyIconA */
@@ -75,7 +71,7 @@ static void test_cbsize(void)
     nidA.hWnd = hMainWnd;
     nidA.uID = 1;
     ret = Shell_NotifyIconA(NIM_DELETE, &nidA);
-    ok( ret || broken(!ret),  /* win9x */ "NIM_DELETE failed!\n");
+    ok(ret, "NIM_DELETE failed!\n");
     /* as icon doesn't exist anymore - now there will be an error */
     nidA.cbSize = sizeof(nidA);
     ok(!Shell_NotifyIconA(NIM_DELETE, &nidA) != !ret, "The icon was not deleted\n");
diff --git a/rostests/winetests/shell32/testlist.c b/rostests/winetests/shell32/testlist.c
index 8f9119596c9..67bafbcda31 100644
--- a/rostests/winetests/shell32/testlist.c
+++ b/rostests/winetests/shell32/testlist.c
@@ -8,9 +8,14 @@
 
 extern void func_appbar(void);
 extern void func_autocomplete(void);
+extern void func_brsfolder(void);
+extern void func_ebrowser(void);
 extern void func_generated(void);
 extern void func_progman_dde(void);
+extern void func_recyclebin(void);
+extern void func_shelldispatch(void);
 extern void func_shelllink(void);
+extern void func_shellole(void);
 extern void func_shellpath(void);
 extern void func_shfldr_special(void);
 extern void func_shlexec(void);
@@ -22,17 +27,22 @@ extern void func_systray(void);
 
 const struct test winetest_testlist[] =
 {
-    { "appbar", func_appbar },  
-	{ "autocomplete", func_autocomplete },
-	{ "generated", func_generated },
-	{ "progman_dde", func_progman_dde },
+    { "appbar", func_appbar },
+    { "autocomplete", func_autocomplete },
+    { "brsfolder", func_brsfolder },
+    { "ebrowser", func_ebrowser },
+    { "generated", func_generated },
+    { "progman_dde", func_progman_dde },
+    { "recyclebin", func_recyclebin },
+    { "shelldispatch", func_shelldispatch },
     { "shelllink", func_shelllink },
+    { "shellole", func_shellole },
     { "shellpath", func_shellpath },
-	{ "shfldr_special", func_shfldr_special },
+    { "shfldr_special", func_shfldr_special },
     { "shlexec", func_shlexec },
     { "shlfileop", func_shlfileop },
     { "shlfolder", func_shlfolder },
-	{ "shlview", func_shlview },
+    { "shlview", func_shlview },
     { "string", func_string },
     { "systray", func_systray },
     { 0, 0 }