Process.Start() does not work unless stepping over using F10 - c#

I would like to start a process using:
ProcessStartInfo createProject = new ProcessStartInfo();
createProject.FileName = exePath;
createProject.UseShellExecute = false;
createProject.WorkingDirectory = projectDirectory;
createProject.Arguments = exeArguments;
try
{
// Start the process with the info specified.
System.Diagnostics.Process.Start(createProject);
}
catch (IOException eX)
{
// Log error.
MessageBox.Show("Unable to create project", "Error Creating Project");
}
When I put a breakpoint at the line of Process.Start() and continue with step over by pressing F10, then the process runs without any problem.
However when I press F5 at the breakpoint or just run my application without any breakpoints, I get a "Your application has stopped working" dialog, without my application throwing any exception.
I tried also using Thread.Sleep() before the Process.Start() which has no result.
I really wonder what causes this problem.
EDIT: After I check the event viewer, I see that the faulting module is MSVCR90.dll. I have the version 9.0.30729.6161 installed.

This answer is for the one who is interested in the solution of the problem not the pragmatic discussion on the question itself:
Actually the answer was in the question itself and I got it after #rene raised one question.
Process runs when I step over because then program has time to finish its job. But when I press F5 it crashes because the process itself is not completed. I used following code:
ProcessStartInfo createProject = new ProcessStartInfo();
createProject.FileName = exePath;
createProject.UseShellExecute = false;
createProject.WorkingDirectory = projectDirectory;
createProject.Arguments = exeArguments;
try
{
using (System.Diagnostics.Process exeProcess = System.Diagnostics.Process.Start(createProject ))
{
exeProcess.WaitForExit();
}
}
catch (IOException eX)
{
// Log error.
MessageBox.Show("Unable to create project", "Error Creating Project");
}
This is the reason also why it doesn't throw any exception.
Thanks to #rene again!

Check your event log (with eventvwr.exe) to see if the process you're starting is hitting anything critical.
If the started process is also yours, you can add logging to it, or use System.Diagnostics.Debugger.Launch() to have it launch a debugger at startup -- or use gflags to break into it with WinDbg or similar on startup.

Related

My updater is failing to close my main program (C#)

I have an updater, which is called via the main program once an update is detected (from a remote XML file), first it checks whether the process is open
if (clsProcess.ProcessName.ToLower().Contains("conkinator-bot.exe"))
{
clsProcess.CloseMainWindow();
return true;
}
(this gets run for every process until it finds it (foreach loop))
the updater then downloads the file:
client.DownloadFile(url, "Conkinator-Bot-new.exe");
and then it attempts to delete the current one and rename it:
File.Delete("Conkinator-Bot.exe");
File.Move("Conkinator-Bot-new.exe", "Conkinator-Bot.exe");
but the error that I get when this occurs is the following:
Unhandled Exception: System.UnauthorizedAccessException: Access to the path 'D:\Conkinator's Skype Tool\Conkinator-Bot.exe' is denied.
however the new version of the program DOES download.
Just because the main window is closed doesn't mean the process is over. You need to wait for the process to exit after you close the main window:
clsProcess.WaitForExit();
Ideally, you'd use a timeout - there might be something preventing the window from closing, or the process might have a faulty exit mechanism.
It is a lot easier to close the main program from inside the main program itself.
string msg = "To update the application we need to close it. Do you want to continue?";
if (DialogResult.Yes == MessageBox.Show(msg, title, MessageBoxButtons.YesNo))
{
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "YourUpdaterFile.exe";
psi.WindowStyle = ProcessWindowStyle.Normal;
// Assuming a lot here but to just show the options available....
psi.WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath);
Process.Start(psi);
Application.Exit();
}

Process.Kill() is causing fatal error in Winform application

today I want to open application inside of form, but it cause error.
if (File.Exists(ts3))
{
Process p = Process.Start(ts3);
Thread.Sleep(2000);
SetParent(p.MainWindowHandle, panel1.Handle);
}
foreach (var process in Process.GetProcessesByName(ts3check))
{
process.Kill();
}
Thread.Sleep(500);
Process p = Process.Start(ts3);
Thread.Sleep(2000);
SetParent(p.MainWindowHandle, panel1.Handle);
It should check, if this app is already openned, if it is, kill it and open new one inside of my form. But when I try to open process in form, it will cause fatal error and makes my form stopped working. I'm looking at it for like half a hour and I can't see it.
EDIT: app works if app is not already openned, but if it is, it will execute this part of code and make the error
foreach (var process in Process.GetProcessesByName(ts3check))
{
process.Kill();
}
Thread.Sleep(500);
Process p = Process.Start(ts3);
Thread.Sleep(2000);
SetParent(p.MainWindowHandle, panel1.Handle);
Try changing Thread.Sleep(2000) to p.WaitForInputIdle() and you might also want to take a look at Hosting EXE Applications in a WinForm project over at CodeProject; someone has created a control to do exactly what you're looking for.

