[SHLWAPI][SHLWAPI_APITEST][SDK] Implement IShellFolder_GetDisplayNameOf (#6918)

This export function is needed to implement
shell32!SHGetRealIDL function correctly.
JIRA issue: CORE-19278
- Implement IShellFolder_GetDisplayNameOf
  function (This function is not inline function in
  this case) with retry data.
- Add SFGDNO_RETRYALWAYS flag to
  <shlwapi_undoc.h>.
- Add IShellFolderHelpers testcase.
This commit is contained in:
Katayama Hirofumi MZ 2024-05-23 22:57:31 +09:00 committed by GitHub
parent f69e256376
commit 53518bbab3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 360 additions and 7 deletions

View file

@ -140,16 +140,36 @@ SHLWAPI_IsBogusHRESULT(HRESULT hr)
return (hr == E_FAIL || hr == E_INVALIDARG || hr == E_NOTIMPL);
}
// Used for IShellFolder_GetDisplayNameOf
struct RETRY_DATA
{
SHGDNF uRemove;
SHGDNF uAdd;
DWORD dwRetryFlags;
};
static const RETRY_DATA g_RetryData[] =
{
{ SHGDN_FOREDITING, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
{ SHGDN_FORADDRESSBAR, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
{ SHGDN_NORMAL, SHGDN_FORPARSING, SFGDNO_RETRYALWAYS },
{ SHGDN_FORPARSING, SHGDN_NORMAL, SFGDNO_RETRYWITHFORPARSING },
{ SHGDN_INFOLDER, SHGDN_NORMAL, SFGDNO_RETRYALWAYS },
};
/*************************************************************************
* IShellFolder_GetDisplayNameOf [SHLWAPI.316]
*
* @note Don't confuse with <shobjidl.h> inline function of the same name.
* If the original call fails with the given uFlags, this function will
* retry with other flags to attempt retrieving any meaningful description.
*/
EXTERN_C HRESULT WINAPI
IShellFolder_GetDisplayNameOf(
_In_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ DWORD uFlags,
_In_ SHGDNF uFlags,
_Out_ LPSTRRET lpName,
_In_ DWORD dwRetryFlags)
_In_ DWORD dwRetryFlags) // dwRetryFlags is an additional parameter
{
HRESULT hr;
@ -159,19 +179,37 @@ IShellFolder_GetDisplayNameOf(
if (!SHLWAPI_IsBogusHRESULT(hr))
return hr;
dwRetryFlags |= 0x80000000;
dwRetryFlags |= SFGDNO_RETRYALWAYS;
if ((uFlags & SHGDN_FORPARSING) == 0)
dwRetryFlags |= SFGDNO_RETRYWITHFORPARSING;
/* It seems the function is actually retrying here */
FIXME("dwRetryFlags: 0x%X\n", dwRetryFlags);
// Retry with other flags to get successful results
for (SIZE_T iEntry = 0; iEntry < _countof(g_RetryData); ++iEntry)
{
const RETRY_DATA *pData = &g_RetryData[iEntry];
if (!(dwRetryFlags & pData->dwRetryFlags))
continue;
SHGDNF uNewFlags = ((uFlags & ~pData->uRemove) | pData->uAdd);
if (uNewFlags == uFlags)
continue;
hr = psf->GetDisplayNameOf(pidl, uNewFlags, lpName);
if (!SHLWAPI_IsBogusHRESULT(hr))
break;
uFlags = uNewFlags; // Update flags every time
}
return hr;
}
/*************************************************************************
* IShellFolder_ParseDisplayName [SHLWAPI.317]
*
* @note Don't confuse with <shobjidl.h> inline function of the same name.
* This function is safer than IShellFolder::ParseDisplayName.
*/
EXTERN_C HRESULT WINAPI
IShellFolder_ParseDisplayName(
@ -209,6 +247,9 @@ IShellFolder_ParseDisplayName(
/*************************************************************************
* IShellFolder_CompareIDs [SHLWAPI.551]
*
* @note Don't confuse with <shobjidl.h> inline function of the same name.
* This function tries IShellFolder2 if possible.
*/
EXTERN_C HRESULT WINAPI
IShellFolder_CompareIDs(

View file

@ -6,6 +6,7 @@ include_directories($<TARGET_FILE_DIR:shlwapi_resource_dll>)
list(APPEND SOURCE
AssocQueryString.c
IShellFolderHelpers.cpp
PathFileExistsDefExtAndAttributesW.c
PathFindOnPath.c
PathIsUNC.c

View file

@ -0,0 +1,308 @@
/*
* PROJECT: ReactOS api tests
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Tests for SHLWAPI IShellFolder helpers
* COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include <apitest.h>
#include <shlobj.h>
#include <shlwapi.h>
#include <versionhelpers.h>
#define SHLWAPI_ISHELLFOLDER_HELPERS
#include <shlwapi_undoc.h>
static INT s_nStep = 0;
class CTestShellFolder : public IShellFolder
{
public:
CTestShellFolder() { }
virtual ~CTestShellFolder() { }
static void *operator new(size_t size)
{
return LocalAlloc(LPTR, size);
}
static void operator delete(void *ptr)
{
LocalFree(ptr);
}
static void operator delete(void *ptr, size_t size)
{
LocalFree(ptr);
}
// IUnknown methods
STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject) override
{
ok_int(s_nStep, 11);
ok_int(IsEqualGUID(riid, IID_IShellFolder2), TRUE);
++s_nStep;
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)() override
{
ok_int(TRUE, FALSE);
return 1;
}
STDMETHOD_(ULONG, Release)() override
{
ok_int(TRUE, FALSE);
return 1;
}
// IShellFolder methods
STDMETHOD(ParseDisplayName)(
HWND hwndOwner,
LPBC pbc,
LPOLESTR lpszDisplayName,
ULONG *pchEaten,
PIDLIST_RELATIVE *ppidl,
ULONG *pdwAttributes) override
{
ok_ptr(*ppidl, NULL);
ok_long(*pdwAttributes, 0);
++s_nStep;
return 0xDEADFACE;
}
STDMETHOD(EnumObjects)(
HWND hwndOwner,
DWORD dwFlags,
LPENUMIDLIST *ppEnumIDList) override
{
ok_int(TRUE, FALSE);
return E_NOTIMPL;
}
STDMETHOD(BindToObject)(
PCUIDLIST_RELATIVE pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID *ppvOut) override
{
ok_int(TRUE, FALSE);
return E_NOTIMPL;
}
STDMETHOD(BindToStorage)(
PCUIDLIST_RELATIVE pidl,
LPBC pbcReserved,
REFIID riid,
LPVOID *ppvOut) override
{
ok_int(TRUE, FALSE);
return E_NOTIMPL;
}
STDMETHOD(CompareIDs)(
LPARAM lParam,
PCUIDLIST_RELATIVE pidl1,
PCUIDLIST_RELATIVE pidl2) override
{
switch (s_nStep)
{
case 11:
// It shouldn't come here
ok_int(TRUE, FALSE);
break;
case 12:
ok_long((LONG)lParam, 0x00001234);
break;
case 13:
ok_long((LONG)lParam, 0x00005678);
break;
default:
skip("\n");
break;
}
++s_nStep;
return 0xFEEDF00D;
}
STDMETHOD(CreateViewObject)(
HWND hwndOwner,
REFIID riid,
LPVOID *ppvOut) override
{
ok_int(TRUE, FALSE);
return E_NOTIMPL;
}
STDMETHOD(GetAttributesOf)(
UINT cidl,
PCUITEMID_CHILD_ARRAY apidl,
DWORD *rgfInOut) override
{
ok_int(TRUE, FALSE);
return E_NOTIMPL;
}
STDMETHOD(GetUIObjectOf)(
HWND hwndOwner,
UINT cidl,
PCUITEMID_CHILD_ARRAY apidl,
REFIID riid,
UINT * prgfInOut,
LPVOID * ppvOut) override
{
ok_int(TRUE, FALSE);
return E_NOTIMPL;
}
STDMETHOD(GetDisplayNameOf)(
PCUITEMID_CHILD pidl,
DWORD dwFlags,
LPSTRRET strRet) override
{
switch (s_nStep)
{
case 0:
ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR | SHGDN_FOREDITING |
SHGDN_INFOLDER);
break;
case 1:
ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_FORADDRESSBAR | SHGDN_INFOLDER);
break;
case 2:
ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_INFOLDER);
break;
case 3:
ok_long(dwFlags, SHGDN_FORPARSING);
break;
case 4:
ok_long(dwFlags, SHGDN_FORADDRESSBAR | SHGDN_FOREDITING | SHGDN_INFOLDER);
break;
case 5:
ok_long(dwFlags, SHGDN_FORADDRESSBAR | SHGDN_INFOLDER);
break;
case 6:
ok_long(dwFlags, SHGDN_INFOLDER);
break;
case 7:
ok_long(dwFlags, SHGDN_FORPARSING | SHGDN_INFOLDER);
break;
case 8:
ok_long(dwFlags, SHGDN_INFOLDER);
break;
case 9:
ok_long(dwFlags, SHGDN_NORMAL);
break;
default:
skip("\n");
break;
}
++s_nStep;
return E_FAIL;
}
STDMETHOD(SetNameOf)(
HWND hwndOwner,
PCUITEMID_CHILD pidl,
LPCOLESTR lpName,
DWORD dwFlags,
PITEMID_CHILD *pPidlOut) override
{
ok_int(TRUE, FALSE);
return E_NOTIMPL;
}
};
static void Test_GetDisplayNameOf(void)
{
CTestShellFolder *psf = new CTestShellFolder();
HRESULT hr;
hr = IShellFolder_GetDisplayNameOf(
psf,
NULL,
SHGDN_FOREDITING | SHGDN_FORADDRESSBAR | SHGDN_FORPARSING | SHGDN_INFOLDER,
NULL,
0);
ok_long(hr, E_FAIL);
ok_int(s_nStep, 4);
hr = IShellFolder_GetDisplayNameOf(
psf,
NULL,
SHGDN_FOREDITING | SHGDN_FORADDRESSBAR | SHGDN_INFOLDER,
NULL,
0);
ok_long(hr, E_FAIL);
ok_int(s_nStep, 10);
if (s_nStep != 10)
skip("s_nStep value is wrong\n");
delete psf;
}
static void Test_ParseDisplayName(void)
{
CTestShellFolder *psf = new CTestShellFolder();
HRESULT hr;
s_nStep = 10;
LPITEMIDLIST pidl = (LPITEMIDLIST)UlongToPtr(0xDEADDEAD);
hr = IShellFolder_ParseDisplayName(
psf,
NULL,
NULL,
NULL,
NULL,
&pidl,
NULL);
ok_long(hr, 0xDEADFACE);
ok_int(s_nStep, 11);
delete psf;
}
typedef HRESULT (WINAPI *FN_IShellFolder_CompareIDs)(
_In_ IShellFolder *psf,
_In_ LPARAM lParam,
_In_ PCUIDLIST_RELATIVE pidl1,
_In_ PCUIDLIST_RELATIVE pidl2);
static void Test_CompareIDs(void)
{
FN_IShellFolder_CompareIDs fnIShellFolder_CompareIDs;
fnIShellFolder_CompareIDs =
(FN_IShellFolder_CompareIDs)
GetProcAddress(GetModuleHandleA("shlwapi"), MAKEINTRESOURCEA(551));
if (IsWindowsVistaOrGreater())
{
skip("Vista+\n");
ok(fnIShellFolder_CompareIDs == NULL, "Vista+ has no IShellFolder_CompareIDs\n");
return;
}
CTestShellFolder *psf = new CTestShellFolder();
HRESULT hr;
s_nStep = 11;
hr = fnIShellFolder_CompareIDs(
psf,
0xFFFF1234,
NULL,
NULL);
ok_long(hr, 0xFEEDF00D);
ok_int(s_nStep, 13);
s_nStep = 13;
hr = fnIShellFolder_CompareIDs(
psf,
0x00005678,
NULL,
NULL);
ok_long(hr, 0xFEEDF00D);
ok_int(s_nStep, 14);
delete psf;
}
START_TEST(IShellFolderHelpers)
{
HRESULT hrCoInit = ::CoInitialize(NULL);
Test_GetDisplayNameOf();
Test_ParseDisplayName();
Test_CompareIDs();
if (SUCCEEDED(hrCoInit))
::CoUninitialize();
}

View file

@ -4,6 +4,7 @@
extern void func_AssocQueryString(void);
extern void func_PathFileExistsDefExtAndAttributesW(void);
extern void func_PathFindOnPath(void);
extern void func_IShellFolderHelpers(void);
extern void func_isuncpath(void);
extern void func_isuncpathserver(void);
extern void func_isuncpathservershare(void);
@ -22,6 +23,7 @@ const struct test winetest_testlist[] =
{ "AssocQueryString", func_AssocQueryString },
{ "PathFileExistsDefExtAndAttributesW", func_PathFileExistsDefExtAndAttributesW },
{ "PathFindOnPath", func_PathFindOnPath },
{ "IShellFolderHelpers", func_IShellFolderHelpers },
{ "PathIsUNC", func_isuncpath },
{ "PathIsUNCServer", func_isuncpathserver },
{ "PathIsUNCServerShare", func_isuncpathservershare },

View file

@ -341,12 +341,13 @@ HRESULT WINAPI
IShellFolder_GetDisplayNameOf(
_In_ IShellFolder *psf,
_In_ LPCITEMIDLIST pidl,
_In_ DWORD uFlags,
_In_ SHGDNF uFlags,
_Out_ LPSTRRET lpName,
_In_ DWORD dwRetryFlags);
/* Flags for IShellFolder_GetDisplayNameOf */
#define SFGDNO_RETRYWITHFORPARSING 1
#define SFGDNO_RETRYWITHFORPARSING 0x00000001
#define SFGDNO_RETRYALWAYS 0x80000000
HRESULT WINAPI
IShellFolder_ParseDisplayName(