Based on this https://msdn.microsoft.com/en-us/library/53ezey2s(v=vs.110).aspx
Process.Start() is not useful.
Start may return a non-null Process with its HasExited property
already set to true. In this case, the started process may have
activated an existing instance of itself and then exited.
In my case, I want to launch a default editor for a xml in new instance so that i can use Process.HasExited property to take action on my WPF app. All i see is native samples or way complicated than thought. What is the best solution ?
Process process = Process.Start(MyFileXMlPath);
//Wait for the Editor to be closed.
if (process != null)
while (!process.HasExited) ;
This is what i have now. So that i uses the user's preferred editor.
What's going on is expected behavior- the editor is being asked to open a file, and it is opening that file in an existing running process. One solution might be to use Process.GetProcesses to get all of the running processes on the box and iterate over them to find the new one, but that's likely problematic, because there is really no good way to tell which one opened the file.
What you probably want to do is to set UseShellExecute to false, run the editor you want explicitly (e.g. #"c:\Windows\notepad.exe") and pass the file name as a parameter, which is usually the convention to open a file. Obviously you'd want to pick an editor that doesn't invoke an existing instance.
Related
From MSDN:
The return value true indicates that a new process resource was
started. If the process resource specified by the FileName member of
the StartInfo property is already running on the computer, no
additional process resource is started. Instead, the running process
resource is reused and false is returned.
Trying something like this:
var info = new ProcessStartInfo {FileName = #"CMD"};
var p1 = new Process
{
StartInfo = info
};
var result = p1.Start(); //true
result = p1.Start(); //true
var p2 = new Process
{
StartInfo = info
};
result = p2.Start(); //true
Have the same result if I'm using FilePath = #"c:\myapp.exe" instead of CMD.
In what cases does it return false?
If you take a look at the reference source, you'll see how Process.Start works:
http://referencesource.microsoft.com/System/R/c50d8ac0eb7bc0d6.html
That is one of two methods called when you call Process.Start. Notice near the bottom where it returns the value true or false. False is only returned if, after starting the process, it cannot obtain the handle for the process that was started.
In order to start the process, it uses NativeMethods.CreateProcess which you can find the source of here: http://referencesource.microsoft.com/System/compmod/microsoft/win32/NativeMethods.cs.html#9c52a5ca5f3eeea3
Which is just the method prototype for Kernel32.CreateProcess, which the API is found here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
If you look at the return values, it says:
If the function succeeds, the return value is nonzero.
If the function fails, the return value is zero.
I can't find anything in the API for CreateProcess that says it fails if the requested process is already running, perhaps if the process failed to start because it is a single instance application (like Outlook) then it may fail, but for multiple instance applications like the command prompt, it shouldn't fail to create a handle to the process.
So, after saying all that, it is possible that the MSDN documentation is not entirely correct, I don't have the link you have, but for the Process.Start(StartInfo), MSDN says this about the return value:
A new Process that is associated with the process resource, or null if no process resource is started. Note that a new process that’s started alongside already running instances of the same process will be independent from the others. In addition, Start may return a non-null Process with its HasExited property already set to true. In this case, the started process may have activated an existing instance of itself and then exited.
(Emphasis added by me). It doesn't say the call will fail if its already running.
For Process.Start(), it says:
Return Value
Type: System.Boolean
true if a process resource is started; false if no new process resource is started (for example, if an existing process is reused).
So it says if an existing process is reused, this is entirely up to the application being started or the method of starting it.
You can technically get a false return when you use ProcessStartInfo.UseShellExecute = true (the default) and you launch the process by passing a document filename. And the shell is somehow able to figure out to pass the document open request to an already running instance of the process.
The only documented case of this is opening a web page in Internet Explorer. There might be other ones, probably having something to do with legacy DDE activation. That's a guess.
This is otherwise a specific case of a general problem with Process.Start(), there are lots of single-instance apps around. The Office apps as the most common example. The most typical behavior you'd observe is that the process very quickly terminates again. It just detected that the app was already running and used process-interop to ask the running instance to open the document. The kind of feature also supported in .NET.
You'll have no idea which specific process is showing the document unless you know it is a single-instance app and its process name so you have some hope of finding it back with Process.GetProcessesByName(). This is however not fail-safe, there might be an unrelated process running that happens to have the same name. Advantage of getting false is that you know there's no point in waiting for it to terminate.
How can i check if another instance is running ?
Also if it is running how can I force my already opened instance to open a file ?
Also if it is possible can I force it to get focus? ( I need this seperate)
How can i check if another instance is running ?
You could use Process.GetProcesses() to get a list of processes which are running on your machine. And simply do your compare with Process.Name. With rather simple name, you may need additional check for your application.
Also if it is running how can I force my already opened instance to
open a file ?
If you want to communicate between 2 processes, I would recommend SendMessage method. See here.
Also if it is possible can I force it to get focus? ( I need this
seperate)
You could use SetForgoundWindow method (also require P/Invoke). See here.
To be honest, I can't say I actually know where to begin with this question. So, I'll start from the beginning.
I have C# code that invokes Process.Start based on a OFD box. Basically allowing the user to open anything from the box, this is absolutely intended.
System.Diagnostics.ProcessStartInfo starter = new System.Diagnostics.ProcessStartInfo(OFPbasicfile.FileName);
starter.UseShellExecute = true;
System.Diagnostics.Process alpha = new System.Diagnostics.Process();
alpha = System.Diagnostics.Process.Start(starter);
Now, it perfectly executes and opens, but I've noticed something of an odd duck. If the first file opens say a .docx file I can then read alpha.ID just fine. However, the next time it opens a .docx file alpha.ID will be assigned a new process ID that corresponds to nothing in the task list. Worse yet, I get absolutely no useful information from alpha as it now has a handler to a non-existent process.
Near as I can figure this is probably something to do with the fact that the program doesn't realize everything perfectly. It tries to create a new process and reserves the ID for it, but then the running instance of word, etc. takes ownership of the started file and my program never gets advised of this change.
Ideally I was trying to find a way to track any and every file opened (process ID, window handles, however worked), but now I'd be more than happy if alpha would just recognize that the process is opened by Word (Or Excel, or what have you).
The basic question boils down to this: When using Process.Start is there any way to ensure it gives the proper process ID (or just the program used to open it) every time?
Or, alternatively: Is there any way to set a process variable with a reference to the exact window it opened?
If I connect to a running process by extracting it using Process.GetProcessesByName("Notepad");, is it possible to reconstruct that process´s ProcessStartInfo?
I would for example want to be able to attach to Notepad, Kill it and Start it again. Without a valid ProcessStartInfo the Start call will fail.
There is no direct support for this.
You can go over each property of the running process and initialize a ProcessStartInfo object with the corresponding values.
No, there are cases where that's not possible. A simple example is:
Process.Start("example.lnk");
No way to find out later that a .lnk file was used to get the process started.
The WorkingDirectory is a tricky one, a process often requires it to be set correctly but might change it later. A process that got started with a different user account is insurmountable, no way you can provide the correct account password. A custom environment is yet another one.
I am trying to create an app that will perform actions on specific times (much like the Windows Task Scheduler). I am currently using Process.Start() to launch the file (or exe) required by the task.
I am initiating a process by calling a file (an .mp3) and the process starts WMP (since it is the default application). So far so good. Now I want to kill that process. I know that it is normal behavior for the Process.Start(string, string) to return nothing (null in C#) in this case.
So I am asking how can I close WMP when I called it through Process.Start(string, string)??
Edit:
Please note that I am not opening WMP directly with Process.Start() and this is the line with which I run the process:
VB: Me._procs.Add(Process.Start(Me._procInfo))
C#: this._procs.Add(Process.Start(this._procInfo))
_procInfo is a ProcessStartInfo instance. _procInfo.FileName is "C:\route\myFile.mp3". That is why WMP opens. In any case, all of the Start() methods, except for the instance-one which returns a boolean, return nothing (null in C#), because WMP is not the process that was directly created (please note that WMP is run and the song does play).
Process.Start(string,string) returns you a Process resource that you can use to further control the new process.
Process newProcess = Process.Start("param1", "param2");
if (newProcess != null && !newProcess.HasExited)
newProcess.Kill();
The same structure works if you use Process.Start(string), or any other static Process.Start overload.
Process.Start() is a member function and associates a new or reused Process with the Process component identified by this. Behaviour of this method depends on the properties of the Process identified by this.
Don't do it this way.
It's not clear whether the intent of your program is 'Always launch with Windows Media Player' or 'Launch with the registered MP3 player', which might be, say, iTunes.
If you need WMP, use Process.Start with the full path to windows media player.
If you need the registed MP3 player, you can find out the correct exe using the code shown here. Again, start the process with this exe path, passing the MP3 as a parameter.
Two ways:
1-
Process customProc = Process.Start("ExecutablePath", "Argument(s)");
customProc.Kill()
2-
Dim pProcess() As Process = System.Diagnostics.Process.GetProcessesByName("ProcessName")
For Each p As Process In pProcess
p.Kill()
Next
If you are letting the registered windows program to open the file, rather than picking the program you want. Then I advise you do not kill the process.
The reason for this is what say your program does use the default application, but that application is already in use, and contains unsaved data. A user would not be happy for your program to overtake there application with the new file and then kill off the process that was already in use by the user for another purpose. Sure, it might not be in use but you must consider the worst case.
As such, I recommend what has been suggested. use Process.Start() with the full path to the program to be used and the file to be opened.
I tried to open .txt file and the process of my text editor was returned, also I tried .mp3 by WMP and it returned null. So it depends on the application. Do you need to run you mp3 only with WMP? If not, you definitely can create the application which will return the Process object.
proc = Process.Start(filename) should work, but like you say, it returns null instead of a process.
That seems to be inherent to Windows Media Player. Other applications return the process. You can get Windows Media Player's process by specifying the application in the start method.
proc = Process.Start("C:\Program Files\Windows Media Player\wmplayer.exe", filename)
Then you can kill it normally.
proc.Kill()
You will probably need to get the location of the application assiciated with .mp3 files from the registry.