-
Notifications
You must be signed in to change notification settings - Fork 991
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix FolderNameEditor memory leak on cancel (#769)
* Cleanup FolderNameEditor * Match FolderBrowserDialog code in FolderNameEditor Fix leaks * PR feedback, more cleanup and fixes * PR feedback
- Loading branch information
Showing
24 changed files
with
510 additions
and
543 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
internal static partial class Interop | ||
{ | ||
public static class HRESULT | ||
{ | ||
public const int S_OK = 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
internal static partial class Interop | ||
{ | ||
public static partial class Libraries | ||
{ | ||
internal const string Kernel32 = "kernel32.dll"; | ||
internal const string Gdi32 = "gdi32.dll"; | ||
internal const string User32 = "user32.dll"; | ||
internal const string Shell32 = "shell32.dll"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
internal partial class Interop | ||
{ | ||
internal partial class Kernel32 | ||
{ | ||
internal const int MAX_PATH = 260; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
src/Common/src/Interop/Kernel32/Interop.MAX_UNICODESTRING_LEN.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
internal partial class Interop | ||
{ | ||
internal partial class Kernel32 | ||
{ | ||
internal const int MAX_UNICODESTRING_LEN = short.MaxValue; | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/Common/src/Interop/Shell32/Interop.SHBrowseForFolder.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.Win32.SafeHandles; | ||
|
||
internal static partial class Interop | ||
{ | ||
public static partial class Shell32 | ||
{ | ||
[DllImport(Libraries.Shell32)] | ||
public static extern CoTaskMemSafeHandle SHBrowseForFolderW(ref BROWSEINFO lpbi); | ||
|
||
public delegate int BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lParam, IntPtr lpData); | ||
|
||
public static class BrowseInfoFlags | ||
{ | ||
public const uint BIF_RETURNONLYFSDIRS = 0x00000001; | ||
public const uint BIF_DONTGOBELOWDOMAIN = 0x00000002; | ||
public const uint BIF_RETURNFSANCESTORS = 0x00000008; | ||
public const uint BIF_EDITBOX = 0x00000010; | ||
public const uint BIF_NEWDIALOGSTYLE = 0x00000040; | ||
public const uint BIF_NONEWFOLDERBUTTON = 0x00000200; | ||
|
||
public const uint BIF_BROWSEFORCOMPUTER = 0x00001000; | ||
public const uint BIF_BROWSEFORPRINTER = 0x00002000; | ||
public const uint BIF_BROWSEFOREVERYTHING = 0x00004000; | ||
} | ||
|
||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] | ||
public unsafe struct BROWSEINFO | ||
{ | ||
public IntPtr hwndOwner; | ||
|
||
public CoTaskMemSafeHandle pidlRoot; | ||
|
||
public char *pszDisplayName; | ||
|
||
public string lpszTitle; | ||
|
||
public uint ulFlags; | ||
|
||
public BrowseCallbackProc lpfn; | ||
|
||
public IntPtr lParam; | ||
|
||
public int iImage; | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/Common/src/Interop/Shell32/Interop.SHGetKnownFolderPath.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Runtime.InteropServices; | ||
|
||
internal static partial class Interop | ||
{ | ||
public static partial class Shell32 | ||
{ | ||
[DllImport(Libraries.Shell32, CharSet = CharSet.Unicode, SetLastError = false, BestFitMapping = false, ExactSpelling = true)] | ||
public static extern int SHGetKnownFolderPath(ref Guid rfid, uint dwFlags, IntPtr hToken, out string pszPath); | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
src/Common/src/Interop/Shell32/Interop.SHGetPathFromIDListLongPath.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.Win32.SafeHandles; | ||
|
||
internal static partial class Interop | ||
{ | ||
public static partial class Shell32 | ||
{ | ||
[DllImport(ExternDll.Shell32, EntryPoint = "SHGetPathFromIDListEx", ExactSpelling = true)] | ||
private static extern bool SHGetPathFromIDListEx(IntPtr pidl, IntPtr pszPath, int cchPath, int flags); | ||
|
||
public static bool SHGetPathFromIDListLongPath(IntPtr pidl, out string path) | ||
{ | ||
IntPtr pszPath = Marshal.AllocHGlobal((Interop.Kernel32.MAX_PATH + 1) * sizeof(char)); | ||
int length = Interop.Kernel32.MAX_PATH; | ||
try | ||
{ | ||
if (!SHGetPathFromIDListLongPath(pidl, ref pszPath, length)) | ||
{ | ||
path = null; | ||
return false; | ||
} | ||
|
||
path = Marshal.PtrToStringAuto(pszPath); | ||
return true; | ||
} | ||
finally | ||
{ | ||
Marshal.FreeHGlobal(pszPath); | ||
} | ||
} | ||
|
||
public unsafe static bool SHGetPathFromIDListLongPath(IntPtr pidl, ref IntPtr pszPath, int length) | ||
{ | ||
// SHGetPathFromIDListEx is basically a helper to get IShellFolder.DisplayNameOf() with some | ||
// extra functionally built in if the various flags are set. | ||
|
||
// SHGetPathFromIDListEx copies into the ouput buffer using StringCchCopyW, which truncates | ||
// when there isn't enough space (with a terminating null) and fails. Long paths can be | ||
// extracted by simply increasing the buffer size whenever the buffer is full. | ||
|
||
// To get the equivalent functionality we could call SHBindToParent on the PIDL to get IShellFolder | ||
// and then invoke IShellFolder.DisplayNameOf directly. This would avoid long path contortions as | ||
// we could directly convert from STRRET, calling CoTaskMemFree manually. (Presuming the type is | ||
// STRRET_WSTR, of course. Otherwise we can just fall back to StrRetToBufW and give up for > MAX_PATH. | ||
// Presumption is that we shouldn't be getting back ANSI results, and if we are they are likely | ||
// some very old component that won't have a > MAX_PATH string.) | ||
|
||
// While we could avoid contortions and avoid intermediate buffers by invoking IShellFolder directly, | ||
// it isn't without cost as we'd be initializing a COM wrapper (RCW) for IShellFolder. Presumably | ||
// this is much less overhead then looping and copying to intermediate buffers before creating a string. | ||
// Additionally, implementing this would allow us to short circuit the one caller (FolderBrowserDialog) | ||
// who doesn't care about the path, but just wants to know that we have an IShellFolder. | ||
while (SHGetPathFromIDListEx(pidl, pszPath, length, 0) == false) | ||
{ | ||
if (length >= Kernel32.MAX_UNICODESTRING_LEN | ||
|| *(char*)pszPath.ToPointer() == '\0') | ||
{ | ||
// Already at the maximum size string, or no data was copied in. Fail. | ||
return false; | ||
} | ||
|
||
// Try giving the API a larger buffer | ||
length = length * 2; | ||
if (length > Kernel32.MAX_UNICODESTRING_LEN) | ||
length = Kernel32.MAX_UNICODESTRING_LEN; | ||
|
||
pszPath = Marshal.ReAllocHGlobal(pszPath, (IntPtr)(length * sizeof(char))); | ||
} | ||
|
||
return true; | ||
} | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
src/Common/src/Interop/Shell32/Interop.SHGetSpecialFolderLocation.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.Win32.SafeHandles; | ||
|
||
internal static partial class Interop | ||
{ | ||
public static partial class Shell32 | ||
{ | ||
[DllImport(Libraries.Shell32, EntryPoint = "SHGetSpecialFolderLocation", ExactSpelling = true)] | ||
public static extern int SHGetSpecialFolderLocation(IntPtr hwnd, int csidl, out CoTaskMemSafeHandle ppidl); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/Common/src/Microsoft/Win32/SafeHandles/CoTaskMemSafeHandle.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
// See the LICENSE file in the project root for more information. | ||
|
||
using System; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Microsoft.Win32.SafeHandles | ||
{ | ||
internal sealed class CoTaskMemSafeHandle : SafeHandle | ||
{ | ||
internal CoTaskMemSafeHandle() : base(IntPtr.Zero, true) | ||
{ | ||
} | ||
|
||
public override bool IsInvalid => IsClosed || handle == IntPtr.Zero; | ||
|
||
protected override bool ReleaseHandle() | ||
{ | ||
Marshal.FreeCoTaskMem(handle); | ||
handle = IntPtr.Zero; | ||
return true; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.