Killing Java Process from C# Console App - c#

I hate to post about this again but I answered my own last post thinking I fixed it (which I didn't). Basically when my c# .NET application shuts down, I want to remove the running Java process that it created. The initial problem was that I was trying to save processID to a static class member variable (which obviously didnt work). I found a Global Class example online and used that instead, however it still isn't shutting down the process.
Debugging it isn't working properly. I guess it just creates a new instance of the application rather than running the one that I built, and even setting the working directory to the "Bin" directory doesn't work. So I am just having to run my .exe from the Bin directory at the moment.
namespace MinecraftDaemon
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting Minecraft Daemon...");
Arguments CommandLine = new Arguments(args);
// Hook ProcessExit Event
AppDomain.CurrentDomain.ProcessExit += new EventHandler(Current_ProcessExit);
if (CommandLine["file"] != null && CommandLine["memory"] != null)
{
// Launch the Application (Command Line Parameters)
LaunchMinecraft(CommandLine["file"], CommandLine["memory"]);
}
else
{
// Launch the Application (Default Parameters)
LaunchMinecraft("minecraft_server.jar", "1024");
}
}
public static void LaunchMinecraft(String file, String memoryValue)
{
String memParams = "-Xmx" + memoryValue + "M" + " -Xms" + memoryValue + "M ";
String args = memParams + "-jar " + file + " nogui";
ProcessStartInfo processInfo = new ProcessStartInfo("java.exe", args);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
try
{
using (Process minecraftProcess = Process.Start(processInfo))
{
GlobalClass.ProcessID = minecraftProcess.Id;
Console.WriteLine("Process ID is " + GlobalClass.ProcessID);
minecraftProcess.WaitForExit();
}
}
catch
{
// Log Error
}
}
static void Current_ProcessExit(object sender, EventArgs e)
{
// Loop the Current Windows Processes
foreach (Process winProcess in Process.GetProcesses())
{
Console.WriteLine("WinProcessID is " + winProcess.Id + " GlobalClass.ProcessID is " + GlobalClass.ProcessID);
// If this is our Process, shut it down
if (winProcess.Id == GlobalClass.ProcessID)
{
Process.GetProcessById(GlobalClass.ProcessID).Kill();
}
}
}
}
}

This was resolved by switching from catching the Event AppDomain.CurrentDomain.ProcessExit to using SetConsoleCtrlHandler();

Related

Access is denied when trying to close an exe through C# in winforms

I opening and closing an application through my windows form application but the problem is, I am getting Access denied error.
Here is the code snippet from the project.
try
{
//This loop wil check the timing.
for (int i = 0; i < exeStartTimes.Count; i++)
{
if (hour == exeStartTimes[i].hour && minute == exeStartTimes[i].minute)
{
if (CheckExeIsOpen(tbExeName.Text) == false)
{
Process p = new Process();
p.StartInfo.FileName = (tbExeLocation.Text + tbExeName.Text);
p.Start();
AppendLogFile("Started " + tbExeLocation.Text + tbExeName.Text + " on " + time);
}
}
if (hour == exeEndTimes[i].hour && minute == exeEndTimes[i].minute)
{
if (CheckExeIsOpen(tbExeName.Text) == true)
{
CloseExe(tbExeName.Text);
AppendLogFile("Closed " + tbExeName.Text + time);
}
}
}
}
catch (Win32Exception w)
{
MessageBox.Show("Error occured : " + w.Message);
AppendLogFile("message : " + w.Message);
AppendLogFile("ErrorCode : " + w.ErrorCode.ToString());
AppendLogFile("Native : " +w.NativeErrorCode.ToString());
AppendLogFile("StackTrace : " + w.StackTrace);
AppendLogFile("Source : " + w.Source);
Exception e = w.GetBaseException();
AppendLogFile(e.Message);
}
And here are the close EXE methods:
private bool CheckExeIsOpen(string exeName)
{
string name = exeName.Split('.')[0];
foreach (var process in Process.GetProcesses())
{
if (process.ProcessName == name)//process name matched return true appliation is open
{
return true;
}
}
return false;//process name not matched return false appliation is closed
}
private void CloseExe(string exeName)
{
string name = exeName.Split('.')[0];
foreach (var process in Process.GetProcesses())
{
if (process.ProcessName == name)
{
process.Kill();
AppendLogFile(tbExeName.Text + " Closed on " + DateTime.Now);
}
}
}
The error details include
message : Access is denied
ErrorCode : -2147467259
I have found that it is creating problem when I am closing the application.
According to the documentation:
The Kill method executes asynchronously. After calling the Kill
method, call the WaitForExit method to wait for the process to exit,
or check the HasExited property to determine if the process has
exited.
and
If the call to the Kill method is made while the process is currently
terminating, a Win32Exception is thrown for Access Denied.
The problem is that you call Kill twice and second call throws exception.
So, the solution would be to call:
process.Kill();
process.WaitForExit();

