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

View file

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

View file

@ -6,6 +6,7 @@
*/ */
#include "precomp.h" #include "precomp.h"
#include <shellfolderutils.h>
#define MAX_PROPERTY_SHEET_PAGE (10) #define MAX_PROPERTY_SHEET_PAGE (10)
@ -99,11 +100,26 @@ HRESULT WINAPI CNetworkConnections::BindToStorage(
/************************************************************************** /**************************************************************************
* ISF_NetConnect_fnCompareIDs * ISF_NetConnect_fnCompareIDs
*/ */
HRESULT WINAPI CNetworkConnections::CompareIDs( HRESULT WINAPI CNetworkConnections::CompareIDs(
LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 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) UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
{ {
//IGenericSFImpl *This = (IGenericSFImpl *)iface; //IGenericSFImpl *This = (IGenericSFImpl *)iface;
// FIXME: Why are these reporting SFGAO_FILESYSTEM and SFGAO_FILESYSANCESTOR?
HRESULT hr = S_OK; HRESULT hr = S_OK;
static const DWORD dwNetConnectAttributes = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | static const DWORD dwNetConnectAttributes = SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE; SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
@ -156,6 +173,9 @@ HRESULT WINAPI CNetworkConnections::GetAttributesOf(
if (*rgfInOut == 0) if (*rgfInOut == 0)
*rgfInOut = ~0; *rgfInOut = ~0;
if (cidl > 1)
*rgfInOut &= ~SFGAO_HASPROPSHEET;
if (cidl == 0) if (cidl == 0)
{ {
*rgfInOut = dwNetConnectAttributes; *rgfInOut = dwNetConnectAttributes;
@ -610,20 +630,23 @@ ShowNetConnectionProperties(
*/ */
HRESULT WINAPI CNetConUiObject::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) 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 */ /* We should get this when F2 is pressed in explorer */
if (HIWORD(lpcmi->lpVerb) && !strcmp(lpcmi->lpVerb, "rename")) if (!IS_INTRESOURCE(lpcmi->lpVerb) && !strcmp(lpcmi->lpVerb, "rename"))
lpcmi->lpVerb = MAKEINTRESOURCEA(IDS_NET_RENAME); {
CmdId = IDS_NET_RENAME;
if (HIWORD(lpcmi->lpVerb) || LOWORD(lpcmi->lpVerb) > 7) }
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"); FIXME("Got invalid command\n");
return E_NOTIMPL; return E_NOTIMPL;
} }
CmdId = LOWORD(lpcmi->lpVerb) + IDS_NET_ACTIVATE;
switch(CmdId) switch(CmdId)
{ {
case IDS_NET_RENAME: case IDS_NET_RENAME:

View file

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

View file

@ -379,7 +379,6 @@ BOOL pcheck( LPCITEMIDLIST pidl )
case PT_YAGUID: case PT_YAGUID:
case PT_IESPECIAL2: case PT_IESPECIAL2:
case PT_SHARE: case PT_SHARE:
case 0x99: /* Network Connection pidl type */
break; break;
default: default:
ERR("unknown IDLIST %p [%p] size=%u type=%x\n", 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 * so we can only check here
*/ */
if (!pcheck(pidl1) || !pcheck (pidl2)) 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; return FALSE;
#endif
pdump (pidl1); pdump (pidl1);
pdump (pidl2); 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