[PATCH 1/6] shell32: Implement SHGetNameFromIDList and IShellItem::GetDisplayName.

David Hedberg david.hedberg at gmail.com
Wed Jul 21 14:45:59 CDT 2010


---
 dlls/shell32/pidl.c            |   62 +++++++++++++++
 dlls/shell32/shell32.spec      |    1 +
 dlls/shell32/shellitem.c       |    7 +-
 dlls/shell32/tests/shlfolder.c |  162 ++++++++++++++++++++++++++++++++++++++--
 include/shobjidl.idl           |    2 +
 5 files changed, 223 insertions(+), 11 deletions(-)

diff --git a/dlls/shell32/pidl.c b/dlls/shell32/pidl.c
index dffa2bd..9ec0dd4 100644
--- a/dlls/shell32/pidl.c
+++ b/dlls/shell32/pidl.c
@@ -1347,6 +1347,68 @@ HRESULT WINAPI SHParseDisplayName(LPCWSTR name, IBindCtx *bindctx, LPITEMIDLIST
     return hr;
 }
 
+/*************************************************************************
+ * SHGetNameFromIDList             [SHELL32.@]
+ */
+HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName)
+{
+    IShellFolder *psfparent;
+    LPCITEMIDLIST child_pidl;
+    STRRET disp_name;
+    HRESULT ret;
+
+    TRACE("%p %d %p\n", pidl, sigdnName, ppszName);
+
+    *ppszName = NULL;
+    ret = SHBindToParent(pidl, &IID_IShellFolder, (void**)&psfparent, &child_pidl);
+    if(SUCCEEDED(ret))
+    {
+        switch(sigdnName)
+        {
+                                                /* sigdnName & 0xffff */
+        case SIGDN_NORMALDISPLAY:               /* SHGDN_NORMAL */
+        case SIGDN_PARENTRELATIVEPARSING:       /* SHGDN_INFOLDER | SHGDN_FORPARSING */
+        case SIGDN_PARENTRELATIVEEDITING:       /* SHGDN_INFOLDER | SHGDN_FOREDITING */
+        case SIGDN_DESKTOPABSOLUTEPARSING:      /* SHGDN_FORPARSING */
+        case SIGDN_DESKTOPABSOLUTEEDITING:      /* SHGDN_FOREDITING | SHGDN_FORADDRESSBAR*/
+        case SIGDN_PARENTRELATIVEFORADDRESSBAR: /* SIGDN_INFOLDER | SHGDN_FORADDRESSBAR */
+        case SIGDN_PARENTRELATIVE:              /* SIGDN_INFOLDER */
+
+            disp_name.uType = STRRET_WSTR;
+            ret = IShellFolder_GetDisplayNameOf(psfparent, child_pidl,
+                                                sigdnName & 0xffff,
+                                                &disp_name);
+            if(SUCCEEDED(ret))
+                ret = StrRetToStrW(&disp_name, pidl, ppszName);
+
+            break;
+
+        case SIGDN_FILESYSPATH:
+            *ppszName = CoTaskMemAlloc(sizeof(WCHAR)*MAX_PATH);
+            if(SHGetPathFromIDListW(pidl, *ppszName))
+            {
+                TRACE("Got string %s\n", debugstr_w(*ppszName));
+                ret = S_OK;
+            }
+            else
+            {
+                CoTaskMemFree(*ppszName);
+                ret = E_INVALIDARG;
+            }
+            break;
+
+        case SIGDN_URL:
+        default:
+            FIXME("Unsupported SIGDN %x\n", sigdnName);
+            ret = E_FAIL;
+        }
+
+        IShellFolder_Release(psfparent);
+    }
+
+    return ret;
+}
+
 /**************************************************************************
  *
  *        internal functions
diff --git a/dlls/shell32/shell32.spec b/dlls/shell32/shell32.spec
index 09743e8..07f97af 100644
--- a/dlls/shell32/shell32.spec
+++ b/dlls/shell32/shell32.spec
@@ -360,6 +360,7 @@
 @ stdcall SHGetInstanceExplorer(long)
 @ stdcall SHGetLocalizedName(wstr ptr long ptr)
 @ stdcall SHGetMalloc(ptr)
+@ stdcall SHGetNameFromIDList(ptr long ptr)
 @ stdcall SHGetNewLinkInfo(str str ptr long long) SHGetNewLinkInfoA
 @ stdcall SHGetPathFromIDList(ptr ptr) SHGetPathFromIDListA
 @ stdcall SHGetPathFromIDListA(ptr ptr)
diff --git a/dlls/shell32/shellitem.c b/dlls/shell32/shellitem.c
index 29f072f..ae6de18 100644
--- a/dlls/shell32/shellitem.c
+++ b/dlls/shell32/shellitem.c
@@ -178,11 +178,10 @@ static HRESULT WINAPI ShellItem_GetParent(IShellItem *iface, IShellItem **ppsi)
 static HRESULT WINAPI ShellItem_GetDisplayName(IShellItem *iface, SIGDN sigdnName,
     LPWSTR *ppszName)
 {
-    FIXME("(%p,%x,%p)\n", iface, sigdnName, ppszName);
-
-    *ppszName = NULL;
+    ShellItem *This = (ShellItem*)iface;
+    TRACE("(%p,%x,%p)\n", iface, sigdnName, ppszName);
 
-    return E_NOTIMPL;
+    return SHGetNameFromIDList(This->pidl, sigdnName, ppszName);
 }
 
 static HRESULT WINAPI ShellItem_GetAttributes(IShellItem *iface, SFGAOF sfgaoMask,
diff --git a/dlls/shell32/tests/shlfolder.c b/dlls/shell32/tests/shlfolder.c
index 210631d..edb58dd 100644
--- a/dlls/shell32/tests/shlfolder.c
+++ b/dlls/shell32/tests/shlfolder.c
@@ -46,6 +46,7 @@ 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);
@@ -55,6 +56,7 @@ static BOOL (WINAPI *pILIsEqual)(LPCITEMIDLIST, LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHCreateShellItem)(LPCITEMIDLIST,IShellFolder*,LPCITEMIDLIST,IShellItem**);
 static LPITEMIDLIST (WINAPI *pILCombine)(LPCITEMIDLIST,LPCITEMIDLIST);
 static HRESULT (WINAPI *pSHParseDisplayName)(LPCWSTR,IBindCtx*,LPITEMIDLIST*,SFGAOF,SFGAOF*);
+static HRESULT (WINAPI *pSHGetNameFromIDList)(PCIDLIST_ABSOLUTE,SIGDN,PWSTR*);
 
 static void init_function_pointers(void)
 {
@@ -72,7 +74,9 @@ static void init_function_pointers(void)
     MAKEFUNC(SHGetPathFromIDListW);
     MAKEFUNC(SHGetSpecialFolderPathA);
     MAKEFUNC(SHGetSpecialFolderPathW);
+    MAKEFUNC(SHGetSpecialFolderLocation);
     MAKEFUNC(SHParseDisplayName);
+    MAKEFUNC(SHGetNameFromIDList);
 #undef MAKEFUNC
 
 #define MAKEFUNC_ORD(f, ord) (p##f = (void*)GetProcAddress(hmod, (LPSTR)(ord)))
@@ -985,9 +989,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 +1101,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);
 
@@ -2042,6 +2041,154 @@ static void test_SHCreateShellItem(void)
     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 */
