Check if Java App is running from C# .NET - c#

I launch a game server application from a .bat file currently using this...
java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui
I would like to be able to check if it is running or not from a C# .NET application. Is there any simple way to do this?

Using the Process class, you can find the java processes but you won't be able to tell what they are executing. You'd need to be able to inspect their command line at least to determine this. If all your Minecraft servers are started with the same command line arguments, you could use WMI to find. You could get the associated associated Process objects if you want to do what you need.
// find all java processes running Minecraft servers
var query =
"SELECT ProcessId "
+ "FROM Win32_Process "
+ "WHERE Name = 'java.exe' "
+ "AND CommandLine LIKE '%minecraft_server%'";
// get associated processes
List<Process> servers = null;
using (var results = new ManagementObjectSearcher(query).Get())
servers = results.Cast<ManagementObject>()
.Select(mo => Process.GetProcessById((int)(uint)mo["ProcessId"]))
.ToList();
You'll need to add a reference to the System.Management.dll library and use the System.Management namespace.
The existence of such processes is enough to know it is running. You could also determine if and when it ends by inspecting each process' properties such as HasExited or wait for it using WaitForExit().

Instead of using a .bat file to launch java, you might consider looking into the System.Diagnostics.Process from .Net. It has all sorts of goodies for dealing with processes.
If you want to be checking on the game server constantly over a stretch of time, you probably will have to use it with some sort of Thread or BackgroundWorker, but the Process class ought to lead you in the right direction.
Hope this helps.

Related

How to get a new process to know the location of dotnet in Linux?

Our test and development team has been working to implement and test a new version of our software using .NET 6 that we will be releasing early next year. For test's part, we have had to upgrade all of our C# automated testing to be cross-platform compatible. One set of tests requires starting a new process and executing a console application we have as a supporting library. Below is the following code I am using:
#if (WINDOWS)
string strCmdText = "/C \" SAT.FCCHandling -l" + password + " -i" + ip + " -xDeleteFCC\"";
#endif
#if (LINUX)
string strCmdText = "-c \" .//SAT.FCCHandling -l" + password + " -i" + ip + " -xDeleteFCC\"";
#endif[![enter image description here](https://i.stack.imgur.com/6SYCA.png)](https://i.stack.imgur.com/6SYCA.png)
using (var proc = Process.Start(new ProcessStartInfo
{
#if (WINDOWS)
FileName = "cmd.exe",
#endif
#if (LINUX)
FileName = "/bin/bash",
#endif
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = strCmdText,
WindowStyle = ProcessWindowStyle.Hidden
}))
{
proc.WaitForExit();
if (proc.ExitCode != 0)
{ Assert.Fail("There was an issue Inserting an invalid FCC."); }
}
I have been using VSCode in Linux to debug problems that arise. When the code above is executed in Linux (specifically in Ubuntu 20.04), in the developer console it's indicating that the location for .NET is not found:
We also use TShark for packet capture in some testing. The methodology of code is used in launching TShark as a new process. I bring this up not because TShark is written in C# with .NET 6, but merely to point out that this approach for launching an application does work.
The problem, as I perceive it, is this child process being launched has no knowledge of environment variables. If I launch the application directly from the terminal in the binary directory, the application runs just fine.
I have done some digging and research online before posing this question. I haven't found anything that is exactly similar to my problem. I have tried a couple avenues based upon what I have read online, but these don't seem to be the right solution:
Assigning all variables to the StartInfo of the new process.
Assigning specifically EnvironmentVariables["TEST_ENV"] = "From parent"; to the Process.StartInfo. I saw something online that seemed to indicate that passing environment variables down to the child process was a necessity as the variables are instances.
Using the StartInfo.Verb = “runas” to elevate the privileges of the process.
I know that the solution is probably an obvious one that I'm just not seeing. I am not a Linux expert by any stretch of the imagination and have been having to learn as I go through this release. Any guidance is much appreciated and I'm happy to provide further information if necessary. Thank you.
I spent some time during the holidays researching, debugging, and testing. I was able to find a solution to my problem. Several things:
In order to know exactly what was happening to my process on launch, I attached two threads to the standard output and standard error of the process I start.
This lead me to discover that the file location was unknown to bash when calling it.
With this resolved, I discovered that I needed to execute 'chmod +x ' before executing the console application.
It's worthy of note that by trying to debug my problem from a .NET 6 console app (launching another console app) was injecting a different kind of problem into my existing problem. Using my existing NUnit testing that calls the console app was what lead me to the discovery noted above.
Lesson learned: If trying to call a .exe in Linux from your .NET 6 application by starting a process, be sure to make the file executable before you try calling it with bash or another shell.