How to run Outlook using Process.Start("outlook.exe") and get the control back

My C# program needs to launch Office Outlook and get the current "running outlook application".
In order to do that I've implemented the following simple program (so if you want you can test it simply):
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Runtime.InteropServices;
static void Main(string[] args)
{
Outlook.Application outlookObj = null;
if (Process.GetProcessesByName("OUTLOOK").Count().Equals(0))
{
Process.Start("outlook.exe"); // MY PROGRAM STOPS HERE
}
var process = Process.GetProcessesByName("OUTLOOK").First();
while (!process.HasExited)
{
try
{
outlookObj = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application");
break;
}
catch
{
outlookObj = null;
}
System.Threading.Thread.Sleep(10);
}
string result = (outlookObj== null)? "DOES NOT WORK" : "OK";
Console.WriteLine(result);
Console.ReadLine();
}
My problem is that once Office Outlook starts running then my C# console application does not continue its job. After the Process.Start("outlook.exe"); instruction is executed then I must click on Visual Studio GUI in order to restart the console application and finally read "OK" on my console application.
How can I solve my problem?
Microsoft wrote a example about how to log into a outlook instance. Although this is directly what you asked for in your question, the example contains how to start a new outlook application in the intended way
application = new Outlook.Application();
as a side note: in your example you use the following code:
while (!process.HasExited)
{
try
{
outlookObj = (Outlook.Application)Marshal.GetActiveObject("Outlook.Application");
break;
}
catch
{
outlookObj = null;
}
System.Threading.Thread.Sleep(10);
}
This is bad practice in your main thread as your applying 'busy waiting' by using the thread.sleep. This means you will 1. use CPU power while your application is doing nothing. 2. make your GUI completely unresponsive and if the thread.sleep is called to many times Windows will suggest to shut the process down (the whole screen gets white and eventually you get a popup asking you if you want to wait or just shut it down). There are plenty of ways in the .net framework to prevent both of these issues (for example using a waithandle, background worker or locking)
There is no need to run the a new process using the Process.Start method. Instead, you can add the Outlook reference to your C# project and create a new instance of the Application class. See C# app automates Outlook (CSAutomateOutlook) sample project for more information.
Also you may find the following articles helpful:
How to automate Outlook and Word by using Visual C# .NET to create a pre-populated e-mail message that can be edited
How to use Visual C# to automate a running instance of an Office program
This works:
public static void StartOutlookIfNotRunning()
{
string OutlookFilepath = #"C:\Program Files (x86)\Microsoft Office\Office12\OUTLOOK.EXE";
if (Process.GetProcessesByName("OUTLOOK").Count() > 0) return;
Process process = new Process();
process.StartInfo = new ProcessStartInfo(OutlookFilepath);
process.Start();
}
Use the Process.Start overload that takes a ProcessStartInfo instead so you can set UseShellExecute
var startInfo = new ProcessStartInfo()
{
FileName = "Outlook.exe",
UseShellExecute = true
};
Process.Start(startInfo);
MAYBE the process need some time to start.
Try this:
if (Process.GetProcessesByName("OUTLOOK").Count().Equals(0))
{
Process.Start("outlook.exe"); // MY PROGRAM STOPS HERE
}
while ((Process.GetProcessesByName("OUTLOOK").Count().Equals(0));
var process = Process.GetProcessesByName("OUTLOOK").First();
This should cause starting process and waiting until it is avaible before trying to catch it...

C# Block code till processes release handle on files

I have a foreach loop that starts a process within a try/catch. In the finally section of my try/catch/finally I am trying to ensure the the process does not have a handle on any files. I have to delete files that were being processed.
Nothing I have tried seems to be working. I continue to get System.IO exceptions. "The file is currently in use by another process."
You can see in the finally I am using the WaitForExit() before returning from this method. The very next method call is one to delete files. Why would the process still be open or have a handle on any of these file after this?
Thanks!
try
{
foreach (var fileInfo in jsFiles)
{
//removed for clarity
_process.StartInfo.FileName = "\"C:\\Program Files\\Java\\jre6\\bin\\java\"";
_process.StartInfo.Arguments = stringBuilder.ToString();
_process.StartInfo.UseShellExecute = false;
_process.StartInfo.RedirectStandardOutput = true;
_process.Start();
}
}
catch (Exception e)
{
BuildMessageEventArgs args = new BuildMessageEventArgs("Compression Error: " + e.Message,
string.Empty, "JSMin", MessageImportance.High);
BuildEngine.LogMessageEvent(args);
}
finally
{
_process.WaitForExit();
_process.Close();
}
There's something seriously wrong here. You're starting a bunch of processes, but only waiting for the last spawned one to exit.
Are you sure you don't want the foreach outside the try block?
If you tell us more about what exactly you're trying to do, we could provide better suggestions.
I think you need to restructure your code. As it stands a failure for any of the processes in the foreach will cause an exit from the loop. Even if everything does succeed then your WaitForExit and Close calls in the finally block will only address the last process from the loop above.
You need to deal with each process and its success and/or failure individually. Create a method that accepts a fileInfo parameter and spawns and waits on each process. Move your loop into the client code that will be calling the suggested method.
Is the process a Console application or a GUI application?
For a GUI application, you will have to do Process.CloseMainWindow.
foreach (var fileInfo in jsFiles)
{
using (Process process = new Process())
{
try
{
//Other stuff
process.Start();
}
catch (...)
{
//Exception Handling goes here...
}
finally
{
try
{
process.WaitForExit();
}
catch (...)
{
}
}
}
}
Process.WaitForExit() might throw an exception, so it needs a try/catch of it's own.
If you create the process in the using statement, you don't have to worry about closing it, .NET will dispose of it properly.
It's usually better to not precede local variables with an underscore character. Most people just use that for their fields.

programmatically kill a process in vista/windows 7 in C#

I want to kill a process programmatically in vista/windows 7 (I'm not sure if there's significant problems in the implementation of the UAC between the two to make a difference).
Right now, my code looks like:
if(killProcess){
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("MyProcessName");
// Before starting the new process make sure no other MyProcessName is running.
foreach (System.Diagnostics.Process p in process)
{
p.Kill();
}
myProcess = System.Diagnostics.Process.Start(psi);
}
I have to do this because I need to make sure that if the user crashes the program or exits abruptly, this secondary process is restarted when the application is restarted, or if the user wants to change the parameters for this secondary process.
The code works fine in XP, but fails in Windows 7 (and I assume in Vista) with an 'access is denied' message. From what the Almighty Google has told me, I need to run my killing program as administrator to get around this problem, but that's just weak sauce. The other potential answer is to use LinkDemand, but I don't understand the msdn page for LinkDemand as it pertains to processes.
I could move the code into a thread, but that has a whole host of other difficulties inherent to it that I really don't want to discover.
You are correct in that it's because you don't have administrative priveleges. You can solve this by installing a service under the local system user and running a custom command against it as needed.
In your windows form app:
private enum SimpleServiceCustomCommands { KillProcess = 128 };
ServiceControllerPermission scp = new ServiceControllerPermission(ServiceControllerPermissionAccess.Control, Environment.MachineName, "SERVICE_NAME");
scp.Assert();
System.ServiceProcess.ServiceController serviceCon = new System.ServiceProcess.ServiceController("SERVICE_NAME", Environment.MachineName);
serviceCon.ExecuteCommand((int)SimpleServiceCustomCommands.KillProcess);
myProcess = System.Diagnostics.Process.Start(psi);
In your service:
private enum SimpleServiceCustomCommands { KillProcess = 128 };
protected override void OnCustomCommand(int command)
{
switch (command)
{
case (int)SimpleServiceCustomCommands.KillProcess:
if(killProcess)
{
System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName("MyProcessName");
// Before starting the new process make sure no other MyProcessName is running.
foreach (System.Diagnostics.Process p in process)
{
p.Kill();
}
}
break;
default:
break;
}
}
I'll add the code for Simon Buchan's suggestion. It makes sense and should work as well, assuming your windows form is what launched the process in the first place.
Here's where you create the process. Notice the variable myProc. That's your handle on it:
System.Diagnostics.Process myProc = new System.Diagnostics.Process();
myProc.EnableRaisingEvents=false;
myProc.StartInfo.FileName="PATH_TO_EXE";
myProc.Start();
Later, just kill it with:
myProc.Kill();

Categories

Resources