C# Error 1053 the service did not respond to the start or control request in a timely fashion

I realize there are a ton of these posts, but none them, believe it or not, resolve my problem.
I have the following code here that uses the ManagementEventWatcher class to kill a process from another in house app if it runs too long, which it occasionally does and kills the cpu.
Anyway, it gets this error instantaneously when starting the service. Nothing in the event log. Currently I have it testing with notepad.exe.
public AppXKiller()
{
InitializeComponent();
this.ServiceName = "AppXKiller";
this.EventLog.Log = "Application";
// These Flags set whether or not to handle that specific
// type of event. Set to true if you need it, false otherwise.
this.CanHandlePowerEvent = true;
this.CanHandleSessionChangeEvent = true;
this.CanPauseAndContinue = true;
this.CanShutdown = true;
this.CanStop = true;
}
static void Main()
{
ServiceBase.Run(new AppXKiller());
}
protected override void OnStart(string[] args)
{
registerWatcher();
}
protected override void OnContinue()
{
base.OnContinue();
}
public void registerWatcher()
{
string pol = "2";
string appName = "notepad.exe";
string queryString =
"SELECT *" +
" FROM __InstanceOperationEvent " +
"WITHIN " + pol +
" WHERE TargetInstance ISA 'Win32_Process' " +
" AND TargetInstance.Name = '" + appName + "'";
// You could replace the dot by a machine name to watch to that machine
string scope = #"\\.\root\CIMV2";
// create the watcher and start to listen
ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
watcher.EventArrived += new EventArrivedEventHandler(this.OnEventArrived);
watcher.Start();
}
private void OnEventArrived(object sender, EventArrivedEventArgs e)
{
Thread.Sleep(20000);
Process[] localByName = Process.GetProcessesByName("notepad");
if (localByName.Length > 0)
{
localByName[0].Kill();
}
}
protected override void OnStop()
{
}
}
Turns out that the application has to be the release version of the build, not the debug version. This makes no sense but oh well. I guess if I want to test and debug the app I have to do it in release mode.
Choose Release from the drop down menu up top (somewhere under tools depending on the size of your screen). It probably says debug.
Build the app.
Install the service from the release folder.

How do I save continuous console output to a text file in c#?