Get already running windows process' console output in a command prompt? Direct StreamReader to command prompt

I am trying to determine if there is a way to get the console output, in a command prompt, of an already running process in the windows environment via C#. I have seen an answer for linux based systems through the shell and also a way to retrieve a Process object. Though neither offer a solution to get the output of the process.
I my code I currently find a process (MongodDB daemon) this way
Process[] procs = Process.GetProcessesByName("mongod");
if (procs.Length > 0)
{
MongoProcess = procs[0];
Console.Out.WriteLine("Found mongod.exe, process id: " + MongoProcess.Id);
}
I have also found the Process.StandardOutput property which supplies "A StreamReader that can be used to read the standard output stream of the application.". Is there a way to direct this StreamReader input to a command prompt output?
I also know that I can start a process and display the command prompt (process output), but this is only when the process is started "by me".
Process.Start(new ProcessStartInfo("notepad.exe") { CreateNoWindow = false })
I also know that I could simply read from the StreamReader and display the output in my own way, but I would really prefer to just display a command prompt.
Windows does not provide any mechanism to retroactively give another process a standard output handle if it was created without one. (Besides, in most cases an application will check the standard output handle only during startup.)
If you know (or can successfully guess) how a specific application generates output, it may in principle be possible to start capturing that output by injecting your own code into the process. For example, if you know that the application uses C++ and is dynamically linked to the VS2015 runtime library, you might inject code that calls freopen as shown here. (In this scenario, you must know which runtime library the application uses because you have specify it when looking up the address for freopen.)
However, code injection is not trivial, and creates a risk of inadvertently causing the process to malfunction. Also, any output that has already been generated will almost certainly have been discarded and be irrevocably lost.

Detect a Non Responding Process

I'm trying to detect if a process I'm launching via my C# program still answers or not.
I've tryed the following :
Process *notepads[];
notepads = Process::GetProcessesByName("Notepad.exe");
// Test to see if the process is responding.
if (notepads[0]->Responding())
notepads[0]->CloseMainWindow();
else
notepads[0]->Kill();
However, I would like to find a Qt equivalent for ANY process (not only MMI processes).
Do you know how I could do that ?
Getting process list is OS-dependent. so you have to do it by yourself on each platform.
on Windows, you can use Windows API EnumProcesses
on Linux, you can search /proc folder.
See QProcess documentation for details.
Qt does not provide any method to obtain information or control overs process that you don't explicitely start from a QProcess instance.

C# Application Calling Powershell Script Issues

