https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ea60890961dcdda7356a3c6cfed919fd20905f88

commit ea60890961dcdda7356a3c6cfed919fd20905f88
Author:     Whindmar Saksit <whinds...@proton.me>
AuthorDate: Thu Aug 8 22:00:03 2024 +0200
Commit:     GitHub <nore...@github.com>
CommitDate: Thu Aug 8 22:00:03 2024 +0200

    [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.
---
 dll/shellext/netshell/enumlist.cpp          | 20 +++++++---
 dll/shellext/netshell/precomp.h             | 20 +++++++---
 dll/shellext/netshell/shfldr_netconnect.cpp | 41 +++++++++++++++-----
 dll/win32/shell32/CDefView.cpp              | 24 +++++++++---
 dll/win32/shell32/debughlp.cpp              |  1 -
 dll/win32/shell32/wine/pidl.c               |  6 +++
 sdk/include/reactos/shellfolderutils.h      | 58 +++++++++++++++++++++++++++++
 7 files changed, 144 insertions(+), 26 deletions(-)

diff --git a/dll/shellext/netshell/enumlist.cpp 
b/dll/shellext/netshell/enumlist.cpp
index 5f4b0fbef11..1cc62e79044 100644
--- a/dll/shellext/netshell/enumlist.cpp
+++ b/dll/shellext/netshell/enumlist.cpp
@@ -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;
diff --git a/dll/shellext/netshell/precomp.h b/dll/shellext/netshell/precomp.h
index 7dc020ca442..1f6497c3862 100644
--- a/dll/shellext/netshell/precomp.h
+++ b/dll/shellext/netshell/precomp.h
@@ -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);
diff --git a/dll/shellext/netshell/shfldr_netconnect.cpp 
b/dll/shellext/netshell/shfldr_netconnect.cpp
index 588f2c063e8..dca42527e7a 100644
--- a/dll/shellext/netshell/shfldr_netconnect.cpp
+++ b/dll/shellext/netshell/shfldr_netconnect.cpp
@@ -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:
diff --git a/dll/win32/shell32/CDefView.cpp b/dll/win32/shell32/CDefView.cpp
index eb4a85de725..ad9317d0a39 100644
--- a/dll/win32/shell32/CDefView.cpp
+++ b/dll/win32/shell32/CDefView.cpp
@@ -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;
 }
diff --git a/dll/win32/shell32/debughlp.cpp b/dll/win32/shell32/debughlp.cpp
index 388349c70a6..6778418c7a8 100644
--- a/dll/win32/shell32/debughlp.cpp
+++ b/dll/win32/shell32/debughlp.cpp
@@ -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",
diff --git a/dll/win32/shell32/wine/pidl.c b/dll/win32/shell32/wine/pidl.c
index e749d05125c..09b09112adb 100644
--- a/dll/win32/shell32/wine/pidl.c
+++ b/dll/win32/shell32/wine/pidl.c
@@ -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);
diff --git a/sdk/include/reactos/shellfolderutils.h 
b/sdk/include/reactos/shellfolderutils.h
new file mode 100644
index 00000000000..b3baa88f1f3
--- /dev/null
+++ b/sdk/include/reactos/shellfolderutils.h
@@ -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 <whinds...@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

Reply via email to