1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Test for SHSimpleIDListFromPath 5 * COPYRIGHT: Copyright 2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 6 * Copyright 2024 Whindmar Saksit <whindsaks@proton.me> 7 */ 8 9 #include "shelltest.h" 10 #include <shellutils.h> 11 12 enum { DIRBIT = 1, FILEBIT = 2 }; 13 14 static BYTE GetPIDLType(LPCITEMIDLIST pidl) 15 { 16 // Return the type without the 0x80 flag 17 return pidl && pidl->mkid.cb >= 3 ? (pidl->mkid.abID[0] & 0x7F) : 0; 18 } 19 20 struct FS95 // FileSystem item header 21 { 22 WORD cb; 23 BYTE type; 24 BYTE unknown; 25 UINT size; 26 WORD date, time; 27 WORD att; 28 CHAR name[ANYSIZE_ARRAY]; 29 30 static BOOL IsFS(LPCITEMIDLIST p) 31 { 32 return (p && p->mkid.cb > 2) ? (p->mkid.abID[0] & 0x70) == 0x30 : FALSE; 33 } 34 static FS95* Validate(LPCITEMIDLIST p) 35 { 36 C_ASSERT(FIELD_OFFSET(FS95, name) == 14); 37 return p && p->mkid.cb > FIELD_OFFSET(FS95, name) && IsFS(p) ? (FS95*)p : NULL; 38 } 39 }; 40 41 static int FileStruct_Att(LPCITEMIDLIST pidl) 42 { 43 C_ASSERT(FIELD_OFFSET(FS95, att) == 12); 44 FS95 *p = FS95::Validate(pidl); 45 return p ? p->att : (UINT(1) << 31); 46 } 47 48 #define TEST_CLSID(pidl, type, offset, clsid) \ 49 do { \ 50 ok_long(GetPIDLType(pidl), (type)); \ 51 ok_int(*(CLSID*)((&pidl->mkid.abID[(offset) - sizeof(WORD)])) == clsid, TRUE); \ 52 } while (0) 53 54 START_TEST(SHSimpleIDListFromPath) 55 { 56 HRESULT hr; 57 WCHAR szPath[MAX_PATH]; 58 GetWindowsDirectoryW(szPath, _countof(szPath)); 59 60 // We compare pidl1 and pidl2 61 CComHeapPtr<ITEMIDLIST> pidl1(SHSimpleIDListFromPath(szPath)); 62 CComHeapPtr<ITEMIDLIST> pidl2(ILCreateFromPathW(szPath)); 63 64 // Yes, they are equal logically 65 LPITEMIDLIST pidl1Last = ILFindLastID(pidl1), pidl2Last = ILFindLastID(pidl2); 66 ok_int(ILIsEqual(pidl1, pidl2), TRUE); 67 ok_int(ILIsEqual(pidl1Last, pidl2Last), TRUE); 68 69 // Bind to parent 70 CComPtr<IShellFolder> psf1, psf2; 71 hr = SHBindToParent(pidl1, IID_PPV_ARG(IShellFolder, &psf1), NULL); 72 ok_long(hr, S_OK); 73 hr = SHBindToParent(pidl2, IID_PPV_ARG(IShellFolder, &psf2), NULL); 74 ok_long(hr, S_OK); 75 76 // Get attributes 77 DWORD attrs1 = SFGAO_FOLDER, attrs2 = SFGAO_FOLDER; 78 hr = (psf1 ? psf1->GetAttributesOf(1, &pidl1Last, &attrs1) : E_UNEXPECTED); 79 ok_long(hr, S_OK); 80 hr = (psf2 ? psf2->GetAttributesOf(1, &pidl2Last, &attrs2) : E_UNEXPECTED); 81 ok_long(hr, S_OK); 82 83 // There is the difference in attributes because SHSimpleIDListFromPath 84 // cannot create PIDLs to folders, only files and drives: 85 ok_long((attrs1 & SFGAO_FOLDER), 0); 86 ok_long((attrs2 & SFGAO_FOLDER), SFGAO_FOLDER); 87 88 89 // Make sure the internal details match Windows NT5+ 90 LPITEMIDLIST item; 91 GetSystemDirectoryW(szPath, _countof(szPath)); 92 CComHeapPtr<ITEMIDLIST> pidlSys32(SHSimpleIDListFromPath(szPath)); 93 if (szPath[1] != ':' || PathFindFileNameW(szPath) <= szPath) 94 { 95 skip("Not a local directory %ls\n", szPath); 96 } 97 else if (!(LPITEMIDLIST)pidlSys32) 98 { 99 skip("?\n"); 100 } 101 else 102 { 103 item = ILFindLastID(pidlSys32); 104 ok_long(item->mkid.abID[0] & 0x73, 0x30 | FILEBIT); // This is actually a file PIDL 105 ok_long(FileStruct_Att(item), 0); // Simple PIDL without attributes 106 ok_int(*(UINT*)(&item->mkid.abID[2]), 0); // No size 107 108 ILRemoveLastID(pidlSys32); // Now we should have "c:\Windows" 109 item = ILFindLastID(pidlSys32); 110 ok_long(item->mkid.abID[0] & 0x73, 0x30 | DIRBIT); 111 ok_int(*(UINT*)(&item->mkid.abID[2]), 0); // No size 112 } 113 114 WCHAR drive[4] = { szPath[0], szPath[1], L'\\', L'\0' }; 115 CComHeapPtr<ITEMIDLIST> pidlDrive(SHSimpleIDListFromPath(drive)); 116 if (drive[1] != ':') 117 { 118 skip("Not a local drive %ls\n", drive); 119 } 120 else if (!(LPITEMIDLIST)pidlDrive) 121 { 122 skip("?\n"); 123 } 124 else 125 { 126 item = ILFindLastID(pidlDrive); 127 ok_long(item->mkid.abID[0] & 0x70, 0x20); // Something in My Computer 128 ok_char(item->mkid.abID[1] | 32, drive[0] | 32); 129 } 130 131 CComHeapPtr<ITEMIDLIST> pidlVirt(SHSimpleIDListFromPath(L"x:\\IDontExist")); 132 if (!(LPITEMIDLIST)pidlVirt) 133 { 134 skip("?\n"); 135 } 136 else 137 { 138 item = ILFindLastID(pidlVirt); 139 ok_long(item->mkid.abID[0] & 0x73, 0x30 | FILEBIT); // Yes, a file 140 ok_long(FileStruct_Att(item), 0); // Simple PIDL, no attributes 141 ok_int(*(UINT*)(&item->mkid.abID[2]), 0); // No size 142 143 ILRemoveLastID(pidlVirt); // "x:\" 144 item = ILFindLastID(pidlVirt); 145 ok_long(item->mkid.abID[0] & 0x70, 0x20); // Something in My Computer 146 ok_char(item->mkid.abID[1] | 32, 'x' | 32); // x: 147 } 148 } 149 150 START_TEST(ILCreateFromPath) 151 { 152 WCHAR szPath[MAX_PATH]; 153 LPITEMIDLIST item; 154 155 ok_ptr(ILCreateFromPathW(L"c:\\IDontExist"), NULL); 156 157 GetSystemDirectoryW(szPath, _countof(szPath)); 158 CComHeapPtr<ITEMIDLIST> pidlDir(ILCreateFromPathW(szPath)); 159 if (szPath[1] != ':' || PathFindFileNameW(szPath) <= szPath) 160 { 161 skip("Not a local directory %ls\n", szPath); 162 } 163 else if (!(LPITEMIDLIST)pidlDir) 164 { 165 skip("?\n"); 166 } 167 else 168 { 169 item = ILFindLastID(pidlDir); 170 ok_long(item->mkid.abID[0] & 0x73, 0x30 | DIRBIT); 171 ok_int(*(UINT*)(&item->mkid.abID[2]), 0); // No size 172 } 173 PathAppendW(szPath, L"kernel32.dll"); 174 CComHeapPtr<ITEMIDLIST> pidlFile(ILCreateFromPathW(szPath)); 175 if (!(LPITEMIDLIST)pidlFile) 176 { 177 skip("?\n"); 178 } 179 else 180 { 181 item = ILFindLastID(pidlFile); 182 ok_long(item->mkid.abID[0] & 0x73, 0x30 | FILEBIT); 183 ok_int(*(UINT*)(&item->mkid.abID[2]) > 1024 * 42, TRUE); // At least this large 184 } 185 } 186 187 START_TEST(PIDL) 188 { 189 LPITEMIDLIST pidl; 190 191 pidl = SHCloneSpecialIDList(NULL, CSIDL_DRIVES, FALSE); 192 if (pidl) 193 TEST_CLSID(ILFindLastID(pidl), 0x1f, 4, CLSID_MyComputer); 194 else 195 skip("?\n"); 196 ILFree(pidl); 197 198 pidl = SHCloneSpecialIDList(NULL, CSIDL_PRINTERS, FALSE); 199 if (pidl) 200 TEST_CLSID(ILFindLastID(pidl), 0x71, 14, CLSID_Printers); 201 else 202 skip("?\n"); 203 ILFree(pidl); 204 } 205