+        hres = 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);
+
+        hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
+        ok(hrSI == S_OK, "Got 0x%08x\n", hrSI);
+        res = SHGetPathFromIDListW(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);
+
+        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);
+
+        hrSI = pSHGetNameFromIDList(pidl, SIGDN_FILESYSPATH, &nameSI);
+        ok(hrSI == E_INVALIDARG, "Got 0x%08x\n", hrSI);
+        res = SHGetPathFromIDListW(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);
+
+        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_SHParseDisplayName(void)
 {
     LPITEMIDLIST pidl1, pidl2;
@@ -2286,6 +2433,7 @@ START_TEST(shlfolder)
     test_SHCreateShellItem();
     test_desktop_IPersist();
     test_GetUIObject();
+    test_SHGetNameFromIDList();
 
     OleUninitialize();
 }
diff --git a/include/shobjidl.idl b/include/shobjidl.idl
index d634d53..be85fbb 100644
--- a/include/shobjidl.idl
+++ b/include/shobjidl.idl
@@ -494,6 +494,8 @@ interface IShellItemArray : IUnknown
 
 }
 
+cpp_quote("HRESULT WINAPI SHGetNameFromIDList(PCIDLIST_ABSOLUTE pidl, SIGDN sigdnName, PWSTR *ppszName);")
+
 /*****************************************************************************
  * IShellItemFilter interface
  */
-- 
1.7.1.1




More information about the wine-patches mailing list