How to set the directory of a save as dialog box through code?
See the question and my original answer on StackOverflowHere is a sample .NET Framework Console App that uses UI Automation, opens Notepad, type something and saves it as a file in the temp folder, using the Address bar on top of the Common Dialog.
See here .NET UI Automation Overview or here Native UI Automation for introduction and reference on UI Automation. It's usually better to use UI Automation than hacking windows handles. If you can't do it with UI Automation, there are chances you won't be able to do it with handles anyway. To discover the elements you can use and code against, you can use the Inspect tool from the Windows SDK.
Note I'm using here an interop version of the native UI Automation, as the .NET original wrappers that are provided with Windows have not been updated by Microsoft for many years for some reason.
// this code needs the "Interop.UIAutomationClient" Nuget package and "using Interop.UIAutomationClient"
class Program
{
private static readonly CUIAutomation8 _automation = new CUIAutomation8();
static void Main()
{
// track window open event
var processId = 0;
_automation.AddAutomationEventHandler(UIA_EventIds.UIA_Window_WindowOpenedEventId, _automation.GetRootElement(), TreeScope.TreeScope_Subtree, null,
new AutomationEventHandler((window, id) =>
{
// check the process id we opened
if (window.CurrentProcessId != processId)
return;
// get editor control
var editor = window.FindFirst(TreeScope.TreeScope_Children, _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_EditControlTypeId));
if (editor == null) // not the window we're looking for
return;
// get editor's value pattern & set some text value
var value = (IUIAutomationValuePattern)editor.GetCurrentPattern(UIA_PatternIds.UIA_ValuePatternId);
value.SetValue("hello world");
// get menu bar
var menuBar = window.FindFirst(TreeScope.TreeScope_Children, _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_MenuBarControlTypeId));
if (menuBar == null)
{
Console.WriteLine("Can't find menu bar.");
return;
}
// get "File" menu item (beware of localization) & invoke (open)
var file = menuBar.FindFirst(TreeScope.TreeScope_Children, _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_NamePropertyId, "File"));
if (file == null)
{
Console.WriteLine("Can't find 'File' menu item.");
return;
}
// expand "File" menu
var expand = (IUIAutomationExpandCollapsePattern)file.GetCurrentPattern(UIA_PatternIds.UIA_ExpandCollapsePatternId);
expand.Expand();
do
{
// get the "Save" item by name from the window subtree (as the menu that opens is a child of the window)
// do some retry to handle menu opening time
var save = window.FindFirst(TreeScope.TreeScope_Subtree, _automation.CreatePropertyConditionEx(UIA_PropertyIds.UIA_NamePropertyId, "Save", PropertyConditionFlags.PropertyConditionFlags_MatchSubstring));
if (save != null)
{
((IUIAutomationInvokePattern)save.GetCurrentPattern(UIA_PatternIds.UIA_InvokePatternId)).Invoke();
break;
}
}
while (true);
// get the "Save As" dialog
// do some retry to handle dialog opening time
IUIAutomationElement dialog;
do
{
dialog = window.FindFirst(TreeScope.TreeScope_Subtree, _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_LocalizedControlTypePropertyId, "dialog"));
if (dialog != null)
break;
}
while (true);
// get the "Previous locations" to enable the Address edit box
var previous = dialog.FindFirst(TreeScope.TreeScope_Subtree, _automation.CreateAndCondition(
_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_ButtonControlTypeId),
_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_NamePropertyId, "Previous Locations")));
if (previous == null)
{
Console.WriteLine("Can't find 'Previous Locations' button.");
return;
}
// push "Previous Locations" button
var previousButton = (IUIAutomationInvokePattern)previous.GetCurrentPattern(UIA_PatternIds.UIA_InvokePatternId);
previousButton.Invoke();
// enter the directory path
var address = dialog.FindFirst(TreeScope.TreeScope_Subtree, _automation.CreateAndCondition(
_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_EditControlTypeId),
_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_NamePropertyId, "Address")));
if (address == null)
{
Console.WriteLine("Can't find 'Address' edit.");
return;
}
// sets the directory (here we use the temp directory)
var edit = (IUIAutomationValuePattern)address.GetCurrentPattern(UIA_PatternIds.UIA_ValuePatternId);
edit.SetValue(System.IO.Path.GetTempPath());
// push "Previous Locations" button again to "commit"
previousButton.Invoke();
// get the "File name:" edit
// do some retry to handle folder refresh
do
{
var fileName = dialog.FindFirst(TreeScope.TreeScope_Subtree, _automation.CreateAndCondition(
_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_EditControlTypeId),
_automation.CreatePropertyConditionEx(UIA_PropertyIds.UIA_NamePropertyId, "File name", PropertyConditionFlags.PropertyConditionFlags_MatchSubstring)));
if (fileName != null)
{
// sets the file name (some "random" name)
((IUIAutomationValuePattern)fileName.GetCurrentPattern(UIA_PatternIds.UIA_ValuePatternId)).SetValue(@"hello" + Environment.TickCount + ".txt");
break;
}
}
while (true);
// get the "Save" button
var dialogSave = dialog.FindFirst(TreeScope.TreeScope_Subtree, _automation.CreateAndCondition(
_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_ButtonControlTypeId),
_automation.CreatePropertyCondition(UIA_PropertyIds.UIA_NamePropertyId, "Save")));
if (dialogSave == null)
{
Console.WriteLine("Can't find 'Save' button.");
return;
}
// press the 'Save' button
((IUIAutomationInvokePattern)dialogSave.GetCurrentPattern(UIA_PatternIds.UIA_InvokePatternId)).Invoke();
}));
// start notepad
var process = Process.Start("notepad");
processId = process.Id;
Console.WriteLine("Press any key to quit...");
Console.ReadKey(false);
try
{
process.CloseMainWindow();
}
catch
{
// maybe closed by something else, do nothing
}
}
// helper class
class AutomationEventHandler : IUIAutomationEventHandler
{
public AutomationEventHandler(Action<IUIAutomationElement, int> action)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
Action = action;
}
public Action<IUIAutomationElement, int> Action { get; }
public void HandleAutomationEvent(IUIAutomationElement sender, int eventId) => Action(sender, eventId);
}
}