/ src / settings-ui / Settings.UI / Helpers / ShellGetFolder.cs
ShellGetFolder.cs
 1  // Copyright (c) Microsoft Corporation
 2  // The Microsoft Corporation licenses this file to you under the MIT license.
 3  // See the LICENSE file in the project root for more information.
 4  
 5  using System;
 6  using System.Runtime.InteropServices;
 7  using System.Text;
 8  
 9  namespace Microsoft.PowerToys.Settings.UI.Helpers
10  {
11      public class ShellGetFolder
12      {
13          public delegate int BrowseCallbackProc(IntPtr hwnd, int msg, IntPtr lp, IntPtr wp);
14  
15          [StructLayout(LayoutKind.Sequential)]
16          public struct BrowseInformation
17          {
18              public IntPtr HwndOwner;
19              public IntPtr PidlRoot;
20              public string PszDisplayName;
21              public string LpszTitle;
22              public uint UlFlags;
23              public BrowseCallbackProc Lpfn;
24              public IntPtr LParam;
25              public int IImage;
26          }
27  
28          public static string GetFolderDialog(IntPtr hwndOwner)
29          {
30              return GetFolderDialogWithFlags(hwndOwner, 0);
31          }
32  
33          public static string GetFolderDialogWithFlags(IntPtr hwndOwner, uint ulFlags)
34          {
35              // windows MAX_PATH with long path enable can be approximated 32k char long
36              // allocating more than double (unicode) to hold the path
37              StringBuilder sb = new StringBuilder(65000);
38              IntPtr bufferAddress = Marshal.AllocHGlobal(65000);
39              IntPtr pidl = IntPtr.Zero;
40              BrowseInformation browseInfo;
41              browseInfo.HwndOwner = hwndOwner;
42              browseInfo.PidlRoot = IntPtr.Zero;
43              browseInfo.PszDisplayName = null;
44              browseInfo.LpszTitle = null;
45              browseInfo.UlFlags = ulFlags;
46              browseInfo.Lpfn = null;
47              browseInfo.LParam = IntPtr.Zero;
48              browseInfo.IImage = 0;
49  
50              try
51              {
52                  pidl = NativeMethods.SHBrowseForFolderW(ref browseInfo);
53                  if (NativeMethods.SHGetPathFromIDListW(pidl, bufferAddress) == 0)
54                  {
55                      return null;
56                  }
57  
58                  sb.Append(Marshal.PtrToStringUni(bufferAddress));
59                  Marshal.FreeHGlobal(bufferAddress);
60              }
61              finally
62              {
63                  // Need to free pidl
64                  Marshal.FreeCoTaskMem(pidl);
65              }
66  
67              return sb.ToString();
68          }
69  
70          public struct FolderDialogFlags
71          {
72              public const uint _BIF_NEWDIALOGSTYLE = 0x00000040;
73          }
74      }
75  }