Adds support for an initial directory in folder picker

Enhances the modern folder browser to accept and open to a specified initial directory.

This improves the user experience by starting the "Browse for Drivers" dialog in the project's 'Drivers' subfolder, reducing the need for manual navigation. The implementation uses the Win32 API to create a shell item from the initial path and set it as the dialog's starting folder.
This commit is contained in:
rbalsleyMSFT
2025-06-26 18:37:22 -07:00
parent 9bbb40ce8c
commit dfe07b16ae
2 changed files with 170 additions and 143 deletions
@@ -594,7 +594,8 @@ function Register-EventHandlers {
param($eventSource, $routedEventArgs)
$window = [System.Windows.Window]::GetWindow($eventSource)
$localState = $window.Tag
$selectedPath = Invoke-BrowseAction -Type 'Folder' -Title "Select Drivers Folder"
$initialDir = Join-Path -Path $localState.FFUDevelopmentPath -ChildPath "Drivers"
$selectedPath = Invoke-BrowseAction -Type 'Folder' -Title "Select Drivers Folder" -InitialDirectory $initialDir
if ($selectedPath) {
$localState.Controls.txtDriversFolder.Text = $selectedPath
}
@@ -620,7 +620,8 @@ function Invoke-ListViewSort {
# 1) Define a C# class that uses the correct GUIDs for IFileDialog, IFileOpenDialog, and FileOpenDialog,
# while omitting conflicting "GetResults/GetSelectedItems" from IFileDialog.
Add-Type -TypeDefinition @"
if (-not ("ModernFolderBrowser" -as [type])) {
$modernFolderBrowserCode = @"
using System;
using System.Runtime.InteropServices;
@@ -629,6 +630,7 @@ public static class ModernFolderBrowser
// Flags for IFileDialog
[Flags]
private enum FileDialogOptions : uint
{
OverwritePrompt = 0x00000002,
StrictFileTypes = 0x00000004,
@@ -718,9 +720,13 @@ public static class ModernFolderBrowser
void Compare(IShellItem psi, uint hint, out int piOrder);
}
private const uint SIGDN_FILESYSPATH = 0x80058000;
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellItem ppv);
public static string ShowDialog(string title, IntPtr parentHandle)
private const uint SIGDN_FILESYSPATH = 0x80058000;
private static readonly Guid IID_IShellItem = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE");
public static string ShowDialog(string title, IntPtr parentHandle, string initialDirectory)
{
// Create COM dialog instance
IFileOpenDialog dialog = (IFileOpenDialog)(new FileOpenDialog());
@@ -733,6 +739,24 @@ public static class ModernFolderBrowser
opts |= FileDialogOptions.PickFolders | FileDialogOptions.PathMustExist | FileDialogOptions.ForceFileSystem;
dialog.SetOptions(opts);
// Set initial directory if provided
if (!string.IsNullOrEmpty(initialDirectory))
{
try
{
Guid iid = IID_IShellItem; // Create a local copy to pass by ref
if (SHCreateItemFromParsingName(initialDirectory, IntPtr.Zero, ref iid, out IShellItem initialFolder) == 0)
{
dialog.SetFolder(initialFolder);
Marshal.ReleaseComObject(initialFolder);
}
}
catch
{
// Ignore errors in setting initial directory (e.g., path doesn't exist)
}
}
// Set title
if (!string.IsNullOrEmpty(title))
{
@@ -770,15 +794,18 @@ public static class ModernFolderBrowser
return folderPath;
}
}
"@ -Language CSharp
"@
Add-Type -TypeDefinition $modernFolderBrowserCode -Language CSharp
}
# 2) Define a PowerShell function that invokes our C# wrapper
function Show-ModernFolderPicker {
param(
[string]$Title = "Select a folder"
[string]$Title = "Select a folder",
[string]$InitialDirectory
)
# For a simple test, pass IntPtr.Zero as the parent window handle
return [ModernFolderBrowser]::ShowDialog($Title, [IntPtr]::Zero)
return [ModernFolderBrowser]::ShowDialog($Title, [IntPtr]::Zero, $InitialDirectory)
}
function Invoke-BrowseAction {
@@ -797,8 +824,7 @@ function Invoke-BrowseAction {
switch ($Type) {
'Folder' {
# Show-ModernFolderPicker does not currently support setting an initial directory.
return Show-ModernFolderPicker -Title $Title
return Show-ModernFolderPicker -Title $Title -InitialDirectory $InitialDirectory
}
'OpenFile' {
$dialog = New-Object Microsoft.Win32.OpenFileDialog