Send text to "save as" dialog - c#

I have winapi c# to save webpage as pdf. Application uses control + P on webpage and hit enter. My default printer is "nuance pdf" and I want to save the file as pdf. My code looks as below:
static class Program
{
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam);
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[STAThread]
static void Main()
{
Boolean Check = true;
string text = "MyFileName";
while (Check)
{
Process[] processes = Process.GetProcessesByName("iexplore");
foreach (Process proc in processes)
{
SetForegroundWindow(proc.MainWindowHandle);
SendKeys.SendWait("^(p)");
SendKeys.SendWait("{ENTER}");
var handle = FindWindow(null, "Save As");
Console.WriteLine("handle {0}", handle);
//SendMessage(handle, 0x000C, IntPtr.Zero, text);
SendKeys.SendWait("{ENTER}");
}
Check = false;
}
}
}
This code saves the file name as "https___www.google.pdf". I would like to change the file name (highlighted).
How do I do that? Any pointers?
Thanks for helping out.

Given your current approach, and given that the text is highlighted by default, why not just send keys with the file name you want?
var handle = FindWindow(null, "Save As");
Console.WriteLine("handle {0}", handle);
SendKeys.SendWait(text);
SendKeys.SendWait("{ENTER}");
You may need to highlight the text first. Which could be a double click, or access the control directly, e.g. var filename = FindEdit(handle, "File Name:") to access it in case it's not highlighted by default.

Related

C# Capture Microsoft Print to PDF dialog

I would like to capture and suppress the Savefiledialog that is shown when using the Microsoft Print to PDF driver from an application that is not office. Then programmatically enter the file path, possibly with System.Windows.Automation.
I can’t seem to find a handle to the SaveFileDialog when its displayed. I believe I could handle the Windows.Automation part.
I would like to use the Microsoft driver, since it is shipped with all windows 10.
Are there other ways to capture/suppress this dialog? I currently do this with another pdf driver on my local machine through the registry. But I would like to move to the Microsoft PDF since it is standard.
The Thread:
How to programmatically print to PDF file without prompting for filename in C# using the Microsoft Print To PDF printer that comes with Windows 10 -Does not solve my problem, and prints a blank page when run from the Revit API. Autodesk Revit has to initiate the printing (and is done through its api).
Code for trying to find the dialog from user32.dll
public static List<IntPtr>GetChildWindows( IntPtr parent) {
List<IntPtr>result=new List<IntPtr>();
GCHandle listHandle=GCHandle.Alloc(result);
try {
EnumWindowProc childProc=new EnumWindowProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally {
if (listHandle.IsAllocated) listHandle.Free();
}
return result;
}
public static string GetText(IntPtr hWnd) {
int length=GetWindowTextLength(hWnd);
StringBuilder sb=new StringBuilder(length + 1);
GetWindowText(hWnd, sb, sb.Capacity);
return sb.ToString();
}
private void Test() {
Process[] revits=Process.GetProcessesByName( "Revit");
List<IntPtr>children=GetChildWindows( revits[0].MainWindowHandle);
var names=new List<string>();
foreach (var child in children) {
names.Add(GetText(child));
}
}
I ran a few tests on my own system and it appears that enumerating the top level windows will find the Save file dialog. I tried with printing to the MS PDF printer from multiple programs and the results were all the same. Below is some code adapted from the MS Docs window enumeration example. I added in the code to get the process ID so you can check to be sure it is your window.
// P/Invoke declarations
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);
Console.WriteLine($"Found it! ProcID: {procId}");
}
}
return true;
}
void Main()
{
EnumWindows(new EnumWindowsProc(EnumTheWindows), IntPtr.Zero);
}

Capture events from other windows applications