I have a C# Winforms application which is calling a simple powershell script using the following method:
Process process = new Process();
process.StartInfo.FileName = #"powershell.exe";
process.StartInfo.Arguments = String.Format("-noexit \"C:\\Develop\\{1}\"", scriptName);
process.Start();
The powershell script simply reads a registry key and outputs the subkeys.
$items = get-childitem -literalPath hklm:\software
foreach($item in $items)
{
Write-Host $item
}
The problem I have is that when I run the script from the C# application I get one set of results, but when I run the script standalone (from the powershell command line) I get a different set of results entirely.
The results from running from the c# app are:
HKEY_LOCAL_MACHINE\software\Adobe
HKEY_LOCAL_MACHINE\software\Business Objects
HKEY_LOCAL_MACHINE\software\Helios
HKEY_LOCAL_MACHINE\software\InstallShield
HKEY_LOCAL_MACHINE\software\Macrovision
HKEY_LOCAL_MACHINE\software\Microsoft
HKEY_LOCAL_MACHINE\software\MozillaPlugins
HKEY_LOCAL_MACHINE\software\ODBC
HKEY_LOCAL_MACHINE\software\Classes
HKEY_LOCAL_MACHINE\software\Clients
HKEY_LOCAL_MACHINE\software\Policies
HKEY_LOCAL_MACHINE\software\RegisteredApplications
PS C:\Develop\RnD\SiriusPatcher\Sirius.Patcher.UI\bin\Debug>
When run from the powershell command line I get:
PS M:\> C:\Develop\RegistryAccess.ps1
HKEY_LOCAL_MACHINE\software\ATI Technologies
HKEY_LOCAL_MACHINE\software\Classes
HKEY_LOCAL_MACHINE\software\Clients
HKEY_LOCAL_MACHINE\software\Equiniti
HKEY_LOCAL_MACHINE\software\Microsoft
HKEY_LOCAL_MACHINE\software\ODBC
HKEY_LOCAL_MACHINE\software\Policies
HKEY_LOCAL_MACHINE\software\RegisteredApplications
HKEY_LOCAL_MACHINE\software\Wow6432Node
PS M:\>
The second set of results match what I have in the registry, but the first set of results (which came from the c# app) don't.
Any help or pointers would be greatly apreciated :)
Ben
This is actually not a particularly good way to embed PowerShell within a C# api. There are APIs for that.
You can find an example of them on MSDN, but in your case the could would look something like
PowerShell.Create().AddScript("get-childitem -literalPath hklm:\software").Invoke()
You can also check out this blog post, which will show you how to dot source inside of the API and how to use this API to get at the other data streams in PowerShell.
Hope this helps
Are you running a 64bit version of Windows by chance? It could be a difference in how the two "hives" are being shown. Try forcing your C# app to compile to x86/x64 instead of "Any" in the Project properties. See if that makes any difference.
Also, your command line syntax is a little strange, see the following thread for better details, but you may want to adjust your syntax:
String cmd = "-Command "& { . \"" + scriptName + "\" }";
Process process = new Process();
process.StartInfo.FileName = #"powershell.exe";
process.StartInfo.Arguments = cmd;
process.Start();
Calling a specific PowerShell function from the command line
I did look at alternative methods for calling Powershell and came across that API.
Am I right in thinking though that they rely on a Microsoft SDK??
I'm not really a fan of dependencies on external SDKs. I work in a rather large company and ensuring that the SDK is installed on all of the developers machines would be a nightmare.
If I'm wrong in my thinking, I am open to a better way of calling Powershell. I didn't particularly like calling the script as a separate process and would like the ability to have values returned from the script.
Ben

killing process java.exe

I launch some batch file from my C# app via Process class. This file started java app. I cant recognize which process called java.exe must be kill to stop this application. Is there some more elegant way than kill them all, hope that i end the right one and dont kill some other important java app? Thanks for any help I really stuck there.
Cheers,
Andrew
EDIT: I missed the batch file part. This answer will only be useful if you can launch the process directly from C#...
When you start the process you can store the process Id so you can get the process back later and kill it.
Process p = new Process();
//set all the process start Info...
p.Start();
someVariableICanGetToLater = p.Id
//Later when you need to kill the process...
Process pToKill = Process.GetProcessById(someVariableICanGetToLater);
pToKill.Kill();
I assume that, since the batch file launches the Java app, knowing the id of the batch file process won't help.
Process.GetProcessesByName("java") gives you a list of all the java.exe instances.
pseudo code . Fill in OS specific calls here:
int cs_pid=getProcessByName("CSharpAppName");
int javaPid[]= getProcessByName("JavaAppName");
bool javaToCSharpRelationship[]=new bool[javaPid.size];
int loopCounter=0;
forEach int in javaPid
begin
if(isChildOf(cs_pid,java_pid))
begin
// OS call or Wrapper to determine relationship between c# pid
// and Java app PID
javaToCSharpRelationShip[loopCounter]=true;
//can call kill here if you like
end
else
javaToCSharpRelationShip[loopCounter]=false;
loopCounter++;
end
At the end of this code you should have an array of PID's which are children of the C# app.
Unless the batch file does lots of things, hard to accomplish using only .NET's Process and ProcessStartInfo classes, another option would be to start directly java.exe and control the arguments and environment variables via ProcessStartInfo's Arguments and EnvironmentVariables properties.
Then you could use Jason's approach to store java.exe process' id in order to kill it later.

Categories