IntPtr hwndMain = FindWindow("mspaint", null);
This is not enough. A common mistake in pinvoke code, C # programmers tend to rely too much on an exception to jump off the screen and hit them in the face to tell them that something went wrong .. The .NET Framework does this unusually well. But this does not work the same way when you use C based api, for example winapi. C is a dinosaur language and generally does not support exceptions. This is still not the case. You will only get an exception if pinvoke failed, usually due to a bad [DllImport] declaration or missing DLL. It does not say when the function completed successfully, but returns a failure return code.
This makes it completely your own job to detect and report a failure. Just go to the MSDN documentation , it always tells you how the winapi function indicates failure. Not fully consistent, so you need to search, in which case FindWindow returns null when the window cannot be found. Therefore, always code it like this:
IntPtr hwndMain = FindWindow("mspaint", null); if (hwndMain == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
Do this for all other pinwaxes. Now you can go ahead, you are reliably getting an exception, instead of plowing with bad data. Which, as is often the case with bad data, is not bad enough. NULL is actually a valid window handle; the operating system assumes that you meant the desktop window. Uch. You are automating a completely wrong process.
Understanding why FindWindow () fails requires a bit of understanding, this is not very intuitive, but good reporting of errors is critical to getting it. The Process.Start () method only ensures that the program is running, it in no way waits for the initialization process to complete. And in this case, he does not wait until he creates the main window. Thus, the call to FindWindow () is executed after about a couple of tens of milliseconds too soon. Itβs an urgent puzzle, as it works great when debugging and executing code once.
You may recognize this kind of failure; it is a mistake in the streaming race. The most vile kind of programming errors. Notorious for failing consistently and very difficult to debug, because races are time-dependent.
I hope you understand that the proposed solution in the accepted answer is also not enough. Arbitrarily adding Thread.Sleep (500) simply improves the odds you now expect long enough before calling FindWindow (). But how do you know that 500 is good enough? Is it always good?
No. Thread.Sleep () is never the right solution for streaming errors. If the user machine is slow or too busy with a lack of available raw RAM, then a few milliseconds turn into seconds. You have to deal with the worst case, and this is really the worst, only ~ 10 seconds - this is, in general, the minimum you need to consider when the car starts to beat. This is becoming very impractical.
Blocking this reliably is such a common need that the OS has a heuristic for it. You need to be heuristic and not call WaitOne () on the synchronization object, since the process itself does not interact at all. You can usually assume that the GUI program has progressed enough when it starts to request notifications. "Pumping up the message pipeline" on Windows. Heuristics also fell into the Process class. Fix:
private static void OpenPaint() { Process.process = new Process(); process.StartInfo.FileName = "mspaint.exe"; process.StartInfo.WindowStyle = "ProcessWindowStyle.Maximized; process.Start(); process.WaitForInputIdle(); // <=== NOTE: added }
I would refuse if I didnβt notice that for this you should use the built-in api. Called UI Automation, well wrapped in the System.Windows.Automation namespace. Takes into account all these unpleasant small details, such as slicing races and turning error codes into good exceptions. The most suitable tutorial is possible here .