I'm quite a noob at programming and I've been stuck at this for a while now. I'm using the following code to get continuous data output streamed to a command prompt. How can I ensure that the output gets copied to a text file after closing the prompt manually?
public static void Main(string[] args)
{
Connector connector;
Console.WriteLine("HelloEEG!");
// Initialize a new Connector and add event handlers
connector = new Connector();
connector.DeviceConnected += new EventHandler(OnDeviceConnected);
connector.DeviceConnectFail += new EventHandler(OnDeviceFail);
connector.DeviceValidating += new EventHandler(OnDeviceValidating);
// Scan for devices across COM ports
// The COM port named will be the first COM port that is checked.
connector.ConnectScan("COM40");
// Blink detection needs to be manually turned on
connector.setBlinkDetectionEnabled(true);
Thread.Sleep(400000);
System.Console.WriteLine("Goodbye.");
connector.Close();
Environment.Exit(0);
}
// Called when a device is connected
static void OnDeviceConnected(object sender, EventArgs e)
{
Connector.DeviceEventArgs de = (Connector.DeviceEventArgs)e;
Console.WriteLine("Device found on: " + de.Device.PortName);
de.Device.DataReceived += new EventHandler(OnDataReceived);
}
// Called when scanning fails
static void OnDeviceFail(object sender, EventArgs e)
{
Console.WriteLine("No devices found! :(");
}
// Called when each port is being validated
static void OnDeviceValidating(object sender, EventArgs e)
{
Console.WriteLine("Validating: ");
}
// Called when data is received from a device
static void OnDataReceived(object sender, EventArgs e)
{
Device.DataEventArgs de = (Device.DataEventArgs)e;
DataRow[] tempDataRowArray = de.DataRowArray;
TGParser tgParser = new TGParser();
tgParser.Read(de.DataRowArray);
/* Loops through the newly parsed data of the connected headset*/
// The comments below indicate and can be used to print out the different data outputs.
for (int i = 0; i < tgParser.ParsedData.Length; i++)
{
//string temp = tgParser.ParsedData[1].ToString;
//Console.WriteLine(tgParser.ParsedData.Length + " + " + temp);
if (tgParser.ParsedData[i].ContainsKey("Raw"))
{
//Console.WriteLine("Raw Value:" + tgParser.ParsedData[i]["Raw"]);
//Console.WriteLine("Raw Value:" + tgParser.ParsedData[i]["Raw"]);
}
if (tgParser.ParsedData[i].ContainsKey("PoorSignal"))
{
//The following line prints the Time associated with the parsed data
//Console.WriteLine("Time:" + tgParser.ParsedData[i]["Time"]);
Console.WriteLine("Time:" + tgParser.ParsedData[i]["Time"]);
//A Poor Signal value of 0 indicates that your headset is fitting properly
Console.WriteLine("Poor Signal:" + tgParser.ParsedData[i]["PoorSignal"]);
poorSig = (byte)tgParser.ParsedData[i]["PoorSignal"];
}
if (tgParser.ParsedData[i].ContainsKey("Attention"))
{
//Console.WriteLine("Att Value:" + tgParser.ParsedData[i]["Attention"]);
Console.WriteLine("Att Value:" + tgParser.ParsedData[i]["Attention"]);
}
if (tgParser.ParsedData[i].ContainsKey("Meditation"))
{
//Console.WriteLine("Med Value:" + tgParser.ParsedData[i]["Meditation"]);
Console.WriteLine("Med Value:" + tgParser.ParsedData[i]["Meditation"]);
}
if (tgParser.ParsedData[i].ContainsKey("EegPowerDelta"))
{
//Console.WriteLine("Delta: " + tgParser.ParsedData[i]["EegPowerDelta"]);
Console.WriteLine("Delta: " + tgParser.ParsedData[i]["EegPowerDelta"]);
}
if (tgParser.ParsedData[i].ContainsKey("BlinkStrength"))
{
//Console.WriteLine("Eyeblink " + tgParser.ParsedData[i]["BlinkStrength"]);
Console.WriteLine("Eyeblink " + tgParser.ParsedData[i]["BlinkStrength"]);
}
}
}
It will be much better to log every console output to a file as it happens. Instead of waiting to write to file when the app is closed manually. To save yourself a lot of coding, you can use log4net to handle the logging.
There's several different ways of approaching this, and with a bit of research I'm sure you could find a few, however this is the solution I would use for this particular action :
As Jonesy mentioned in the comments, I would firstly tidy up your Main. Create a separate class to perform the console writeline and the text output at the same time.
In this class perhaps use a loop to output the data to a file as and when it happens, therefore you wouldn't have to code in the logic when the console is closed manually, which in turn would cover unexpected errors and loss of logs.
This might work.
public static void WriteToFileAndConsole()
{
string outFile = "ConsoleOut.txt";
using (FileStream fileStream = new FileStream(outFile, FileMode.OpenOrCreate))
{
using (StreamWriter writer = new StreamWriter(fileStream))
{
using (TextWriter originalConsoleOut = Console.Out)
{
Console.SetOut(writer);
Console.WriteLine("Hello To File");
Console.SetOut(originalConsoleOut);
}
}
}
Console.WriteLine("Hello to console only");
}

FileSystemWatcher Access to a FileShare: Possible permission iusse?