I have a third party application which I did not create myself. I need to create an application which is able to listen for button clicks and read data from tables in that application. I believe that the third party application is made in C# but I do not know for sure. Is there a way to know when UI buttons are pressed and to harvest data from the application? I do not mind which programming language the solution must be written in, as long as it fulfils the above tasks.
You can use few dlls like user32.dll, to get data from other apps.
Find parent handle of a window:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public static IntPtr FindWindow(string windowName)
{
var hWnd = FindWindow(windowName, null);
return hWnd;
}
After that, find handle of a child window
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
private IntPtr FindSomeElement(IntPtr parent)
{
IntPtr childHandle;
childHandle = FindWindowEx(
parent,
IntPtr.Zero,
"WindowsForms10.EDIT.app21",
IntPtr.Zero);
return childHandle;}
and get text from it:
private static string GetText(IntPtr childHandle)
{
const uint WM_GETTEXTLENGTH = 0x000E;
const uint WM_GETTEXT = 0x000D;
var length = (int)SendMessage(handle, WM_GETTEXTLENGTH, IntPtr.Zero, null);
var sb = new StringBuilder(length + 1);
SendMessage(handle, WM_GETTEXT, (IntPtr)sb.Capacity, sb);
return sb.ToString();
}
//I didnt test this code, just gave an idea.
Visit www.pinvoke.net/default.aspx/ for more information. You can find alot about user32.dll

Notepad - force to show save dialog when content provided by SendMessage pinvoke

I have simple helper method which allows me to open notepad.exe and fill it by provided text.
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", EntryPoint = "SendMessageW")]
public static extern IntPtr SendMessageW(IntPtr hWnd, UInt32 msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
public static void OpenNotepadWithText(string text)
{
var process = Process.Start("notepad.exe");
if (process == null)
throw new Exception("Unable to run notepad.exe process!");
process.WaitForInputIdle();
IntPtr child = FindWindowEx(process.MainWindowHandle, new IntPtr(0), "Edit", null);
SendMessageW(child, 0x000C, IntPtr.Zero, text);
}
When I click on close button of notepad, notepad is closed without asking for save. It seems that used approach does not set "need_to_save" flag in notepad and thus notepad thinks that there is no changed content to save. Can someone help me with setting this flag?

Alt+F,S not working in sendKeys C#

I want to save and close all kinds of application which is opened. The specific application is identified from Process command. with this I can kill it.
For saving I tried SendKeys class, First I set the SetForegroundWindow(h), and succeeded with ctrl+s by using
SendKeys.Send("^s"); //Ctrl+s
but, user defined applications are there, and also I have a situation to save a new(not existing file) which has to be saved by Alt+F+S.
So that it saves with default name
How do I achieve this,
I tried,
SendKeys.Send("%(fs)");
SendKeys.Send("%f"+"s"); //Alt+F
SendKeys.Send("%f" + "%s)"); //Alt+F
SendKeys.Send("%fs");
Please guide me, If its not possible with SendKeys, what else should I try.
Always use the breakets and you can avoid errors.
SendKeys.Send("%{f}"); //Alt+F
SendKeys.Send("{A}"); //A
or try
SendKeys.Send("%{f}{A}"); //Alt+F And A
What APP? SendKeys will send key strokes but under the hood most things use the good old message loop.
SendMessage(hWnd, WM_SETTEXT, wParam, lParam);
c#
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, String lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
static extern uint RegisterWindowMessage(string lpString);
IntPtr hwnd= FindWindow(null, "Window Title");
SendMessage(hwnd, id, IntPtr.Zero, IntPtr.Zero);
To get notepad to save it would be
const int WM_COMMAND = 0x111;
SendMessage(hwnd, WM_COMMAND,777 , NULL);

Sending keystrokes to a program

In window form, I made a button and I'm trying to make it send F1 to a specific window (Such as FireFox, My Computer, etc...)
My questions are :
How do I do it by the window's name? (such as "Mozilla Firefox")
How do I do it by the process's name? (such as firefox.exe)
By Window name:
[DllImport("User32.dll")]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("User32.dll")]
static extern int SetForegroundWindow(IntPtr hWnd);
IntPtr ptrFF = FindWindow(null, "Mozilla Firefox");
SetForegroundWindow(ptrFF);
SendKeys.SendWait("{F1}");
By Process name:
Process proc = Process.GetProcessesByName("firefox")[0];
IntPtr ptrFF = proc.Handle;
SetForegroundWindow(ptrFF);
SendKeys.SendWait("{F1}");
Take a look into the SendKeys class.

Categories