updated
I have a problem related to Process.Start();
My program launches files as processes, like so:
Process processMonitor = new Process();
processMonitor.StartInfo.FileName = filePath; // Example: #"C:\test.txt"
processMonitor.StartInfo.CreateNoWindow = true;
processMonitor.Exited += new EventHandler(Process_Exited);
processMonitor.EnableRaisingEvents = true;
processMonitor.Start();
// Handle Exited event and display process information.
private void Process_Exited(object sender, EventArgs e)
{
// This code is called on every exit, except images: (Windows Photo Viewer, *jpg, *png, *bmp etc.)
}
This successfully launches a process, notepad.exe with the correct file.
Catching the Exited event also works so basically i have everything in place to monitor the close event for the process.
Now for the problem...
When doing exactly the same, but now for an image:
processMonitor.StartInfo.FileName = filePath; // Example: #"C:\test.jpg"
This is not successfull.. The process launches perfectly, But i can not detect if the process is ever closed. A little research shows me that a process called:
DLLHOST.EXE (COM Surrogate)
Is launched and i cannot detect the Exited event for this process.
Can anybody help me, or at least point me in the right direction?
If all other doesn't work, you can look into WMI: http://msdn.microsoft.com/en-us/library/aa394582(v=vs.85).aspx - this will require you to do some wrapping work (or use a wrapper, like the one here: http://www.codeproject.com/Articles/21971/WMI-Interface-for-NET)
Another option you can use as last resort and as a workaround only is polling for the process state, but this is really not recommended for most project, and it certainly doesn't sound like something you want to do in your project.
I think it has to do with the nature of an image. Opening a .txt file launches notepad whereas opening a .jpg opens a viewer. Any way to key into the viewer itself?
Related
i have this C# code (WPF app, but it probably doesnt matter):
void StartEditing(string projectPath) {
InitializeProject(projectPath);
Process process = Process.Start(new ProcessStartInfo(#"path\to\Code.exe", projectPath));
if (!process.HasExited) {
process.Exited += (sender, args) => { CleanupProject(projectPath); }
process.EnableRaisingEvents = true;
}
}
Basically i wanna to do some initialization before vscode starts and then do some cleanup after it exits (start/stop synchronization of changes with remote storage using FileSystemWatcher).
My code works only when there is no Code.exe process already running at time of call Process.Start method.
When there is already another Code.exe process (from different project), then my process exits immediately but vscode window is still opened afterwards (guessing vscode detects previous instance and pass its arguments to it before exiting)
So my question is: How to detect, that vscode opened at projectPath was closed?
PS: on my machine opening folder in vscode spawns 13 Code.exe processes and opening second one spawns additional 3.
In the top of Form1 i did:
private Process zipFileDirectoryProcess;
In the constructor i did:
zipFileDirectoryProcess = new Process();
zipFileDirectoryProcess.StartInfo.FileName = "explorer.exe";
zipFileDirectoryProcess.StartInfo.CreateNoWindow = true;
zipFileDirectoryProcess.EnableRaisingEvents = true;
zipFileDirectoryProcess.Exited += new EventHandler(zipFileDirectoryProcess_Exited);
Then i have a method i call it from a button click event:
private void Compress()
{
zipFileDirectoryProcess.StartInfo.Arguments = zipFileDirectoryProcess.StartInfo.Arguments = "/select," + Path.GetFullPath(t);
zipFileDirectoryProcess.Start();
zipFileDirectoryProcess.WaitForExit();
this.TopMost = true;
}
And then in the bottom the Exited event:
private void zipFileDirectoryProcess_Exited(object sender, EventArgs e)
{
this.BeginInvoke(new MethodInvoker(delegate()
{
this.TopMost = false;
}));
}
What i wanted to do is only when i close the process window after started it in the method only if closed the window/process then do the Exited event.
The problem is that once the process started after 2-3 seconds its jumping automatic to the Exited event.
How can i fix it ? Tried examples cant figure out.
Tried to add this line:
zipFileDirectoryProcess.WaitForExit();
But no effect.
zipFileDirectoryProcess.StartInfo.FileName = "explorer.exe";
Trying to start Windows Explorer again when it is already running, and it is always running, will have a disappointing outcome. It is a "heavy" process and it intentionally tries the minimize the number of running copies. Otherwise known as a "single-instance app". There are lots like that, the Microsoft Office programs are single instance apps for example.
So what really happens is that explorer.exe actually starts up, but sees that another instance is already running. And uses process interop to ask that first instance to do the job that you asked it to do. Since you didn't ask it to do anything, you just get another window, displayed by the first instance. The one that you started immediately quits, it doesn't have anything else to do.
So, yes, you'll see that the Exited event fires without you doing anything. Accurately telling you that the explorer.exe process you started did in fact quit. Easy to see in the Taskmgr.exe Processes tab btw. Waiting for that window to be closed is never going to work, it is displayed by the original instance of explorer.exe.
This will just not work the way you hope it will work. What you are actually trying to do is not quite obvious but can be guessed at. Creating a ZIP archive is not difficult, there are excellent libraries available for C# to get the job done, no point in asking another program to do it for you. DotNetZip and SharpZipLib are very popular. It got finally added to .NET as well in version 4.5, Microsoft finally getting over the lost Stacker lawsuit, about time. If you really, really want another program to do it for you then use a console mode zipper like 7-zip.
To show output folder in windows explorer to the user, it's simply enough to do this:
Process.Start("explorer.exe", OutputDir);
My program is in win forms (c#). It should open an external program, do a printscreen of it's main window, and close it.
By using Process.Start() I can open the the program, but then all the focus is on it and my code is halted. Only when I close it myself my form continues- but it's too late for the screenshot.
So how do I force my code to keep running?
public void Runttk(string maromnum)
{
Process runttk = new Process();
runttk.StartInfo.UseShellExecute = true;
runttk.StartInfo.FileName = #"C:\\program.exe";
runttk.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
runttk.Start();
this.Focus();
try
{
if (runttk.WaitForInputIdle()==true)
{
PringJpg(maromnum);
Killttk();
}
}
catch (Exception e)
{
}
}
Thank you
UPDATE:
eventuanlly I've used Thread.Sleep(3000). Crued but do the trick.
I didn't used backgroundworker because the sync between the finale uplaod the the extenral program and my code wasn't clear enough.
Trying your code, but with another program like notepad.exe, Notepad runs and then control drops through to where you call PringJpg.
So I think the problem is that it is blocking on if (runttk.WaitForInputIdle()==true), please try adding a timeout to this operation.
Maybe your programm is never idle - means that runttk.WaitForInputIdle()==true let your app wait until you close it.
Add a limit ( for example runttk.WaitForInputIdle(500)==true) should fulfill your needings.
After some poking around on how to reset my computer and or shut it down from C# I found this explanation on how to do that:
ManagementBaseObject outParameters = null;
ManagementClass sysOS = new ManagementClass("Win32_OperatingSystem");
sysOS.Get();
// Enables required security privilege.
sysOS.Scope.Options.EnablePrivileges = true;
// Get our in parameters
ManagementBaseObject inParameters = sysOS.GetMethodParameters("Win32Shutdown");
// Pass the flag of 0 = System Shutdown
inParameters["Flags"] = "1"; //shut down.
inParameters["Reserved"] = "0";
foreach (ManagementObject manObj in sysOS.GetInstances())
{
outParameters = manObj.InvokeMethod("Win32Shutdown", inParameters, null);
}
This worked in Windows 7, but not on the Windows XP box I tried it on. So I figured well lets go with a simpler solution:
Process.Start("shutdown", "/s /t 00");
Alas that as well seems to work on my windows 7 box, but not my Windows XP box. I have only tried it on one Windows XP machine, but it flashes up like a command prompt, my program that is up is minimized to the system tray and then nothing happens..so its like it wants to do something but ultimately nothing happens. (I do have code that purposely puts my program to the sys tray when the close X is hit, and the user has to purposely exit it... ) is there an issue with that? My FormClosing code is this:
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (!canExit)
{
e.Cancel = true;
this.WindowState = FormWindowState.Minimized;
}
else
{
// Write out the logs.
List<String> logs = LogUtil.getLog(); // mic.getLog();
// Create a writer and open the file
TextWriter tw = new StreamWriter(userAppData + "\\logTMC.txt", true);
// Write a line of text to the file
tw.WriteLine("----- " + DateTime.Now + " ------");
foreach (String log in logs)
{
tw.WriteLine(log);
}
// Close the stream
tw.Close();
}
}
I am not sure why I can reset, and shutdown my pc from C# in Windows 7, but not on Windows XP...maybe I missed something? An extra command? A better way to close out the log file I have open when the form closes? Some way to force a shutdown or reset no matter what, the Windows XP box I am using does indeed have an SVN server as a windows service running, but I am not sure if this makes a difference or not.
So I am not really sure where to investigate my problem. Does the Process.Start() have a way to see a return or a try catch to see what might of caused it not to shut down or is it a "fire and forget" type a deal?
You could use the ExitWindowsEx API via pinvoke.net.
See the ExitWindowsEx, ExitWindows-Enum and ShutdownReason-Enum on pinvoke.net for more information. Note that your process must have the SE_SHUTDOWN_NAME priviledge aquired (for example via AdjustTokenPrivileges API).
The answers to this stackoverflow question contain some "complete" examples (although most of them are missing errorchecking and resource cleanup - the latter might not matter when you successfully shutdown, YMMV).
Finally, note that using Process.Start() as you showed, without a fully qualified name to shutdown.exe is also problematic from a security standpoint. Someone could put a malicious EXE named shutdown in your PATH. Since you probably need to run with admin rights to be able to execute the "real" shutdown.exe, this can cause some trouble. If you specify something like Process.Start(Environment.ExpandEnvironmentVariables("%windir%\system32\shutdown.exe")) you can at least assume that the real shutdown.exe is protected from malicious replacement by file system rights (if the attacker himself is an admin your basically busted anyway).
I can't add comments yet, so have to post it as an answer.
There is an article on this site, showing several methods on shutting down the PC here: How to shut down the computer from C#
At a glance I noticed in the above link, for XP, Pop Catalin uses Process.Start("shutdown","/s /t 0");. I'm not sure if using 1 0 is going to make any difference.
I believe it's correct. You just have to change the command to:
shutdown.exe -s -t 00
It works on my Windows box (from cmd).
Okay, here's the deal...
I have a Windows (XP) program in .NET 2.0 (C#) which allows users to rename a given .pdf file. (The filename is "structurally descriptive", as it lays out simple info about what's in the file itself.) On the program's only form, there is a LinkLabel object which allows the user to open the .pdf itself, so that they can see what they are renaming.
The trick is that, when the user makes the appropriate change(s) and clicks the "Save" button, I want the Acrobat window showing the .pdf to close, the save performed, a "next" file to be retrieved, and a new window to immediately open displaying that next file.
Here's the relevant code snippets:
private void OpenViewer()
{
// NOTE: pdfView is of type Process, in case you're not familiar with
// Process.Start().
pdfView = System.Diagnostics.Process.Start(lnkFile.Links[0].LinkData.ToString());
}
private bool KillViewer()
{
bool result = (pdfView != null);
if (pdfView != null)
{
pdfView.CloseMainWindow();
pdfView.Close();
pdfView.Dispose();
pdfView = null;
GC.Collect();
// Verify that the lock is available before you return, as returning basically says:
// "Yup, the file's available."
bool locked = false;
StreamWriter sw = null;
do
{
try
{
sw = new StreamWriter(new FileStream(lnkFile.Links[0].LinkData.ToString(), FileMode.Open));
locked = false;
}
catch (Exception)
{
locked = true;
}
} while (locked);
sw.Dispose();
}
return result;
}
private void SomeButtonEvent
{
// Record whether a viewer was open in the first place.
bool viewerActive = KillViewer();
PerformFileLockingMethod();
GetNextFile()
if(viewerActive)
{
OpenViewer();
}
}
Notice in KillViewer() that there's basically a lock-grabbing loop to make sure that the program doesn't try to rename the working file until after the pdf viewer has fully released the lock.
The problem is this: sometimes this all works beautifully, and sometimes KillViewer breaks down on the CloseMainWindow() call, with an InvalidOperationException, details = "Process has exited, so the requested information is not available.". This would be fairly straightforward if it weren't for two things...
1: pdfView.HasExited = true
AND
2: The darned pdf viewer is STILL OPEN!!!
How in the world is this possible? Is there a process command I should be using to ensure the window closes? FYI, the program references nothing outside of either System.* namespaces, or internally built class which also ultimately reference only System.*.
Thanks.
Try this instead..
pdfView.Kill();
pdfView.WaitForExit();
After further investigation, I think I've determined what was going on.
I didn't detail workflow details because I couldn't reliably replicate the situation. After further attempts, I found two reliable situations...
Click on the link multiple times and then click save.
Click on the link, close the viewer window, and click save.
In each of these cases, the problem boiled down to the Process pointed to by pdfViewer becoming out of sync with what the user was doing.
If the link was clicked on multiple times, then the active viewer was on a process not connected with pdfViewer's process, hence the seemingly impossible situation detailed above.
If the link was clicked on and the window closed, the pdfViewer variable would remain, leaving a process with HasExited = true.
The take home lesson of all this is as follows: If you're running a separate process from your main user interface, make ABSOLUTELY SURE that you cover every possible situation that could occur with the external process.
For the record, Nick Guerrera deserves points for directing me towards the process IDs. That ultimately solved it.