Skip to content

Commit 816fcdc

Browse files
committed
Fixed a memory leak
1 parent c6993ea commit 816fcdc

File tree

2 files changed

+99
-46
lines changed

2 files changed

+99
-46
lines changed

src/Files.App.CsWin32/IInternalCustomDestinationList.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,14 @@ public struct _Anonymous_e__Union
125125
public fixed int Padding[10];
126126
}
127127

128+
/// <summary>
129+
/// Defines constants that specify category enumeration behavior.
130+
/// </summary>
128131
public enum GETCATFLAG : uint
129132
{
130-
// 1 is the only valid value?
133+
/// <summary>
134+
/// The default behavior. Only this value is currently valid.
135+
/// </summary>
131136
DEFAULT = 1,
132137
}
133138

src/Files.App.Storage/Windows/Managers/JumpListManager.cs

Lines changed: 93 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.IO;
55
using System.Runtime.CompilerServices;
66
using Windows.ApplicationModel;
7+
using Windows.Devices.Enumeration.Pnp;
78
using Windows.Win32;
89
using Windows.Win32.Foundation;
910
using Windows.Win32.System.Com;
@@ -167,7 +168,7 @@ private HRESULT SyncFilesJumpListWithExplorer(int maxItemsToSync)
167168
{
168169
HRESULT hr = default;
169170

170-
// If the Explorer's Automatic Destination has no items, nothing to sync
171+
// Get whether the Files's Automatic Destination has items
171172
BOOL hasList = default;
172173
hr = _filesADL->HasList(&hasList);
173174
if (FAILED(hr)) return hr;
@@ -192,27 +193,27 @@ private HRESULT SyncFilesJumpListWithExplorer(int maxItemsToSync)
192193
hr = poc.Get()->GetCount(&dwItemsCount);
193194
if (FAILED(hr)) return hr;
194195

195-
//for (uint dwIndex = 0; dwIndex < dwItemsCount; dwIndex++)
196-
//{
197-
// // Get an instance of IShellItem
198-
// using ComPtr<IShellItem> psi = default;
199-
// hr = poc.Get()->GetAt(dwIndex, IID.IID_IShellItem, (void**)psi.GetAddressOf());
200-
// if (FAILED(hr)) continue;
196+
for (uint dwIndex = 0; dwIndex < dwItemsCount; dwIndex++)
197+
{
198+
// Get an instance of IShellItem
199+
using ComPtr<IShellItem> psi = default;
200+
hr = poc.Get()->GetAt(dwIndex, IID.IID_IShellItem, (void**)psi.GetAddressOf());
201+
if (FAILED(hr)) continue;
201202

202-
// // Get its pin index
203-
// int pinIndex = 0;
204-
// hr = _explorerADL->GetPinIndex((IUnknown*)psi.Get(), &pinIndex);
205-
// if (FAILED(hr)) continue;
203+
// Get its pin index
204+
int pinIndex = 0;
205+
hr = _explorerADL->GetPinIndex((IUnknown*)psi.Get(), &pinIndex);
206+
if (FAILED(hr)) continue;
206207

207-
// // Get an instance of IShellLinkW from the IShellItem instance
208-
// IShellLinkW* psl = default;
209-
// hr = CreateLinkFromItem(psi.Get(), &psl);
210-
// if (FAILED(hr)) continue;
208+
// Get an instance of IShellLinkW from the IShellItem instance
209+
IShellLinkW* psl = default;
210+
hr = CreateLinkFromItem(psi.Get(), &psl);
211+
if (FAILED(hr)) continue;
211212

212-
// // Pin it to the Files' Automatic Destinations
213-
// hr = _filesADL->PinItem((IUnknown*)psl, pinIndex);
214-
// if (FAILED(hr)) continue;
215-
//}
213+
// Pin it to the Files' Automatic Destinations
214+
hr = _filesADL->PinItem((IUnknown*)psl, pinIndex);
215+
if (FAILED(hr)) continue;
216+
}
216217

217218
// Get the Explorer's Recent items from its Automatic Destination
218219
poc.Dispose();
@@ -226,6 +227,7 @@ private HRESULT SyncFilesJumpListWithExplorer(int maxItemsToSync)
226227
// Instantiate an instance of IObjectCollection
227228
using ComPtr<IObjectCollection> pNewObjectCollection = default;
228229
hr = PInvoke.CoCreateInstance(CLSID.CLSID_EnumerableObjectCollection, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IObjectCollection, (void**)pNewObjectCollection.GetAddressOf());
230+
if (FAILED(hr)) return hr;
229231

230232
for (uint dwIndex = 0; dwIndex < dwItemsCount; dwIndex++)
231233
{
@@ -260,8 +262,11 @@ private HRESULT SyncFilesJumpListWithExplorer(int maxItemsToSync)
260262
hr = _filesCDL->BeginList(&cMinSlots, IID.IID_IObjectArray, (void**)pRemovedObjectArray.GetAddressOf());
261263
if (FAILED(hr)) return hr;
262264

265+
hr = pRemovedObjectArray.Get()->GetCount(out var count);
266+
if (FAILED(hr)) return hr;
267+
263268
// Append "Recent" category
264-
hr = _filesCDL->AppendCategory((PCWSTR)Unsafe.AsPointer(ref Unsafe.AsRef(in _localizedRecentCategoryName.GetPinnableReference())), pNewObjectArray.Get());
269+
hr = _filesCDL->AppendCategory((PCWSTR)Unsafe.AsPointer(ref Unsafe.AsRef(in "Recent".GetPinnableReference())), pNewObjectArray.Get());
265270
if (FAILED(hr)) return hr;
266271

267272
// Commit the collection updates
@@ -275,71 +280,106 @@ private HRESULT SyncExplorerJumpListWithFiles(int maxItemsToSync)
275280
{
276281
HRESULT hr = default;
277282

283+
// Get whether the Explorer's Automatic Destination has items
278284
BOOL hasList = default;
279285
hr = _explorerADL->HasList(&hasList);
280286
if (FAILED(hr)) return hr;
281287

288+
// Clear the Explorer' Automatic Destination if any
282289
if (hasList)
283290
{
284291
hr = _explorerADL->ClearList(true);
285292
if (FAILED(hr)) return hr;
286293
}
287294

295+
// Get the count of categories in the Files' Custom Destinations
288296
uint count = 0U;
289297
_filesICDL->GetCategoryCount(&count);
290298

291-
uint dwDestinationsIndex = 0U;
292-
for (uint dwIndex = 0U; dwIndex < count; dwIndex++)
299+
// Find the "Recent" category index
300+
uint indexOfRecentCategory = 0U;
301+
for (uint index = 0U; index < count; index++)
293302
{
294303
APPDESTCATEGORY category = default;
295304

296305
try
297306
{
298-
hr = _filesICDL->GetCategory(dwIndex, GETCATFLAG.DEFAULT, &category);
307+
hr = _filesICDL->GetCategory(index, GETCATFLAG.DEFAULT, &category);
299308
if (FAILED(hr) ||
300309
category.Type is not APPDESTCATEGORYTYPE.CUSTOM ||
301310
!_localizedRecentCategoryName.Equals(new(category.Anonymous.Name), StringComparison.OrdinalIgnoreCase))
302311
continue;
303312

304-
dwDestinationsIndex = dwIndex;
313+
indexOfRecentCategory = index;
305314
}
306315
finally
307-
308316
{
309317
// The memory layout at Name can be either PWSTR or int depending on the category type
310318
if (category.Anonymous.Name.Value is not null && category.Type is APPDESTCATEGORYTYPE.CUSTOM)
311319
PInvoke.CoTaskMemFree(category.Anonymous.Name);
312320
}
313321
}
314322

315-
using ComPtr<IObjectCollection> pDestinationsObjectCollection = default;
316-
hr = _filesICDL->EnumerateCategoryDestinations(dwDestinationsIndex, IID.IID_IObjectCollection, (void**)pDestinationsObjectCollection.GetAddressOf());
323+
// Get the items in the "Recent" category
324+
using ComPtr<IObjectCollection> poc = default;
325+
hr = _filesICDL->EnumerateCategoryDestinations(indexOfRecentCategory, IID.IID_IObjectCollection, (void**)poc.GetAddressOf());
326+
327+
// Get the count of items in the "Recent" category
328+
uint countOfItems = 0U;
329+
hr = poc.Get()->GetCount(&countOfItems);
330+
if (FAILED(hr)) return hr;
331+
332+
// Copy them to the Explorer's Automatic Destination
333+
for (uint index = 0U; index < countOfItems && index < maxItemsToSync; index++)
334+
{
335+
using ComPtr<IShellLinkW> psl = default;
336+
hr = poc.Get()->GetAt(index, IID.IID_IShellLinkW, (void**)psl.GetAddressOf());
337+
if (FAILED(hr)) continue;
338+
339+
using ComHeapPtr<char> pszParseablePath = default;
340+
pszParseablePath.Allocate(PInvoke.MAX_PATH);
341+
hr = psl.Get()->GetArguments(pszParseablePath.Get(), (int)PInvoke.MAX_PATH);
342+
343+
using ComHeapPtr<IShellItem> psi = default;
344+
hr = PInvoke.SHCreateItemFromParsingName(pszParseablePath.Get(), null, IID.IID_IShellItem, (void**)psi.GetAddressOf());
345+
if (FAILED(hr)) continue;
346+
347+
hr = _explorerADL->AddUsagePoint((IUnknown*)psi.Get());
348+
if (FAILED(hr)) continue;
349+
}
350+
351+
// Get the Explorer's Pinned items from its Automatic Destination
352+
poc.Dispose();
353+
hr = _filesADL->GetList(DESTLISTTYPE.PINNED, maxItemsToSync, GETDESTLISTFLAGS.NONE, IID.IID_IObjectCollection, (void**)poc.GetAddressOf());
354+
if (FAILED(hr)) return hr;
317355

318-
uint dwItems = 0U;
319-
hr = pDestinationsObjectCollection.Get()->GetCount(&dwItems);
356+
// Get the count of the Explorer's Pinned items
357+
hr = poc.Get()->GetCount(&countOfItems);
320358
if (FAILED(hr)) return hr;
321359

322-
for (uint dwIndex = 0U; dwIndex < dwItems && dwIndex < maxItemsToSync; dwIndex++)
360+
// Copy them to the Explorer's Automatic Destination
361+
for (uint index = 0U; index < countOfItems; index++)
323362
{
324363
using ComPtr<IShellLinkW> psl = default;
325-
hr = pDestinationsObjectCollection.Get()->GetAt(dwIndex, IID.IID_IShellLinkW, (void**)psl.GetAddressOf());
364+
hr = poc.Get()->GetAt(index, IID.IID_IShellLinkW, (void**)psl.GetAddressOf());
326365
if (FAILED(hr)) continue;
327366

328-
using ComHeapPtr<ITEMIDLIST> pidl = default;
329-
hr = psl.Get()->GetIDList(pidl.GetAddressOf());
367+
using ComHeapPtr<char> pszParseablePath = default;
368+
pszParseablePath.Allocate(PInvoke.MAX_PATH);
369+
hr = psl.Get()->GetArguments(pszParseablePath.Get(), (int)PInvoke.MAX_PATH);
330370

331371
using ComHeapPtr<IShellItem> psi = default;
332-
hr = PInvoke.SHCreateItemFromIDList(pidl.Get(), IID.IID_IShellItem, (void**)psi.GetAddressOf());
372+
hr = PInvoke.SHCreateItemFromParsingName(pszParseablePath.Get(), null, IID.IID_IShellItem, (void**)psi.GetAddressOf());
333373
if (FAILED(hr)) continue;
334374

335375
hr = _explorerADL->AddUsagePoint((IUnknown*)psi.Get());
336376
if (FAILED(hr)) continue;
337377

338-
int pinIndex = 0;
339-
hr = _explorerADL->GetPinIndex((IUnknown*)psl.Get(), &pinIndex);
340-
if (FAILED(hr)) continue; // If not pinned, HRESULT is E_NOT_SET
378+
int pinIndex;
379+
hr = _filesADL->GetPinIndex((IUnknown*)psl.Get(), &pinIndex);
380+
if (FAILED(hr)) continue;
341381

342-
hr = _filesADL->PinItem((IUnknown*)psi.Get(), -1);
382+
hr = _explorerADL->PinItem((IUnknown*)psi.Get(), pinIndex);
343383
if (FAILED(hr)) continue;
344384
}
345385

@@ -348,38 +388,46 @@ category.Type is not APPDESTCATEGORYTYPE.CUSTOM ||
348388

349389
private HRESULT CreateLinkFromItem(IShellItem* psi, IShellLinkW** ppsl)
350390
{
391+
// Instantiate a default instance of IShellLinkW
351392
using ComPtr<IShellLinkW> psl = default;
352393
HRESULT hr = PInvoke.CoCreateInstance(CLSID.CLSID_ShellLink, null, CLSCTX.CLSCTX_INPROC_SERVER, IID.IID_IShellLinkW, (void**)psl.GetAddressOf());
353394
if (FAILED(hr)) return hr;
354395

355-
fixed (char* pszFilesEntryPointPath = $"Shell:AppsFolder\\{_filesAUMID}")
396+
// Set the Files package path in the shell namespace
397+
fixed (char* pszFilesEntryPointPath = $"files-dev.exe")
356398
hr = psl.Get()->SetPath(pszFilesEntryPointPath);
357399
if (FAILED(hr)) return hr;
358400

401+
// Get the full path of the folder
359402
using ComHeapPtr<char> pszParseablePath = default;
360403
hr = psi->GetDisplayName(SIGDN.SIGDN_DESKTOPABSOLUTEPARSING, (PWSTR*)pszParseablePath.GetAddressOf());
361404
if (FAILED(hr)) return hr;
362405

363-
hr = psl.Get()->SetArguments(new(pszParseablePath.Get()));
406+
// Set it as the argument of the link
407+
hr = psl.Get()->SetArguments(pszParseablePath.Get());
364408
if (FAILED(hr)) return hr;
365409

410+
// Get the icon location of the folder
366411
using ComHeapPtr<char> pszIconLocation = default;
367-
pszIconLocation.Allocate(PInvoke.MAX_PATH);
368-
int index = 0;
412+
pszIconLocation.Allocate(PInvoke.MAX_PATH); int index = 0;
369413
hr = GetFolderIconLocation(psi, (PWSTR*)pszIconLocation.GetAddressOf(), PInvoke.MAX_PATH, &index);
370414
if (FAILED(hr)) return hr;
371415

416+
// Set it as the icon location of the link
372417
hr = psl.Get()->SetIconLocation(pszIconLocation.Get(), index);
373418
if (FAILED(hr)) return hr;
374419

420+
// Get the display name of the folder
375421
using ComHeapPtr<char> pszDisplayName = default;
376422
hr = psi->GetDisplayName(SIGDN.SIGDN_PARENTRELATIVEFORUI, (PWSTR*)pszDisplayName.GetAddressOf());
377423
if (FAILED(hr)) return hr;
378424

425+
// Set it as the tooltip of the link
379426
fixed (char* pszTooltip = $"{new(pszDisplayName.Get())} ({new(pszParseablePath.Get())})")
380427
hr = psl.Get()->SetDescription(pszTooltip);
381428
if (FAILED(hr)) return hr;
382429

430+
// Query an instance of IPropertyStore
383431
using ComPtr<IPropertyStore> pps = default;
384432
hr = psl.Get()->QueryInterface(IID.IID_IPropertyStore, (void**)pps.GetAddressOf());
385433
if (FAILED(hr)) return hr;
@@ -399,8 +447,8 @@ private HRESULT CreateLinkFromItem(IShellItem* psi, IShellLinkW** ppsl)
399447
hr = PInvoke.PropVariantClear(&PVAR_Title);
400448
if (FAILED(hr)) return hr;
401449

402-
hr = psl.Get()->QueryInterface(IID.IID_IShellLinkW, (void**)ppsl);
403-
if (FAILED(hr)) return hr;
450+
psl.Get()->AddRef();
451+
*ppsl = psl.Get();
404452

405453
return hr;
406454
}
@@ -427,7 +475,7 @@ private void ExplorerJumpListWatcher_Changed(object sender, FileSystemEventArgs
427475

428476
private void FilesJumpListWatcher_Changed(object sender, FileSystemEventArgs e)
429477
{
430-
//PushJumpListToExplorer();
478+
PushJumpListToExplorer();
431479
}
432480

433481
public void Dispose()

0 commit comments

Comments
 (0)