I'm written a basic application that watches one network File Share directory and when a new file is created in that directory it then fires an external application that parses that file. I've also tested with a local directory and everything worked. I've tested it with debug code like so and the application will work:
#if DEBUG
Service1 mysService1 = new Service1();
mysService1.OnDebug(); //calls onStart(Null);
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#endif
Then when I switch to release, build and install the service nothing will happen. So since the path worked i figured this was down to permissions?
I went to Task Manager>Services>Services..> right clicked on my service>Properties>Log On> and have given it my credentials.
I've also gone to the root folder of where my application is on the network Right click>Security>Edit. Then I gave my account Modify, Read & Execute, Listing folder contents, and Read permissions and of course those permissions propagated to all of the folders under its hierarchy.
I even tried mapping it to the network drive Z and trying to access it that one.
With everything I tried the service still refuses to do anything. I've added more debugging code where I would check if the file was changed or deleted and write it down in text files. Once again it would work and detect those changes in debug but upon install nothing would happen.
I'm pretty sure this is probably still some kind of permission issue can anyone tell me what else I could do to remedy this issue?
EDIT:
There was a request for more code. Also note that my Utility class was able to produce a stack trace. It lead to an issue with System.IO.FileStream error started from this line of code in the FileWatcher.cs System.IO.File.AppendAllText(PathLocation() + "\logFile.txt", Environment.NewLine + " Started! " + DateTime.Now.ToString());
Service1.cs:
public Service1()
{
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
try
{
FileWatcher f = new FileWatcher();
}
catch (Exception e)
{
new ErrorMailer(e, DateTime.Now.ToString());
}
}
FileWatcher.cs:
private FileSystemWatcher _fileWatcher;
static ProcessStartInfo start;
public FileWatcher()
{
System.IO.File.AppendAllText(PathLocation() + "\\logFile.txt", Environment.NewLine + " Started! " + DateTime.Now.ToString());
_fileWatcher = new FileSystemWatcher(PathLocation());
HasMailClerkBeenRun = false;
start = new ProcessStartInfo();
_fileWatcher.Created += new FileSystemEventHandler(_fileWatcher_Created);
_fileWatcher.Deleted += new FileSystemEventHandler(_fileWatcher_Deleted);
_fileWatcher.Changed += new FileSystemEventHandler(_fileWatcher_Changed);
_fileWatcher.EnableRaisingEvents = true;
}
{
string value = String.Empty;
value = #"Z:\MyAppDirectory\DirectoryFileWatcherIsWatching"; //#"\\FileShareName\RootDirectory\MyAppDirectory\DirectoryFileWatcherIsWatching";
return value;
}
void _fileWatcher_Changed(object sender, FileSystemEventArgs e)
{
System.IO.File.AppendAllText(PathLocation() + "\\logFile.txt", Environment.NewLine + "Started from the bottom now we changed! " + DateTime.Now.ToString());
}
void _fileWatcher_Deleted(object sender, FileSystemEventArgs e)
{
System.IO.File.AppendAllText(PathLocation() + "\\logFile.txt", Environment.NewLine + "Started from the bottom now we deleted! " + DateTime.Now.ToString());
}
void _fileWatcher_Created(object sender, FileSystemEventArgs e)
{
System.IO.File.AppendAllText(PathLocation() + "\\logFile.txt", Environment.NewLine + "Started from the bottom now we here! " + DateTime.Now.ToString());
LaunchExternalApp();
}
private void LaunchExternalApp()
{
start.UseShellExecute = false;
start.RedirectStandardError = true;
start.RedirectStandardInput = true;
start.RedirectStandardOutput = true;
start.CreateNoWindow = true;
start.ErrorDialog = false;
start.WindowStyle = ProcessWindowStyle.Hidden;
start.FileName =#"Z:\MyAppDirectory\AppExcutionLocation\MyApp.exe"
Thread thread1 = new Thread(new ThreadStart(A));
thread1.Start();
thread1.Join();
}
static void A()
{
using (Process proc = Process.Start(start))
{
proc.WaitForExit();
//HasMailClerkBeenRun = true;
// Retrieve the app's exit code
/// int exitCode = proc.ExitCode;
}
Thread.Sleep(100);
Console.WriteLine('A');
}
Check that the service is running under the same account as the interactive user account that you are using when checking the share or mapping the drive. If not, try switching it to use this account.
I have no idea why you are calling System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite), but I suspect that removing that line will solve your problem. If it doesn't, please post more code.

C# Keeping Sub-Process Running

I wrote a small program in C# NET a while back to keep a Java process running. I am about to deploy it to a bunch of servers and I am working on fixing up some of the code now. As it stands, I don't think I have this setup right.
What would be the best way to keep the process running that I am creating in my LaunchMinecraft() function? I want to have it so as long as my process is running, it continues to restart this process if it crashes.
static void Main(string[] args)
{
// Launch the Application
LaunchMinecraft("minecraft_server.jar", "512");
}
public static void LaunchMinecraft(string file, string memory)
{
string memParams = "-Xms" + memory + "M" + " -Xmx" + memory + "M ";
string args = memParams + "-jar " + file + " nogui";
ProcessStartInfo processInfo = new ProcessStartInfo("java.exe", args);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardError = true;
try
{
using (Process minecraftProcess = Process.Start(processInfo))
{
// Store Process Globally to access elsewhere
JavaProcess = minecraftProcess;
// Creates a Repeating Poll Timer (30 Seconds)
// Use this to keep the Minecraft's Process Affinity/Priority the same as the Daemon
PollTimer = new System.Timers.Timer();
PollTimer.Elapsed += new ElapsedEventHandler(Event_PollProcess);
PollTimer.Interval = 5000;
PollTimer.Start();
Console.WriteLine("Minecraft Process Started.");
// Setup Callback for Redirected Output/Error Streams
minecraftProcess.OutputDataReceived += new DataReceivedEventHandler(Handler_ProcessOutput);
minecraftProcess.ErrorDataReceived += new DataReceivedEventHandler(Handler_ProcessError);
// Steam Writer
streamWriter = minecraftProcess.StandardInput;
minecraftProcess.BeginOutputReadLine();
minecraftProcess.BeginErrorReadLine();
while (minecraftProcess.HasExited == false)
{
String strInput = Console.ReadLine();
SendProcessCmd(strInput);
}
minecraftProcess.WaitForExit();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The Process class itself cant prevent your external program from shutting down, you have to use the Exited event as #Jalal mentiones or poll the HasExited property of the process.

Categories