Reactos

[IEFRAME] Implement URL PIDL (#7850)

authored by

Whindmar Saksit and committed by
GitHub
769462fa 13657fdb

+417
+1
dll/win32/ieframe/CMakeLists.txt
··· 13 13 ieframe_main.c 14 14 iehtmlwnd.c 15 15 iexplore.c 16 + inetfolder.c 16 17 intshcut.c 17 18 navigate.c 18 19 oleobject.c
+21
dll/win32/ieframe/ieframe_main.c
··· 178 178 179 179 static IClassFactory CUrlHistoryFactory = { &CUrlHistoryFactoryVtbl }; 180 180 181 + #ifdef __REACTOS__ 182 + extern HRESULT WINAPI CInternetFolder_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv); 183 + 184 + static const IClassFactoryVtbl CInternetFolderFactoryVtbl = { 185 + ClassFactory_QueryInterface, 186 + ClassFactory_AddRef, 187 + ClassFactory_Release, 188 + CInternetFolder_CreateInstance, 189 + ClassFactory_LockServer 190 + }; 191 + 192 + static IClassFactory CInternetFolderFactory = { &CInternetFolderFactoryVtbl }; 193 + #endif 194 + 181 195 /****************************************************************** 182 196 * DllMain (ieframe.@) 183 197 */ ··· 225 239 TRACE("(CLSID_CUrlHistory %s %p)\n", debugstr_guid(riid), ppv); 226 240 return IClassFactory_QueryInterface(&CUrlHistoryFactory, riid, ppv); 227 241 } 242 + 243 + #ifdef __REACTOS__ 244 + if(IsEqualGUID(&CLSID_Internet, rclsid)) { 245 + TRACE("(CLSID_Internet %s %p)\n", debugstr_guid(riid), ppv); 246 + return IClassFactory_QueryInterface(&CInternetFolderFactory, riid, ppv); 247 + } 248 + #endif 228 249 229 250 FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); 230 251 return CLASS_E_CLASSNOTAVAILABLE;
+358
dll/win32/ieframe/inetfolder.c
··· 1 + /* 2 + * PROJECT: ReactOS ieframe 3 + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 + * PURPOSE: Internet IShellFolder implementation 5 + * COPYRIGHT: Copyright 2025 Whindmar Saksit <whindsaks@proton.me> 6 + */ 7 + 8 + #define NONAMELESSUNION 9 + 10 + #include "ieframe.h" 11 + 12 + #include "shlobj.h" 13 + #include "shobjidl.h" 14 + #include "shellapi.h" 15 + #include "shlwapi.h" 16 + #include "shlguid.h" 17 + #include "intshcut.h" 18 + 19 + #include "wine/debug.h" 20 + 21 + WINE_DEFAULT_DEBUG_CHANNEL(ieframe); 22 + 23 + extern int WINAPI SHAnsiToUnicodeCP(UINT CodePage, LPCSTR pszSrc, LPWSTR pwszDst, int cwchBuf); 24 + 25 + #define MAX_URL_LENGTH 1024 26 + 27 + #define PT_INTERNET_URL 0x61 28 + #define IFUIF_UNICODE 0x80 29 + typedef struct _IFURLITEM 30 + { 31 + WORD cb; 32 + BYTE Type; // PT_INTERNET_URL 33 + BYTE Flags; // IFUIF_* 34 + UINT Unknown; 35 + WCHAR Url[ANYSIZE_ARRAY]; 36 + } IFURLITEM; 37 + 38 + static int GetSchemeCharType(WCHAR c) 39 + { 40 + if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) 41 + return 0; 42 + return c == '+' || c == '-' || c == '.' ? 1 : -1; 43 + } 44 + 45 + static unsigned int GetSchemeLength(PCWSTR s) 46 + { 47 + if (GetSchemeCharType(s[0]) != 0) // The first character MUST be A-Z, a-z. 48 + return 0; 49 + for (unsigned int i = 0;;) 50 + { 51 + if (s[++i] == ':') 52 + return ++i; 53 + if (GetSchemeCharType(s[i]) < 0) 54 + return 0; 55 + } 56 + } 57 + 58 + static LPITEMIDLIST CreateUrlItem(PCWSTR pszUrl) 59 + { 60 + UINT cch = lstrlenW(pszUrl) + 1; 61 + UINT cb = FIELD_OFFSET(IFURLITEM, Url[cch]); 62 + IFURLITEM *pidl = SHAlloc(cb + sizeof(WORD)); 63 + if (!pidl) 64 + return (LPITEMIDLIST)pidl; 65 + pidl->cb = cb; 66 + pidl->Type = PT_INTERNET_URL; 67 + pidl->Flags = IFUIF_UNICODE; 68 + pidl->Unknown = 0; 69 + CopyMemory(pidl->Url, pszUrl, cch * sizeof(*pszUrl)); 70 + ILGetNext((LPITEMIDLIST)pidl)->mkid.cb = 0; 71 + return (LPITEMIDLIST)pidl; 72 + } 73 + 74 + static IFURLITEM* IsUrlItem(LPCITEMIDLIST pidl) 75 + { 76 + IFURLITEM *p = (IFURLITEM*)pidl; 77 + if (p && p->cb > FIELD_OFFSET(IFURLITEM, Url) && p->Type == PT_INTERNET_URL) 78 + return p; 79 + return NULL; 80 + } 81 + 82 + static PWSTR GetUrl(IFURLITEM *pUrl, PWSTR Buffer) 83 + { 84 + if (pUrl->Flags & IFUIF_UNICODE) 85 + return pUrl->Url; 86 + SHAnsiToUnicodeCP(CP_ACP, (PCSTR)pUrl->Url, Buffer, MAX_URL_LENGTH); 87 + return Buffer; 88 + } 89 + 90 + static HRESULT CreateUrlShortcut(PCWSTR Url, IUniformResourceLocatorW **ppv) 91 + { 92 + HRESULT hr = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, 93 + &IID_IUniformResourceLocatorW, (void**)ppv); 94 + if (SUCCEEDED(hr)) 95 + hr = (*ppv)->lpVtbl->SetURL(*ppv, Url, 0); 96 + return hr; 97 + } 98 + 99 + typedef struct _CInternetFolder 100 + { 101 + IShellFolder IShellFolder_iface; 102 + IPersistFolder IPersistFolder_iface; 103 + LONG refCount; 104 + } CInternetFolder; 105 + 106 + static HRESULT Unknown_QueryInterface(CInternetFolder *This, REFIID riid, PVOID *ppvObject) 107 + { 108 + TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject); 109 + *ppvObject = NULL; 110 + if (IsEqualGUID(&IID_IUnknown, riid)) 111 + *ppvObject = &This->IShellFolder_iface; 112 + else if (IsEqualGUID(&IID_IShellFolder, riid)) 113 + *ppvObject = &This->IShellFolder_iface; 114 + else if (IsEqualGUID(&IID_IPersist, riid) || IsEqualGUID(&IID_IPersistFolder, riid)) 115 + *ppvObject = &This->IPersistFolder_iface; 116 + else 117 + return E_NOINTERFACE; 118 + IUnknown_AddRef((IUnknown*)*ppvObject); 119 + return S_OK; 120 + } 121 + 122 + static ULONG Unknown_AddRef(CInternetFolder *This) 123 + { 124 + return InterlockedIncrement(&This->refCount); 125 + } 126 + 127 + static ULONG Unknown_Release(CInternetFolder *This) 128 + { 129 + const ULONG count = InterlockedDecrement(&This->refCount); 130 + if (count == 0) 131 + { 132 + SHFree(This); 133 + unlock_module(); 134 + } 135 + return count; 136 + } 137 + 138 + static HRESULT WINAPI ShellFolder_QueryInterface(IShellFolder *This, REFIID riid, PVOID *ppvObject) 139 + { 140 + return Unknown_QueryInterface(CONTAINING_RECORD(This, CInternetFolder, IShellFolder_iface), riid, ppvObject); 141 + } 142 + 143 + static ULONG WINAPI ShellFolder_AddRef(IShellFolder *This) 144 + { 145 + return Unknown_AddRef(CONTAINING_RECORD(This, CInternetFolder, IShellFolder_iface)); 146 + } 147 + 148 + static ULONG WINAPI ShellFolder_Release(IShellFolder *This) 149 + { 150 + return Unknown_Release(CONTAINING_RECORD(This, CInternetFolder, IShellFolder_iface)); 151 + } 152 + 153 + static HRESULT WINAPI ParseDisplayName(IShellFolder *This, HWND hwnd, IBindCtx *pbc, LPWSTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) 154 + { 155 + UINT len; 156 + 157 + *ppidl = NULL; 158 + len = GetSchemeLength(pszDisplayName); 159 + if (len) 160 + { 161 + if (len + 1 == sizeof("shell:")) 162 + { 163 + WCHAR szBuf[100]; 164 + lstrcpynW(szBuf, pszDisplayName, sizeof("shell:")); 165 + if (!lstrcmpiW(szBuf, L"shell:")) 166 + return E_FAIL; 167 + } 168 + 169 + if ((*ppidl = CreateUrlItem(pszDisplayName)) == NULL) 170 + return E_OUTOFMEMORY; 171 + if (pchEaten) 172 + *pchEaten = lstrlenW(pszDisplayName); 173 + if (pdwAttributes) 174 + IShellFolder_GetAttributesOf(This, 1, (PCUITEMID_CHILD_ARRAY)ppidl, pdwAttributes); 175 + return S_OK; 176 + } 177 + return E_FAIL; 178 + } 179 + 180 + static HRESULT WINAPI ShellFolder_EnumObjects(IShellFolder *This, HWND hwndOwner, SHCONTF grfFlags, IEnumIDList **ppenumIDList) 181 + { 182 + *ppenumIDList = NULL; 183 + return E_NOTIMPL; 184 + } 185 + 186 + static HRESULT WINAPI BindToObject(IShellFolder *This, PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut) 187 + { 188 + *ppvOut = NULL; 189 + return E_NOTIMPL; 190 + } 191 + 192 + static HRESULT WINAPI BindToStorage(IShellFolder *This, PCUIDLIST_RELATIVE pidl, IBindCtx *pbc, REFIID riid, void **ppvOut) 193 + { 194 + *ppvOut = NULL; 195 + return E_NOTIMPL; 196 + } 197 + 198 + static HRESULT WINAPI CompareIDs(IShellFolder *This, LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 199 + { 200 + IFURLITEM *pUrl1 = IsUrlItem(pidl1), *pUrl2 = IsUrlItem(pidl2); 201 + if (pUrl1 && pUrl2) 202 + { 203 + WCHAR szUrl1[MAX_URL_LENGTH], *pszUrl1 = GetUrl(pUrl1, szUrl1); 204 + WCHAR szUrl2[MAX_URL_LENGTH], *pszUrl2 = GetUrl(pUrl2, szUrl2); 205 + int cmp = lstrcmpiW(pszUrl1, pszUrl2); 206 + return cmp < 0 ? 0xffff : cmp != 0; 207 + } 208 + return E_FAIL; 209 + } 210 + 211 + static HRESULT WINAPI CreateViewObject(IShellFolder *This, HWND hwndOwner,REFIID riid,void **ppv) 212 + { 213 + *ppv = NULL; 214 + return E_NOTIMPL; 215 + } 216 + 217 + static HRESULT WINAPI GetAttributesOf(IShellFolder *This, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, SFGAOF *rgfInOut) 218 + { 219 + UINT i; 220 + 221 + if (cidl == 0) 222 + { 223 + *rgfInOut &= SFGAO_FOLDER | SFGAO_CANLINK | SFGAO_STREAM; // Folder attributes 224 + return S_OK; 225 + } 226 + 227 + for (i = 0; i < cidl; ++i) 228 + { 229 + IFURLITEM *pUrl = IsUrlItem(apidl[i]); 230 + if (!pUrl) 231 + return E_FAIL; 232 + *rgfInOut &= SFGAO_CANLINK | SFGAO_BROWSABLE | SFGAO_STREAM; 233 + } 234 + return S_OK; 235 + } 236 + 237 + static HRESULT WINAPI GetUIObjectOf(IShellFolder *This, HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT *rgfReserved, void **ppv) 238 + { 239 + IFURLITEM *pUrl; 240 + if (cidl == 1 && (pUrl = IsUrlItem(apidl[0])) != NULL) 241 + { 242 + if (IsEqualIID(riid, &IID_IExtractIconW) || IsEqualIID(riid, &IID_IExtractIconA) || 243 + IsEqualIID(riid, &IID_IContextMenu) || 244 + IsEqualIID(riid, &IID_IDataObject) || 245 + IsEqualIID(riid, &IID_IQueryInfo)) 246 + { 247 + IUniformResourceLocatorW *pUrlLnk; 248 + WCHAR szUrl[MAX_URL_LENGTH], *pszUrl = GetUrl(pUrl, szUrl); 249 + HRESULT hr = CreateUrlShortcut(pszUrl, &pUrlLnk); 250 + if (SUCCEEDED(hr)) 251 + { 252 + hr = IUnknown_QueryInterface(pUrlLnk, riid, ppv); 253 + IUnknown_Release(pUrlLnk); 254 + } 255 + return hr; 256 + } 257 + } 258 + return E_NOINTERFACE; 259 + } 260 + 261 + static HRESULT WINAPI GetDisplayNameOf(IShellFolder *This, PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pSR) 262 + { 263 + IFURLITEM *pUrl = IsUrlItem(pidl); 264 + if (pUrl) 265 + { 266 + WCHAR szUrl[MAX_URL_LENGTH], *pszUrl = GetUrl(pUrl, szUrl); 267 + pSR->uType = STRRET_WSTR; 268 + return SHStrDupW(pszUrl, &pSR->u.pOleStr); 269 + } 270 + return E_FAIL; 271 + } 272 + 273 + static HRESULT WINAPI SetNameOf(IShellFolder *This, HWND hwndOwner, PCUITEMID_CHILD pidl, LPCWSTR pszName, SHGDNF uFlags, PITEMID_CHILD*ppidlOut) 274 + { 275 + if (ppidlOut) 276 + *ppidlOut = NULL; 277 + return E_NOTIMPL; 278 + } 279 + 280 + static HRESULT WINAPI PersistFolder_QueryInterface(IPersistFolder *This, REFIID riid, PVOID *ppvObject) 281 + { 282 + return Unknown_QueryInterface(CONTAINING_RECORD(This, CInternetFolder, IPersistFolder_iface), riid, ppvObject); 283 + } 284 + 285 + static ULONG WINAPI PersistFolder_AddRef(IPersistFolder *This) 286 + { 287 + return Unknown_AddRef(CONTAINING_RECORD(This, CInternetFolder, IPersistFolder_iface)); 288 + } 289 + 290 + static ULONG WINAPI PersistFolder_Release(IPersistFolder *This) 291 + { 292 + return Unknown_Release(CONTAINING_RECORD(This, CInternetFolder, IPersistFolder_iface)); 293 + } 294 + 295 + static HRESULT WINAPI PersistFolder_GetClassID(IPersistFolder *This, CLSID *pClassID) 296 + { 297 + *pClassID = CLSID_Internet; 298 + return S_OK; 299 + } 300 + 301 + static HRESULT WINAPI PersistFolder_Initialize(IPersistFolder *This, PCIDLIST_ABSOLUTE pidl) 302 + { 303 + return S_OK; 304 + } 305 + 306 + static const IShellFolderVtbl ShellFolderVtbl = { 307 + ShellFolder_QueryInterface, 308 + ShellFolder_AddRef, 309 + ShellFolder_Release, 310 + ParseDisplayName, 311 + ShellFolder_EnumObjects, 312 + BindToObject, 313 + BindToStorage, 314 + CompareIDs, 315 + CreateViewObject, 316 + GetAttributesOf, 317 + GetUIObjectOf, 318 + GetDisplayNameOf, 319 + SetNameOf 320 + }; 321 + 322 + static const IPersistFolderVtbl PersistFolderVtbl = { 323 + PersistFolder_QueryInterface, 324 + PersistFolder_AddRef, 325 + PersistFolder_Release, 326 + PersistFolder_GetClassID, 327 + PersistFolder_Initialize 328 + }; 329 + 330 + static CInternetFolder* CreateInstance(void) 331 + { 332 + CInternetFolder *obj = SHAlloc(sizeof(CInternetFolder)); 333 + if (obj) 334 + { 335 + obj->IShellFolder_iface.lpVtbl = &ShellFolderVtbl; 336 + obj->IPersistFolder_iface.lpVtbl = &PersistFolderVtbl; 337 + obj->refCount = 1; 338 + lock_module(); 339 + } 340 + return obj; 341 + } 342 + 343 + HRESULT WINAPI CInternetFolder_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) 344 + { 345 + CInternetFolder *pThis; 346 + 347 + *ppv = NULL; 348 + if (outer) 349 + return CLASS_E_NOAGGREGATION; 350 + 351 + if ((pThis = CreateInstance()) != NULL) 352 + { 353 + HRESULT hr = Unknown_QueryInterface(pThis, riid, ppv); 354 + Unknown_Release(pThis); 355 + return hr; 356 + } 357 + return E_OUTOFMEMORY; 358 + }
+3
dll/win32/shell32/wine/pidl.h
··· 108 108 #define PT_FOLDERTYPEMASK 0x70 109 109 #define PT_DESKTOP_REGITEM 0x1F // => SHDID_ROOT_REGITEM 110 110 #define PT_COMPUTER_REGITEM 0x2E // => SHDID_COMPUTER_? 111 + #define PT_COMPUTER_DRIVE 0x2F 111 112 #define PT_FS 0x30 // Win95 SHSimpleIDListFromPath 112 113 #define PT_FS_FOLDER_FLAG 0x01 113 114 #define PT_FS_FILE_FLAG 0x02 114 115 #define PT_FS_UNICODE_FLAG 0x04 115 116 #define PT_FS_COMMON_FLAG 0x08 116 117 // PT_NET_REGITEM 0x4? // => SHDID_NET_OTHER 118 + #define PT_INTERNET 0x60 119 + #define PT_INTERNET_URL 0x61 117 120 #define PT_CONTROLS_OLDREGITEM 0x70 118 121 #define PT_CONTROLS_NEWREGITEM 0x71 119 122 #endif
+34
modules/rostests/apitests/shell32/ItemIDList.cpp
··· 12 12 enum { 13 13 DIRBIT = 1, FILEBIT = 2, 14 14 PT_COMPUTER_REGITEM = 0x2E, 15 + PT_INTERNET_URL = 0x61, 15 16 }; 16 17 17 18 static BYTE GetPIDLType(LPCITEMIDLIST pidl) ··· 46 47 C_ASSERT(FIELD_OFFSET(FS95, att) == 12); 47 48 FS95 *p = FS95::Validate(pidl); 48 49 return p ? p->att : (UINT(1) << 31); 50 + } 51 + 52 + static HRESULT GetDisplayNameOf(IShellFolder *pSF, LPCITEMIDLIST pidl, UINT Flags, PWSTR Buf, UINT Cap) 53 + { 54 + STRRET sr; 55 + HRESULT hr = pSF->GetDisplayNameOf(pidl, Flags, &sr); 56 + if (SUCCEEDED(hr)) 57 + hr = StrRetToBufW(&sr, pidl, Buf, Cap); 58 + return hr; 49 59 } 50 60 51 61 #define TEST_CLSID(pidl, type, offset, clsid) \ ··· 195 205 196 206 START_TEST(PIDL) 197 207 { 208 + CCoInit ComInit; 198 209 LPITEMIDLIST pidl; 199 210 200 211 pidl = SHCloneSpecialIDList(NULL, CSIDL_DRIVES, FALSE); ··· 210 221 else 211 222 skip("?\n"); 212 223 ILFree(pidl); 224 + 225 + 226 + CComPtr<IShellFolder> pInternet; 227 + HRESULT hr = SHCoCreateInstance(NULL, &CLSID_Internet, NULL, IID_PPV_ARG(IShellFolder, &pInternet)); 228 + if (SUCCEEDED(hr)) 229 + { 230 + PCWSTR pszUrl = L"http://example.com/page?query&foo=bar"; 231 + PIDLIST_RELATIVE pidlUrl; 232 + hr = pInternet->ParseDisplayName(NULL, NULL, const_cast<PWSTR>(pszUrl), NULL, &pidlUrl, NULL); 233 + ok_long(hr, S_OK); 234 + if (hr == S_OK) 235 + { 236 + ok_int(pidlUrl->mkid.abID[0], PT_INTERNET_URL); 237 + WCHAR buf[MAX_PATH]; 238 + hr = GetDisplayNameOf(pInternet, pidlUrl, SHGDN_FORPARSING, buf, _countof(buf)); 239 + ok_long(hr, S_OK); 240 + if (SUCCEEDED(hr)) 241 + { 242 + ok(!lstrcmpiW(buf, pszUrl), "FORPARSING must match URL\n"); 243 + } 244 + ILFree(pidlUrl); 245 + } 246 + } 213 247 } 214 248 215 249 START_TEST(ILIsEqual)