I am trying to intercept the "Save Print Output As" dialog in Revit so I can programmatically insert a path and file name. This dialog pops up every time for every view or sheet that is printed when printed separately or only once if a combined document is printed once.
So far, I have assembled the viewset however when it comes time to print, I do not have access to the window because it opens and closes too soon. I am hoping there is a more "hacky" way to intercept it.
In Revit, the event handler:
a.ControlledApplication.DocumentPrinting += new EventHandler<Autodesk.Revit.DB.Events.DocumentPrintingEventArgs>(AppDocumentPrinting);
only activates after the name/destination has been selected but before the document has printed so it doesnt quite help.
I have found this post which explains how to cycle through the windows which I am able to do but I don't know how to listen for the window to be opened and I can't find anything on it. The SO post also mentions something about p/invoke but I haven't found much documentation on it.
I have looked at subscribing to events but I haven't found anything on being able to subscribe to listen to a window opening.
My printer setup is currently Microsoft print to pdf which doesn't seem to allow the PrintToFile
option. Regardless though, I would still like to be able to handle the dialog if it pops up if it is possible.
Any and all help/direction is appreciated.
My code:
EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero); // cant find window because it doesnt exist
printManager.SubmitPrint(); // Window opens for user input here and then closes
// doc.Print(pdfviewSet); // option B: Window opens for user input here and then closes
EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero); // cant find window because it doesnt exist
code adapted from other SO post
// P/Invoke declarations <--- suspect the answer might lie here?
protected delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowText(IntPtr hWnd, StringBuilder strText, int maxCount);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
protected static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll")]
protected static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
protected static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
// Callback for examining the window
protected static bool EnumTheWindows(IntPtr hWnd, IntPtr lParam)
{
int size = GetWindowTextLength(hWnd);
if (size++ > 0 && IsWindowVisible(hWnd))
{
StringBuilder sb = new StringBuilder(size);
GetWindowText(hWnd, sb, size);
if (sb.ToString().Equals("Save Print Output As", StringComparison.Ordinal))
{
uint procId = 0;
GetWindowThreadProcessId(hWnd, out procId);
Debug.WriteLine($"Found it! ProcID: {procId}");
FlaUI.Core.Application application = FlaUI.Core.Application.Attach(Process.GetCurrentProcess());
string appName = application.Name;
Window mainWindow = application.GetMainWindow(new UIA3Automation());
ConditionFactory cf = new ConditionFactory(new UIA3PropertyLibrary());
mainWindow.FindFirstDescendant(cf.ByProcessId(int.Parse(procId.ToString()))).AsTextBox().Enter("test"); // try to enter info here but returns null because window has closed.
}
}
return true;
}
Dialog I am trying to intercept:
Other info I have looked at: p/invoke - not too sure how to implement this.