Process.Start gives wrong IDs on multiple window programs - c#

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?

Related

C# Paste Data into ExternalProcess

I am writing a launcher in C# that processes user input and I would like its corresponding output string to be piped into an external program. The external program is a precompiled C# executable that is end-of-life, so I cannot easily modify it.
I can easily launch the desired program using ExternalProcess, but do not see any means for sending data over. My desired function calls go something like:
string myString = "string to pass over"
Clipboard.SetText(myString);
Process ExternalProcess = new Process();
ExternalProcess.StartInfo.FileName = "Notepad.exe";
ExternalProcess.Start();
// some kind of paste command here...
// ExternalProcess.magicpaste(myString);
ExternalProcess.WaitForExit();
Is there a better way to go about this? I realize the purported security implication in piping text this way, but I need to create a simple launcher program to support a legacy project.
Given your answer in the comments that you need to put some text in a field, I'm afraid you're going to have to get your hands dirty.
That text box (I assume that's what it is) in this legacy application, will be a window. And you're going to have to find it, and send it a message using Platform-Invoke. This question should get you started.
If said control has a name, you can find it using Spy++.

How to always run new instance of a process in C#?

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.

Find process id when Process.Start returns null?

If I try to open an image file, or video, or website by calling Process.Start(filepath) directly, then it will typically succeed. However, the return value of Process.Start will sometimes be null. (As discussed here)
I need to know the associated process's id so that I can retrieve it later and close it if necessary. (Use case: User opens an image file using my program, and would like to close it using my program) However, it's kind of hard to retrieve the process id of a process that returns null :P
Any suggestions on how I should go about this, other than maybe specifying directly which program to use for each type of file we may encounter?
You have to specify directly which program to use to get the id of the process. I can imagine you can ask the os what program to use for each extensions as the os has a list of those.

Tracking multiple processes at same time

I have an application (winforms) that downloads a file to user's temporary folder, then it opens the file for user to see contents, and when the file is closed, the file gets deleted from temp folder. The application is working ok if I open let's say one .pdf and one .doc The problem appears when trying to open one .doc if another winword process is still runing (doesn't matter if is opened by my app or directly by user).
I'm using the following code:
_OpenFileProces = System.Diagnostics.Process.Start(TempFileName);
_OpenFileProces.EnableRaisingEvents = true;
_OpenFileProces.Exited += new EventHandler(_OpenFileProces_Exited);
and this one to clear temp
void _OpenFileProces_Exited(object sender, EventArgs e)
{
string s = ((System.Diagnostics.Process)sender).StartInfo.FileName;
System.IO.File.Delete(s);
}
It seems that the running process is stopping my own.. and due to stopping it will delete the file or it will generate an error while trying to delete the file.
Do you have any suggestion how can I open my own process? The thing is I do not know what file type I have to open (it could be anything) and I'm counting on windows to choose the best application. from my test, notepad works ok, but winword and acrobat closes my process.
Thank you
I suspect that Microsoft Word is doing exactly the same thing here as Raymond Chen describes the Windows Shell as doing here:
A customer wanted help with monitoring the lifetime of an Explorer window.
"We want to launch a copy of Explorer to open a specific folder, then wait until the user closes the folder before continuing. We tried launching a copy of Explorer with the folder on the command line, then doing a Wait­For­Single­Object on the process handle, but the wait sometimes completes immediately without waiting. How do we wait until the user closes the Explorer window?"
This is another case of solving a problem halfway and then having trouble with the other half.
The reason that Wait­For­Single­Object returns immediately is that Explorer is a single-instance program (well, limited-instance). When you open an Explorer window, the request is handed off to a running copy of Explorer, and the copy of Explorer you launched exits. That's why your Wait­For­Single­Object returns immediately.
In your case, Word is already running, so when you create a second Word process and instruct it to open your document, it simply hands the request off to the instance of Word that is already running, and quits the second process you launched immediately.
That's what you're seeing when you describe that "the running process is stopping my own". Because that second instance gets closed immediately after you launch it, the Exited event is raised and your code tells it to delete the file!
You astutely observe that Notepad (unlike Word and Adobe Acrobat) works just fine. That's because Notepad is designed to be a multiple-instance application. You can open as many copies of Notepad as you want; it doesn't care if there's already 1 or 6 copies open on the desktop. And more importantly, asking the shell to open a text document in Notepad actually opens a second copy of the Notepad application, rather than sending a request to the first instance to open a new window for the new doc.
You should set the Process.StartInfo.UseShellExecute to true like this _OpenFileProces.StartInfo.UseShellExecute = true; before starting the process and then it should work I think...

Kill process started with System.Diagnostic.Process.Start("FileName")

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.

Categories

Resources