Skip to content

Commit

Permalink
Merge pull request #8202 from workgroupengineering/features/Skia/WPF/…
Browse files Browse the repository at this point in the history
…FolderPicker

feat(FolderPicker): [Skia][WPF] Added support at SuggestedStartLocati…
  • Loading branch information
mergify[bot] authored Mar 6, 2022
2 parents 67f224d + bc4db1e commit 96e801f
Showing 1 changed file with 117 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Uno.UI.Runtime.Skia;
using Windows.Storage;
using Windows.Storage.Pickers;

Expand All @@ -14,17 +13,36 @@ internal class FolderPickerExtension : IFolderPickerExtension
{
private readonly FolderPicker _picker;

public Guid? SuggestedStartLocation { get; private set; }

public FolderPickerExtension(FolderPicker owner)
{
_picker = owner ?? throw new ArgumentNullException(nameof(owner));
}

public async Task<StorageFolder?> PickSingleFolderAsync(CancellationToken token)
{
SuggestedStartLocation = _picker.SuggestedStartLocation switch
{
PickerLocationId.Desktop => NativeMethods.KnownFolder.Desktop,
PickerLocationId.HomeGroup => NativeMethods.KnownFolder.Profile,
PickerLocationId.Downloads => NativeMethods.KnownFolder.Downloads,
PickerLocationId.ComputerFolder => NativeMethods.KnownFolder.ComputerFolder,
PickerLocationId.DocumentsLibrary => NativeMethods.KnownFolder.DocumentsLibrary,
PickerLocationId.MusicLibrary => NativeMethods.KnownFolder.Music,
PickerLocationId.Objects3D => NativeMethods.KnownFolder.Objects3D,
PickerLocationId.PicturesLibrary => NativeMethods.KnownFolder.Pictures,
PickerLocationId.VideosLibrary => NativeMethods.KnownFolder.Videos,
PickerLocationId.Unspecified => default,
_ => throw new NotImplementedException(),
};
NativeMethods.BROWSEINFO pbi = new NativeMethods.BROWSEINFO();
pbi.ulFlags = 0x41; //BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE
pbi.pszDisplayName = new string('\0', NativeMethods.MAX_PATH);

var callback = new WndProc(FolderBrowserDialog_BrowseCallbackProc);
var cp = Marshal.GetFunctionPointerForDelegate(callback);
GC.KeepAlive(callback);
pbi.lpfn = cp;
IntPtr pidl = NativeMethods.SHBrowseForFolder(ref pbi);
if (pidl != IntPtr.Zero)
{
Expand All @@ -43,11 +61,80 @@ public FolderPickerExtension(FolderPicker owner)
return null;
}

private uint FolderBrowserDialog_BrowseCallbackProc(IntPtr hwnd, uint msg, IntPtr lParam, IntPtr lpData)
{

switch (msg)
{
case NativeMethods.BFFM_INITIALIZED:
var selectedPath = string.Empty;
var buttonText = _picker.CommitButtonText;
if (SuggestedStartLocation is Guid rfid)
{
selectedPath = NativeMethods.SHGetKnownFolderPath(rfid);
}
if (!string.IsNullOrWhiteSpace(selectedPath))
{
NativeMethods.SendMessage(new HandleRef(null, hwnd)
, NativeMethods.BFFM_SETSELECTION
, 1
, selectedPath);
}
if (!string.IsNullOrWhiteSpace(buttonText))
{
NativeMethods.SendMessage(new HandleRef(null, hwnd)
, NativeMethods.BFFM_SETOKTEXT
, 1
, buttonText);
}
break;
case NativeMethods.BFFM_SELCHANGED:
if (lParam != IntPtr.Zero)
{
var path = NativeMethods.SHGetPathFromIDListLong(lParam);
NativeMethods.SendMessage(new HandleRef(null, hwnd)
, NativeMethods.BFFM_ENABLEOK
, 0
, !string.IsNullOrWhiteSpace(path) ? 1 : 0);
}
break;
}

return 0;
}

[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate uint WndProc(IntPtr hwnd, uint msg, IntPtr lParam, IntPtr lpData);

private static class NativeMethods
{
const uint WM_USER = 0x0400;
internal const uint BFFM_INITIALIZED = 1;
internal const uint BFFM_SELCHANGED = 2;
private const uint BFFM_SETSELECTIONA = (WM_USER + 102);
private const uint BFFM_SETSELECTIONW = (WM_USER + 103);
internal const uint BFFM_ENABLEOK = (WM_USER + 101);
internal const uint BFFM_SETOKTEXT = (WM_USER + 105);
internal readonly static uint BFFM_SETSELECTION = Marshal.SystemDefaultCharSize == 1
? BFFM_SETSELECTIONA
: BFFM_SETSELECTIONW;
internal const int MAX_PATH = 260;
private const int MAX_LONG_PATH = 32767;

internal static class KnownFolder
{
public static readonly Guid Desktop = new Guid("B4BFCC3A-DB2C-424C-B029-7FE99A87C641");
public static readonly Guid Profile = new Guid("5E6C858F-0E22-4760-9AFE-EA3317B67173");
public static readonly Guid Downloads = new Guid("374DE290-123F-4565-9164-39C4925E467B");
public static readonly Guid ComputerFolder = new Guid("0AC0837C-BBF8-452A-850D-79D08E667CA7");
public static readonly Guid DocumentsLibrary = new Guid("7B0DB17D-9CD2-4A93-9733-46CC89022E7C");
public static readonly Guid Music = new Guid("4BD8D571-6D19-48D3-BE97-422220080E43");
public static readonly Guid Objects3D = new Guid("31C0DD25-9439-4F12-BF41-7FF4EDA38722");
public static readonly Guid Pictures = new Guid("33E28130-4E1E-4676-835A-98395C3BC3BB");
public static readonly Guid Videos = new Guid("18989B1D-99B5-455B-841C-AB7C74E4DDFC");
}


[DllImport("shell32", EntryPoint ="SHBrowseForFolderW", CharSet=CharSet.Unicode)]
internal static extern IntPtr SHBrowseForFolder(ref BROWSEINFO lpbi);

Expand Down Expand Up @@ -83,6 +170,34 @@ private static class NativeMethods
[DllImport("shell32")]
private static extern bool SHGetPathFromIDListEx(IntPtr pidl, IntPtr pszPath, int len, int flags);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(HandleRef hWnd, uint msg, int wParam, string? lParam);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(HandleRef hWnd, uint msg, int wParam, int lParam);


internal static string SHGetKnownFolderPath(Guid rfid, uint dwFlags = 0, IntPtr hToken = default(IntPtr))
{
IntPtr pszPath;
SHGetKnownFolderPath(rfid, dwFlags, hToken, out pszPath);

try
{
return Marshal.PtrToStringUni(pszPath);
}
finally
{
Marshal.FreeCoTaskMem(pszPath);
}
}

[DllImport("shell32.dll")]
private static extern int SHGetKnownFolderPath([MarshalAs(UnmanagedType.LPStruct)] Guid rfid,
uint dwFlags
, IntPtr hToken
, out IntPtr pszPath);

internal struct BROWSEINFO
{
internal IntPtr hwndOwner;
Expand Down

0 comments on commit 96e801f

Please sign in to comment.