System.Diagnostics.Process.Start() strange behaviour
Asked Answered
K

2

7

I have an application that uses Process.Start(string Filename) to open up a file. This method overload will cause the system to invoke the appropriate application based on the filename extension. In my case, it will typically be a WORD, PPT, PDF, JPG etc... Some type of viewable document. Ultimately, I need to launch the process and then later in the application I need to do something with the MainWindowHandle value.

I've found at least three different cases that cause Process.Start(string filename) to return different ways...

For the first and second cases below, assume I'm opening up two .pdf files (but the same thing appears to happen if I was opening two .ppt or two .doc files as well)...

Case 1: If AcroRd32 isn't running and I do something like..

Process p = Process.Start("yada.pdf");
p.WaitForInputIdle();
p.Refresh();

things work as expected. The value p.MainWindowHandle is populated correctly. No problem with this case.

Case 2: Now assume at the time of the call to Process.Start() AcroRd32 is already running on a previously opened pdf file. Now things get weird. Referring to the code below (some error-checking logic removed for clarity), after the call to Process.Start() the value of p.MainWindowHandle is zero (even though the window is created), and p.MainWindowTitle is empty. Then I sleep for 1 second and the handle is still zero, but the mainwindowtitle is now populated (even though I did NOT call p.Referesh() after the sleep. Each of the trace statements that have "<<<<" in the comments are printed at runtime.

Process p = Process.Start("SomeFileName.pdf");
p.WaitForInputIdle();
p.Refresh();
if (p.MainWindowHandle == 0)
    DebugTrace("MainWindowHandle is zero, why??");   //<<<<
if (p.MainWindowTitle.Length == 0)
    DebugTrace("MainWindowTitle is null");           //<<<<
Thread.Sleep(1000);
if (p.MainWindowHandle == 0)
    DebugTrace("MainWindowHandle is still zero.");   //<<<<
if (p.MainWindowTitle.Length == 0)
    DebugTrace("MainWindowTitle is null");
else
    DebugTrace("MainWindowTitle: " + p.MainWindowTitle);  //<<<<

I'm sure this has something to do with the fact that AcroRd32 is already running, but I have no control over that and I do need to get the value of p.MainWindowHandle. Any ideas how to handle this?

Case 3: Then onto the third case: in some cases, Process.Start() will return null even when it successfully opens the file. I found this to be the case with .jpg files, but I'm sure that just depends on the application that has been assigned to the .jpg extension. The Process.Start("file.jpg") returns null if the application is "Windows Photo Viewer" but if I change that to be "Paint" it doesn't return null. What's up with that? And how can I get the handle then?

Ok, all done, sorry for the detail, but hopefully I'm explaining the situation(s) I'm trying to work through!

Karakorum answered 1/6, 2012 at 14:54 Comment(2)
Out of curiosity, what is it that you need to do with the MainWindowHandle? Maybe there's a better way!Hipparchus
I need to keep track of the location/size of the window and I am currently using GetWindowRect() which takes the window handle as input. Because of the limitations Process.Start() I also have to "guess" at what the active window is based on knowing the filename and at times knowing the processname. Ideally, I'd like to not have to guess! :-)Karakorum
N
2

I suspect that windows start a new process with acroRd32, which then passes along the given filepath to the running instance and then shuts down.

This is how it is usually done for avoiding multiple instance of a program...

Nealon answered 1/6, 2012 at 15:4 Comment(5)
Understood, and I'm sure the same thing happens with powerpoint, word etc... The problem is that I need to get the window handle which appears to be unavailable in these cases with this code.Karakorum
Use GetProcesses to check if AcroRd32 exists and retrieve the main handle from there msdn.microsoft.com/en-us/library/…Nealon
Can't do that because I really don't know what process will be launched. I used acroRd32 as the example above, but it could be a word document, powerpoint, jpeg, whatever application is hooked to the file extension. One thing that isn't clear above is the fact that the string passed to Process.Start() is arbitrary.Karakorum
I assume that the process you get back from Process.Start() is filled in? Can't you search if the same process still exists on the system?Nealon
That's what I currently do (not metioned for the sake of brevity above because I was hoping there was a more elegant way to do this). If Process.Start() returns a process whose MainWindowHandle member is zero, I use the ProcessName member (which does seem to be consistently available in the case) along with the filename to parse through the results of EnumWindows() to take an educated guess at what the actual window is. Note taht this still doesn't address the case where Process.Start() returns null.Karakorum
G
0

You can't depend on MainWindowHandle that Process.Start returns. As you mentioned, it doesn't return it when the file gets opened by an alreadly running application. Since Windows Vista, MS added ReStart Manager, a new api that can give your locking processes on a given file. https://msdn.microsoft.com/en-us/magazine/cc163450.aspx

My approact to the problem was to try Process.Start's MainWindowHandle and the locking handle ReStart manager returns. There's an example code from MSDN magazine. https://github.com/andrewchaa/PopOpen/blob/master/Pop.Cs/InUseDetection.cs

Gabler answered 4/4, 2015 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.