From caffc9f55759718c04299cd169c1b82751f2bb4c Mon Sep 17 00:00:00 2001 From: David Hedberg Date: Sun, 25 Jul 2010 19:08:15 +0200 Subject: [PATCH] shell32: Implement IShellItem::Compare. --- dlls/shell32/shellitem.c | 46 ++++++- dlls/shell32/tests/shlfolder.c | 227 +++++++++++++++++++++++++++++++++ include/shobjidl.idl | 7 + 3 files changed, 278 insertions(+), 2 deletions(-) diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c index 27b2d53f6cb..bbd85e66f55 100644 --- a/dlls/shell32/shellitem.c +++ b/dlls/shell32/shellitem.c @@ -209,9 +209,51 @@ static HRESULT WINAPI ShellItem_GetAttributes(IShellItem *iface, SFGAOF sfgaoMas static HRESULT WINAPI ShellItem_Compare(IShellItem *iface, IShellItem *oth, SICHINTF hint, int *piOrder) { - FIXME("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder); + LPWSTR dispname, dispname_oth; + HRESULT ret; + TRACE("(%p,%p,%x,%p)\n", iface, oth, hint, piOrder); - return E_NOTIMPL; + if(hint & (SICHINT_CANONICAL | SICHINT_ALLFIELDS)) + FIXME("Unsupported flags 0x%08x\n", hint); + + ret = IShellItem_GetDisplayName(iface, SIGDN_DESKTOPABSOLUTEEDITING, &dispname); + if(SUCCEEDED(ret)) + { + ret = IShellItem_GetDisplayName(oth, SIGDN_DESKTOPABSOLUTEEDITING, &dispname_oth); + if(SUCCEEDED(ret)) + { + *piOrder = lstrcmpiW(dispname, dispname_oth); + CoTaskMemFree(dispname_oth); + } + CoTaskMemFree(dispname); + } + + if(SUCCEEDED(ret) && *piOrder && + (hint & SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL)) + { + LPWSTR dispname, dispname_oth; + + TRACE("Testing filesystem path.\n"); + ret = IShellItem_GetDisplayName(iface, SIGDN_FILESYSPATH, &dispname); + if(SUCCEEDED(ret)) + { + ret = IShellItem_GetDisplayName(oth, SIGDN_FILESYSPATH, &dispname_oth); + if(SUCCEEDED(ret)) + { + *piOrder = lstrcmpiW(dispname, dispname_oth); + CoTaskMemFree(dispname_oth); + } + CoTaskMemFree(dispname); + } + } + + if(FAILED(ret)) + return ret; + + if(*piOrder) + return S_FALSE; + else + return S_OK; } static const IShellItemVtbl ShellItem_Vtbl = { diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c index 4a81b950bff..2781b233c9c 100644 --- a/dlls/shell32/tests/shlfolder.c +++ b/dlls/shell32/tests/shlfolder.c @@ -2414,6 +2414,232 @@ static void test_SHGetItemFromDataObject(void) IShellFolder_Release(psfdesktop); } +static void test_ShellItemCompare(void) +{ + IShellItem *psi[9]; /* a\a, a\b, a\c, b\a, .. */ + IShellItem *psi_a, *psi_b, *psi_c; + 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); + + /* Generate ShellItems for the files */ + ZeroMemory(&psi, sizeof(IShellItem*)*9); + 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 */ + psi_a = psi_b = psi_c = NULL; + 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) */ + hr = IShellItem_Compare(psi_a, NULL, 0, NULL); + hr = IShellItem_Compare(psi_a, psi_b, 0, NULL); + hr = 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 { @@ -3213,6 +3439,7 @@ START_TEST(shlfolder) test_SHGetItemFromDataObject(); test_SHGetIDListFromObject(); test_SHGetItemFromObject(); + test_ShellItemCompare(); OleUninitialize(); } diff --git a/include/shobjidl.idl b/include/shobjidl.idl index 8a90f64d936..6bd6b07c725 100644 --- a/include/shobjidl.idl +++ b/include/shobjidl.idl @@ -358,6 +358,13 @@ interface IShellItem : IUnknown SIGDN_PARENTRELATIVE = 0x80080001 } SIGDN; /* & 0xFFFF => SHGDN */ + [v1_enum] enum _SICHINTF + { + SICHINT_DISPLAY = 0x00000000, + SICHINT_CANONICAL = 0x10000000, + SICHINT_TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000, + SICHINT_ALLFIELDS = 0x80000000 + }; typedef DWORD SICHINTF; HRESULT BindToHandler(