In order to determine whether or not the application to automate is ready to accept user input (key strokes) you have to search for the window of the application processing the key strokes you will send. There is quite a bit interop necessary to accomplish the task. Below you will find a small example automating the task of printing an excel document (all error handling details omitted).
I've copied the interop signatures from pinvoke.net.
First, let me describe the necessary steps:
- Search for the excel main window using the class name of the excel main window. Use a tool like spy++ to determine the class name.
- Bring the excel main window to the foreground.
- Send CTRL+C to the main window to open the print dialog.
- Wait for the print dialog to appear.
- Send ENTER to the print dialog.
Second, let me show you a small code example:
private enum WindowShowStyle : uint
{
Hide = 0,
ShowNormal = 1,
ShowMinimized = 2,
ShowMaximized = 3,
Maximize = 3,
ShowNormalNoActivate = 4,
Show = 5,
Minimize = 6,
ShowMinNoActivate = 7,
ShowNoActivate = 8,
Restore = 9,
ShowDefault = 10,
ForceMinimized = 11
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, WindowShowStyle nCmdShow);
[DllImport("user32.dll")]
private static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("kernel32.dll")]
private static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
private static void BringWindowToForeground(IntPtr hWnd)
{
uint foregroundThread, currentThread;
uint pid;
foregroundThread = GetWindowThreadProcessId(GetForegroundWindow(), out pid);
currentThread = GetCurrentThreadId();
if (foregroundThread != currentThread)
{
AttachThreadInput(foregroundThread, currentThread, true);
BringWindowToTop(hWnd);
ShowWindow(hWnd, WindowShowStyle.ShowMaximized);
AttachThreadInput(foregroundThread, currentThread, false);
}
else
{
BringWindowToTop(hWnd);
ShowWindow(hWnd, WindowShowStyle.ShowMaximized);
}
}
private void button1_Click(object sender, EventArgs e)
{
// Find excel window.
IntPtr hWnd;
while (true)
{
hWnd = FindWindow("XLMAIN", null); // XLMAIN is the class name
// of the main excel window.
if (hWnd != IntPtr.Zero)
break;
}
BringWindowToForeground(hWnd);
SendKeys.SendWait("^p"); // Send CTRL+P to main excel window
// Find print dialog.
while (true)
{
hWnd = FindWindow("bosa_sdm_XL9", null); // bosa_sdm_XL9 is the class name
// of the print dialog.
if (hWnd != IntPtr.Zero)
break;
}
BringWindowToForeground(hWnd);
SendKeys.SendWait("~"); // Send ENTER to print dialog.
}
The button_click
methods includes the steps to wait for the Excel windows to appear. If the specified window is found the keys are sent.
Hope, this helps.