mirror of
https://github.com/reactos/reactos
synced 2025-10-05 16:02:58 +02:00
[SHELL32] Handle sort order in RegItems (#7906)
* [SHELL32] Handle sort order in RegItems This makes the TweakUI "First icon on desktop" setting work correctly.
This commit is contained in:
@@ -29,9 +29,9 @@ extern BOOL SHELL32_IsShellFolderNamespaceItemHidden(LPCWSTR SubKey, REFCLSID Cl
|
||||
|
||||
static const REQUIREDREGITEM g_RequiredItems[] =
|
||||
{
|
||||
{ CLSID_MyComputer, "sysdm.cpl", 0x50 },
|
||||
{ CLSID_NetworkPlaces, "ncpa.cpl", 0x58 },
|
||||
{ CLSID_Internet, "inetcpl.cpl", 0x68 },
|
||||
{ CLSID_MyComputer, "sysdm.cpl", REGITEMORDER_MYCOMPUTER },
|
||||
{ CLSID_NetworkPlaces, "ncpa.cpl", REGITEMORDER_NETHOOD },
|
||||
{ CLSID_Internet, "inetcpl.cpl", REGITEMORDER_INTERNET },
|
||||
};
|
||||
static const REGFOLDERINFO g_RegFolderInfo =
|
||||
{
|
||||
|
@@ -60,7 +60,7 @@ static int iDriveTypeIds[7] = { IDS_DRIVE_FIXED, /* DRIVE_UNKNOWN */
|
||||
|
||||
static const REQUIREDREGITEM g_RequiredItems[] =
|
||||
{
|
||||
{ CLSID_ControlPanel, 0, 0x50 },
|
||||
{ CLSID_ControlPanel, NULL, REGITEMORDER_MYCOMPUTER_CONTROLS },
|
||||
};
|
||||
static const REGFOLDERINFO g_RegFolderInfo =
|
||||
{
|
||||
|
@@ -25,17 +25,49 @@
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL (shell);
|
||||
|
||||
#define DEFAULTSORTORDERINDEX 0x80 // The default for registry items according to Geoff Chappell
|
||||
|
||||
static HRESULT CRegItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, HWND hwnd, UINT cidl,
|
||||
PCUITEMID_CHILD_ARRAY apidl, IShellFolder *psf, IContextMenu **ppcm);
|
||||
|
||||
HRESULT FormatGUIDKey(LPWSTR KeyName, SIZE_T KeySize, LPCWSTR RegPath, const GUID* riid)
|
||||
{
|
||||
WCHAR xriid[CHARS_IN_GUID];
|
||||
StringFromGUID2(*riid, xriid, _countof(xriid));
|
||||
return StringCchPrintfW(KeyName, KeySize, RegPath, xriid);
|
||||
}
|
||||
|
||||
static DWORD SHELL_QueryCLSIDValue(_In_ REFCLSID clsid, _In_opt_ LPCWSTR SubKey, _In_opt_ LPCWSTR Value, _In_opt_ PVOID pData, _In_opt_ PDWORD pSize)
|
||||
{
|
||||
const UINT cchGuid = CHARS_IN_GUID - 1, cchClsidSlash = sizeof("CLSID\\") - 1;
|
||||
WCHAR Path[200];
|
||||
wcscpy(Path, L"CLSID\\");
|
||||
StringFromGUID2(clsid, Path + 6, CHARS_IN_GUID);
|
||||
if (SubKey)
|
||||
{
|
||||
*(Path + cchClsidSlash + cchGuid) = L'\\';
|
||||
wcscpy(Path + cchClsidSlash + cchGuid + 1, SubKey);
|
||||
}
|
||||
return RegGetValueW(HKEY_CLASSES_ROOT, Path, Value, RRF_RT_ANY, NULL, pData, pSize);
|
||||
}
|
||||
|
||||
static bool HasCLSIDShellFolderValue(REFCLSID clsid, LPCWSTR Value)
|
||||
{
|
||||
return SHELL_QueryCLSIDValue(clsid, L"ShellFolder", Value, NULL, NULL) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
static inline UINT GetRegItemCLSIDOffset(PIDLTYPE type)
|
||||
{
|
||||
return type == PT_CONTROLS_NEWREGITEM ? 14 : 4;
|
||||
}
|
||||
|
||||
static LPITEMIDLIST CreateRegItem(PIDLTYPE type, REFCLSID clsid, BYTE order = 0)
|
||||
static BYTE GetRegItemOrder(REFCLSID clsid)
|
||||
{
|
||||
DWORD dwOrder, cb = sizeof(dwOrder);
|
||||
if (SHELL_QueryCLSIDValue(clsid, NULL, L"SortOrderIndex", &dwOrder, &cb) || cb != sizeof(dwOrder))
|
||||
dwOrder = REGITEMORDER_DEFAULT;
|
||||
return (BYTE)dwOrder;
|
||||
}
|
||||
|
||||
static LPITEMIDLIST CreateRegItem(PIDLTYPE type, REFCLSID clsid, int order = -1)
|
||||
{
|
||||
#if 1 // FIXME: CControlPanelFolder is not ready for this yet
|
||||
if (type == PT_CONTROLS_NEWREGITEM)
|
||||
@@ -49,7 +81,7 @@ static LPITEMIDLIST CreateRegItem(PIDLTYPE type, REFCLSID clsid, BYTE order = 0)
|
||||
ZeroMemory(pidl, cbTotal); // Note: This also initializes the terminator WORD
|
||||
pidl->mkid.cb = cb;
|
||||
pidl->mkid.abID[0] = type;
|
||||
pidl->mkid.abID[1] = order;
|
||||
pidl->mkid.abID[1] = order >= 0 ? (BYTE)order : GetRegItemOrder(clsid);
|
||||
*(CLSID*)(SIZE_T(pidl) + offset) = clsid;
|
||||
}
|
||||
return pidl;
|
||||
@@ -61,31 +93,6 @@ static LPITEMIDLIST CreateRegItem(PIDLTYPE type, LPCWSTR clsidstr)
|
||||
return SUCCEEDED(CLSIDFromString(clsidstr, &clsid)) ? CreateRegItem(type, clsid) : NULL;
|
||||
}
|
||||
|
||||
HRESULT FormatGUIDKey(LPWSTR KeyName, SIZE_T KeySize, LPCWSTR RegPath, const GUID* riid)
|
||||
{
|
||||
WCHAR xriid[CHARS_IN_GUID];
|
||||
StringFromGUID2(*riid, xriid, _countof(xriid));
|
||||
return StringCchPrintfW(KeyName, KeySize, RegPath, xriid);
|
||||
}
|
||||
|
||||
static DWORD SHELL_QueryCLSIDValue(_In_ REFCLSID clsid, _In_opt_ LPCWSTR SubKey, _In_opt_ LPCWSTR Value, _In_opt_ PVOID pData, _In_opt_ PDWORD pSize)
|
||||
{
|
||||
WCHAR Path[MAX_PATH];
|
||||
wcscpy(Path, L"CLSID\\");
|
||||
StringFromGUID2(clsid, Path + 6, 39);
|
||||
if (SubKey)
|
||||
{
|
||||
wcscpy(Path + 6 + 38, L"\\");
|
||||
wcscpy(Path + 6 + 39, SubKey);
|
||||
}
|
||||
return RegGetValueW(HKEY_CLASSES_ROOT, Path, Value, RRF_RT_ANY, NULL, pData, pSize);
|
||||
}
|
||||
|
||||
static bool HasCLSIDShellFolderValue(REFCLSID clsid, LPCWSTR Value)
|
||||
{
|
||||
return SHELL_QueryCLSIDValue(clsid, L"ShellFolder", Value, NULL, NULL) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
struct CRegFolderInfo
|
||||
{
|
||||
const REGFOLDERINFO *m_pInfo;
|
||||
@@ -118,6 +125,12 @@ struct CRegFolderInfo
|
||||
return CreateRegItem(GetPidlType(), item.clsid, item.Order);
|
||||
}
|
||||
|
||||
WORD GetRegItemOrder(LPCITEMIDLIST pidl) const
|
||||
{
|
||||
const CLSID *pCLSID = IsRegItem(pidl);
|
||||
return pCLSID ? ::GetRegItemOrder(*pCLSID) : 0xffff;
|
||||
}
|
||||
|
||||
LPCWSTR GetParsingPath() const { return m_pInfo->pszParsingPath; }
|
||||
UINT GetCLSIDOffset() const { return GetRegItemCLSIDOffset(m_pInfo->PidlType); }
|
||||
PIDLTYPE GetPidlType() const { return m_pInfo->PidlType; }
|
||||
@@ -314,6 +327,7 @@ class CRegFolder :
|
||||
IShellFolder *m_pOuterFolder; // Not ref-counted
|
||||
CComHeapPtr<ITEMIDLIST> m_pidlRoot;
|
||||
|
||||
HRESULT CompareRegItemsSortOrder(PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2);
|
||||
HRESULT GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes);
|
||||
BOOL _IsInNameSpace(_In_ LPCITEMIDLIST pidl);
|
||||
|
||||
@@ -514,6 +528,18 @@ HRESULT WINAPI CRegFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserv
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT CRegFolder::CompareRegItemsSortOrder(PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
|
||||
{
|
||||
LPPIDLDATA p1 = (LPPIDLDATA)pidl1->mkid.abID;
|
||||
LPPIDLDATA p2 = (LPPIDLDATA)pidl2->mkid.abID;
|
||||
int Order1 = p1->u.guid.uSortOrder > 0x40 ? p1->u.guid.uSortOrder : GetRegItemOrder(pidl1);
|
||||
int Order2 = p2->u.guid.uSortOrder > 0x40 ? p2->u.guid.uSortOrder : GetRegItemOrder(pidl2);
|
||||
int Cmp = Order1 - Order2;
|
||||
if (Cmp != 0)
|
||||
return MAKE_COMPARE_HRESULT(Cmp);
|
||||
return SHELL32_CompareDetails(this, COL_NAME, pidl1, pidl2);
|
||||
}
|
||||
|
||||
HRESULT WINAPI CRegFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
|
||||
{
|
||||
if (!pidl1 || !pidl2 || pidl1->mkid.cb == 0 || pidl2->mkid.cb == 0)
|
||||
@@ -532,6 +558,12 @@ HRESULT WINAPI CRegFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, P
|
||||
}
|
||||
else if (clsid1 && clsid2)
|
||||
{
|
||||
if ((lParam & SHCIDS_COLUMNMASK) == COL_NAME && !(lParam & SHCIDS_CANONICALONLY))
|
||||
{
|
||||
HRESULT hrCmpOrder = CompareRegItemsSortOrder(pidl1, pidl2);
|
||||
if (hrCmpOrder && SUCCEEDED(hrCmpOrder))
|
||||
return hrCmpOrder;
|
||||
}
|
||||
if (memcmp(clsid1, clsid2, sizeof(GUID)) == 0)
|
||||
return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
|
||||
|
||||
|
@@ -1798,19 +1798,19 @@ LPITEMIDLIST _ILCreateDesktop(void)
|
||||
LPITEMIDLIST _ILCreateMyComputer(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_MyComputer);
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_MyComputer, REGITEMORDER_MYCOMPUTER);
|
||||
}
|
||||
|
||||
LPITEMIDLIST _ILCreateMyDocuments(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_MyDocuments);
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_MyDocuments, REGITEMORDER_MYDOCS_DEFAULT);
|
||||
}
|
||||
|
||||
LPITEMIDLIST _ILCreateIExplore(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_Internet);
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_Internet, REGITEMORDER_INTERNET);
|
||||
}
|
||||
|
||||
LPITEMIDLIST _ILCreateControlPanel(void)
|
||||
@@ -1820,7 +1820,7 @@ LPITEMIDLIST _ILCreateControlPanel(void)
|
||||
TRACE("()\n");
|
||||
if (parent)
|
||||
{
|
||||
LPITEMIDLIST cpl = _ILCreateGuid(PT_COMPUTER_REGITEM, &CLSID_ControlPanel);
|
||||
LPITEMIDLIST cpl = _ILCreateGuid(PT_COMPUTER_REGITEM, &CLSID_ControlPanel, REGITEMORDER_MYCOMPUTER_CONTROLS);
|
||||
if (cpl)
|
||||
{
|
||||
ret = ILCombine(parent, cpl);
|
||||
@@ -1861,22 +1861,22 @@ LPITEMIDLIST _ILCreatePrinters(void)
|
||||
LPITEMIDLIST _ILCreateNetwork(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_NetworkPlaces);
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_NetworkPlaces, REGITEMORDER_NETHOOD);
|
||||
}
|
||||
|
||||
LPITEMIDLIST _ILCreateBitBucket(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_RecycleBin);
|
||||
return _ILCreateGuid(PT_DESKTOP_REGITEM, &CLSID_RecycleBin, REGITEMORDER_RECYCLEBIN);
|
||||
}
|
||||
|
||||
LPITEMIDLIST _ILCreateAdminTools(void)
|
||||
{
|
||||
TRACE("()\n");
|
||||
return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut); //FIXME
|
||||
return _ILCreateGuid(PT_GUID, &CLSID_AdminFolderShortcut, REGITEMORDER_DEFAULT); //FIXME
|
||||
}
|
||||
|
||||
LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid)
|
||||
LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid, BYTE SortOrder)
|
||||
{
|
||||
LPITEMIDLIST pidlOut;
|
||||
|
||||
@@ -1886,7 +1886,7 @@ LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid)
|
||||
if (pidlOut)
|
||||
{
|
||||
LPPIDLDATA pData = _ILGetDataPointer(pidlOut);
|
||||
|
||||
pData->u.guid.uSortOrder = SortOrder;
|
||||
pData->u.guid.guid = *guid;
|
||||
TRACE("-- create GUID-pidl %s\n",
|
||||
debugstr_guid(&(pData->u.guid.guid)));
|
||||
|
@@ -119,7 +119,27 @@ extern "C" {
|
||||
#define PT_INTERNET_URL 0x61
|
||||
#define PT_CONTROLS_OLDREGITEM 0x70
|
||||
#define PT_CONTROLS_NEWREGITEM 0x71
|
||||
|
||||
#define REGITEMLOCATION_CONTROLS CSIDL_DRIVES
|
||||
#define REGITEMLOCATION_PRINTERS CSIDL_CONTROLS
|
||||
|
||||
#define REGITEMORDER_DEFAULT 0x80
|
||||
#define REGITEMORDER_LIBRARIES 0x42
|
||||
#define REGITEMORDER_USERSFILEFOLDER 0x44
|
||||
#define REGITEMORDER_MYCOMPUTER 0x50
|
||||
#define REGITEMORDER_MYDOCS_BEFOREMYCOMPUTER 0x48 // Tweak UI "Desktop => First Icon" only
|
||||
#define REGITEMORDER_MYDOCS_AFTERMYCOMPUTER 0x54 // accepts these two values.
|
||||
#define REGITEMORDER_MYDOCS_DEFAULT 0x48
|
||||
#define REGITEMORDER_NETHOOD 0x58
|
||||
#if (REGITEMLOCATION_CONTROLS == CSIDL_DESKTOP)
|
||||
#define REGITEMORDER_RECYCLEBIN 0x78
|
||||
#else
|
||||
#define REGITEMORDER_RECYCLEBIN 0x60
|
||||
#endif
|
||||
#define REGITEMORDER_INTERNET 0x68
|
||||
#define REGITEMORDER_DESKTOP_CONTROLS 0x70 // NT6
|
||||
#define REGITEMORDER_MYCOMPUTER_CONTROLS 0x1E // NT5
|
||||
#endif // __REACTOS__
|
||||
|
||||
static inline BYTE _ILGetType(LPCITEMIDLIST pidl)
|
||||
{
|
||||
@@ -165,7 +185,7 @@ typedef struct tagPIDLPrinterStruct
|
||||
|
||||
typedef struct tagGUIDStruct
|
||||
{
|
||||
BYTE dummy; /* offset 01 is unknown */
|
||||
BYTE uSortOrder;
|
||||
GUID guid; /* offset 02 */
|
||||
} GUIDStruct;
|
||||
|
||||
@@ -269,7 +289,7 @@ UINT _ILGetDepth(LPCITEMIDLIST pidl);
|
||||
/* Creates a PIDL with guid format and type type, which must be one of PT_GUID,
|
||||
* PT_SHELLEXT, or PT_YAGUID.
|
||||
*/
|
||||
LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid) DECLSPEC_HIDDEN;
|
||||
LPITEMIDLIST _ILCreateGuid(PIDLTYPE type, REFIID guid, BYTE SortOrder);
|
||||
|
||||
#ifndef __REACTOS__
|
||||
/* Like _ILCreateGuid, but using the string szGUID. */
|
||||
|
Reference in New Issue
Block a user