[NETSHELL][SHELL32] Make NetShell PIDL format more Windows compatible (#7183)

- The PIDL format needs to be Windows compatible so that wlanwiz can get the connection GUID.
- SHELL32::ILIsEqual cannot deem PIDL formats it does not understand as invalid.
- DefView must ask the folder when comparing PIDLs.
This commit is contained in:
Whindmar Saksit 2024-08-08 22:00:03 +02:00 committed by GitHub
parent 5d96ba9217
commit ea60890961
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 144 additions and 26 deletions

View File

@ -9,9 +9,13 @@
PNETCONIDSTRUCT ILGetConnData(PCITEMID_CHILD pidl)
{
if (!pidl || !pidl->mkid.cb || pidl->mkid.abID[0] != 0x99)
return NULL;
return (PNETCONIDSTRUCT)(&pidl->mkid.abID[0]);
if (pidl && pidl->mkid.cb >= 2 + sizeof(NETCONIDSTRUCT))
{
PNETCONIDSTRUCT pData = (PNETCONIDSTRUCT)pidl->mkid.abID;
if (pData->Signature == NETCONIDSTRUCT_SIG)
return pData;
}
return NULL;
}
PWCHAR ILGetConnName(PCITEMID_CHILD pidl)
@ -48,17 +52,21 @@ PITEMID_CHILD ILCreateNetConnectItem(INetConnection * pItem)
/* Allocate enough memory for the trailing id which will indicate that this is a simple id */
pidl = static_cast<LPITEMIDLIST>(SHAlloc(size + sizeof(SHITEMID)));
if (!pidl)
goto end;
pidl->mkid.cb = (WORD)size;
pidl->mkid.abID[0] = 0x99;
((PNETCONIDSTRUCT)(pidl->mkid.abID))->Signature = NETCONIDSTRUCT_SIG;
/* Copy the connection properties */
pnetid = ILGetConnData(pidl);
memset(pnetid->Unknown, 0, sizeof(pnetid->Unknown));
pnetid->clsidThisObject = pProperties->clsidThisObject;
pnetid->guidId = pProperties->guidId;
pnetid->Status = pProperties->Status;
pnetid->MediaType = pProperties->MediaType;
pnetid->dwCharacter = pProperties->dwCharacter;
pnetid->uNameOffset = sizeof(NETCONIDSTRUCT);
pnetid->uDeviceNameOffset = pnetid->uNameOffset + (wcslen(pProperties->pszwName) + 1) * sizeof(WCHAR);
pnetid->uDeviceNameOffset = ULONG(pnetid->uNameOffset + (wcslen(pProperties->pszwName) + 1) * sizeof(WCHAR));
pwchName = ILGetConnName(pidl);
wcscpy(pwchName, pProperties->pszwName);
@ -68,7 +76,7 @@ PITEMID_CHILD ILCreateNetConnectItem(INetConnection * pItem)
/* Set the trailing id to null */
memset((void*)((ULONG_PTR)pidl + size), 0, sizeof(SHITEMID));
end:
NcFreeNetconProperties(pProperties);
return pidl;

View File

@ -55,16 +55,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(shell);
extern HINSTANCE netshell_hInstance;
/* enumlist.c */
#include <pshpack1.h>
#define NETCONIDSTRUCT_SIG 0x4EFF
typedef struct tagNETCONIDSTRUCT
{
BYTE type;
WORD Signature;
BYTE Unknown[8];
CLSID clsidThisObject;
GUID guidId;
NETCON_STATUS Status;
NETCON_MEDIATYPE MediaType;
DWORD dwCharacter;
ULONG_PTR uNameOffset;
ULONG_PTR uDeviceNameOffset;
NETCON_MEDIATYPE MediaType;
NETCON_STATUS Status;
ULONG uNameOffset;
ULONG uDeviceNameOffset;
} NETCONIDSTRUCT, *PNETCONIDSTRUCT;
#include <poppack.h>
C_ASSERT(2 + FIELD_OFFSET(NETCONIDSTRUCT, clsidThisObject) == 2 + (2 + 8));
C_ASSERT(2 + FIELD_OFFSET(NETCONIDSTRUCT, guidId) == 2 + (2 + 8 + 16));
C_ASSERT(2 + FIELD_OFFSET(NETCONIDSTRUCT, dwCharacter) == 2 + (2 + 8 + 32));
C_ASSERT(2 + FIELD_OFFSET(NETCONIDSTRUCT, MediaType) == 2 + (2 + 8 + 36));
PNETCONIDSTRUCT ILGetConnData(PCITEMID_CHILD pidl);
PWCHAR ILGetConnName(PCITEMID_CHILD pidl);

View File

@ -6,6 +6,7 @@
*/
#include "precomp.h"
#include <shellfolderutils.h>
#define MAX_PROPERTY_SHEET_PAGE (10)
@ -99,11 +100,26 @@ HRESULT WINAPI CNetworkConnections::BindToStorage(
/**************************************************************************
* ISF_NetConnect_fnCompareIDs
*/
HRESULT WINAPI CNetworkConnections::CompareIDs(
LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
{
return E_NOTIMPL;
const UINT colcount = NETCONNECTSHELLVIEWCOLUMNS;
if (ILGetNext(pidl1) || ILGetNext(pidl2))
return E_NOTIMPL; // FIXME: Can the connection folder have subfolders?
if (lParam & SHCIDS_CANONICALONLY)
{
PNETCONIDSTRUCT p1 = ILGetConnData(pidl1);
PNETCONIDSTRUCT p2 = ILGetConnData(pidl2);
if (p1 && p2)
{
int res = memcmp(&p1->guidId, &p2->guidId, sizeof(GUID));
return MAKE_COMPARE_HRESULT(res);
}
}
IShellFolder2 *psf = static_cast<IShellFolder2*>(this);
return ShellFolderImpl_CompareItemIDs<colcount, -1>(psf, lParam, (PCUITEMID_CHILD)pidl1, (PCUITEMID_CHILD)pidl2);
}
/**************************************************************************
@ -140,6 +156,7 @@ HRESULT WINAPI CNetworkConnections::GetAttributesOf(
UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
{
//IGenericSFImpl *This = (IGenericSFImpl *)iface;
// FIXME: Why are these reporting SFGAO_FILESYSTEM and SFGAO_FILESYSANCESTOR?
HRESULT hr = S_OK;
static const DWORD dwNetConnectAttributes = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
@ -156,6 +173,9 @@ HRESULT WINAPI CNetworkConnections::GetAttributesOf(
if (*rgfInOut == 0)
*rgfInOut = ~0;
if (cidl > 1)
*rgfInOut &= ~SFGAO_HASPROPSHEET;
if (cidl == 0)
{
*rgfInOut = dwNetConnectAttributes;
@ -610,20 +630,23 @@ ShowNetConnectionProperties(
*/
HRESULT WINAPI CNetConUiObject::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
UINT CmdId;
UINT CmdId = LOWORD(lpcmi->lpVerb) + IDS_NET_ACTIVATE;
/* We should get this when F2 is pressed in explorer */
if (HIWORD(lpcmi->lpVerb) && !strcmp(lpcmi->lpVerb, "rename"))
lpcmi->lpVerb = MAKEINTRESOURCEA(IDS_NET_RENAME);
if (HIWORD(lpcmi->lpVerb) || LOWORD(lpcmi->lpVerb) > 7)
if (!IS_INTRESOURCE(lpcmi->lpVerb) && !strcmp(lpcmi->lpVerb, "rename"))
{
CmdId = IDS_NET_RENAME;
}
else if (!IS_INTRESOURCE(lpcmi->lpVerb) && !strcmp(lpcmi->lpVerb, "properties"))
{
CmdId = IDS_NET_PROPERTIES;
}
else if (!IS_INTRESOURCE(lpcmi->lpVerb) || LOWORD(lpcmi->lpVerb) > 7)
{
FIXME("Got invalid command\n");
return E_NOTIMPL;
}
CmdId = LOWORD(lpcmi->lpVerb) + IDS_NET_ACTIVATE;
switch(CmdId)
{
case IDS_NET_RENAME:

View File

@ -1290,15 +1290,29 @@ PCUITEMID_CHILD CDefView::_PidlByItem(LVITEM& lvItem)
int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl)
{
ASSERT(m_ListView);
ASSERT(m_ListView && m_pSFParent);
int cItems = m_ListView.GetItemCount();
for (int i = 0; i<cItems; i++)
LPARAM lParam = m_pSF2Parent ? SHCIDS_CANONICALONLY : 0;
for (int i = 0; i < cItems; i++)
{
PCUITEMID_CHILD currentpidl = _PidlByItem(i);
if (ILIsEqual(pidl, currentpidl))
return i;
HRESULT hr = m_pSFParent->CompareIDs(lParam, pidl, currentpidl);
if (SUCCEEDED(hr))
{
if (hr == S_EQUAL)
return i;
}
else
{
for (i = 0; i < cItems; i++)
{
currentpidl = _PidlByItem(i);
if (ILIsEqual(pidl, currentpidl))
return i;
}
break;
}
}
return -1;
}

View File

@ -379,7 +379,6 @@ BOOL pcheck( LPCITEMIDLIST pidl )
case PT_YAGUID:
case PT_IESPECIAL2:
case PT_SHARE:
case 0x99: /* Network Connection pidl type */
break;
default:
ERR("unknown IDLIST %p [%p] size=%u type=%x\n",

View File

@ -557,7 +557,13 @@ BOOL WINAPI ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
* so we can only check here
*/
if (!pcheck(pidl1) || !pcheck (pidl2))
#ifdef __REACTOS__
{
/* We don't understand the PIDL content but that does not mean it's invalid */
}
#else
return FALSE;
#endif
pdump (pidl1);
pdump (pidl2);

View File

@ -0,0 +1,58 @@
/*
* LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
* PURPOSE: Utility functions for IShellFolder implementations
* COPYRIGHT: Copyright 2024 Whindmar Saksit <whindsaks@proton.me>
*/
#pragma once
#include "shellutils.h"
#ifdef __cplusplus
template <BOOL LOGICALCMP = TRUE>
static HRESULT ShellFolderImpl_CompareItemColumn(IShellFolder2 *psf, UINT column, PCUITEMID_CHILD pidl1, PCUITEMID_CHILD pidl2)
{
SHELLDETAILS details1, details2;
LPWSTR str1, str2;
HRESULT hr;
if (SUCCEEDED(hr = psf->GetDetailsOf(pidl1, column, &details1)) &&
SUCCEEDED(hr = StrRetToStrW(&details1.str, pidl1, &str1)))
{
if (SUCCEEDED(hr = psf->GetDetailsOf(pidl2, column, &details2)) &&
SUCCEEDED(hr = StrRetToStrW(&details2.str, pidl2, &str2)))
{
int res = LOGICALCMP ? StrCmpLogicalW(str1, str2) : lstrcmpiW(str1, str2);
hr = MAKE_COMPARE_HRESULT(res);
SHFree(str2);
}
SHFree(str1);
}
return hr;
}
template <UINT COLCOUNT, int CANONICAL, BOOL LOGICALCMP = TRUE>
static HRESULT ShellFolderImpl_CompareItemIDs(IShellFolder2 *psf, LPARAM lParam, PCUITEMID_CHILD pidl1, PCUITEMID_CHILD pidl2)
{
HRESULT hr;
if (CANONICAL >= 0 && (lParam & SHCIDS_CANONICALONLY))
{
hr = ShellFolderImpl_CompareItemColumn<LOGICALCMP>(psf, CANONICAL, pidl1, pidl2);
if (hr == S_EQUAL || !(lParam & SHCIDS_ALLFIELDS) || FAILED(hr))
return hr;
}
if (lParam & SHCIDS_ALLFIELDS)
{
for (UINT i = 0; i < COLCOUNT; ++i)
{
hr = ShellFolderImpl_CompareItemColumn<LOGICALCMP>(psf, i, pidl1, pidl2);
if (hr && SUCCEEDED(hr)) // Only stop if we successfully found a difference
break;
}
return hr;
}
const UINT column = (UINT)(lParam & SHCIDS_COLUMNMASK);
return ShellFolderImpl_CompareItemColumn<LOGICALCMP>(psf, column, pidl1, pidl2);
}
#endif // __cplusplus