Waitforinputidle Doesn't Work for Starting Mspaint Programmatically

WaitForInputIdle doesn't work for starting mspaint programmatically

WaitForInputIdle works, but not the way you assume it does. This is largely, because the documentation is misleading (or at least not as explicit as it should be):

Waits until the specified process has finished processing its initial input and is waiting for user input with no input pending, or until the time-out interval has elapsed.

This is almost criminally inaccurate. While the Remarks section notes, that WaitForInputIdle waits at most once per process, it never mentions significant details. Specifically:

  • WaitForInputIdle returns, as soon as the initial startup has come to a point, where any thread in the process is ready to process messages. Those messages need not be user input.
  • WaitForInputIdle was invented to allow a process to communicate with a child process using a message-based protocol. The specific scenario addressed was DDE, which no one1) uses anymore.

WaitForInputIdle cannot be used as a reliable solution to your problem: Waiting for a child process' UI to show up. You really need to wait for the UI show up.

The system offers two solutions you can use:

  1. A global CBT hook, and wait for the HCBT_CREATEWND callback. You can inspect the CREATESTRUCT's lpszClass and/or lpszName members to filter out the window you are interested in.
  2. Use WinEvents and respond to the EVENT_OBJECT_CREATE event.

The global CBT hook is called, whenever a window is about to be created. The kernel structures that the HWND references have been fully populated, but the client calling CreateWindow[Ex] may still terminate window creation. In contrast, the WinEvent is issued, after the window has been fully constructed, and is ready for interaction.

In general, a solution based on a CBT hook is used, when an application needs to update certain aspects of a window before the caller of CreateWindowEx gets to see the HWND for the first time. WinEvents, instead, are usually the tool of choice when implementing accessibility or UI automation solutions.



Additional resources:

  • WaitForInputIdle should really be called WaitForProcessStartupComplete
  • WaitForInputIdle waits for any thread, which might not be the thread you care about



1) Yes, I know, some applications might still use DDE. But if Raymond Chen suggested in 2007, that we should feel free to stop using DDE, I'll just pass that on as authoritative guidance.

How to determine when spawned process is ready? (Using CreateProcess() and FindWindow())

(Edit): User IInspectable pointed out problems with WaitForInputIdle(), and suggested CBT Hooks instead.

(...) callback function used with the SetWindowsHookEx
function. The system calls this function before activating,
creating, (...) a window; (... many other things).

Also, CBT is short for computer-based training, for whatever reason.

(Old, beware, see comments.) You are looking for WaitForInputIdle(). Quote:

When a parent process creates a child
process, the CreateProcess function
returns without waiting for the child
process to finish its initialization.
Before trying to communicate with the
child process, the parent process can
use the WaitForInputIdle function to
determine when the child's
initialization has been completed.

Process.Start with UseShellExecute fails to bring notepad.exe window to the foreground after a previous close window

After working on this problem for another few days and trying out various solution attempts, I still cannot explain why the original problem occurred (failing to bring notepad to the front after closing it with a different app).

However, over time my code grew in size as I checked every Win32 error code after every Win32 operation and retried by looping and trying again as necessary or appropriate.

I conclude that checking every Win32 error code on every operation and retrying failed operations every 100 milliseconds caught some failed operations, but did not solve the original problem.

How can I set the window text of an application using .NET Process.Start()?

Somwhere in your code:

[DllImport("user32.dll")]
static extern IntPtr FindWindow(string windowClass, string windowName);

[DllImport("user32.dll")]
static extern bool SetWindowText(IntPtr hWnd, string text);

public void startProcess(string path, string title) {
Process.Start(path);
Thread.Sleep(1000); //Wait, the new programm must be full loaded
IntPtr handle = FindWindow("ConsoleWindowClass", path); //get the Handle of the
//console window
SetWindowText(handle, title); //sets the caption
}

Update by Pure Krome

Instead of looking for the handle, the process already has that info... So i did this (because my program i was starting was a console app, if that has anything to do with this ... )

..... snipped .....
var process = Process.Start(path);
Thread.Sleep(1000); // Wait for the new program to start.
SetWindowText(process.MainWindowHandle, title);

HTH.



Related Topics



Leave a reply



Submit