2

I started a java program from c# by using

...
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = "C:\\path\\to\\jar\\";
startInfo.FileName = "C:\\Windows\\Sysnative\\java.exe";
startInfo.Arguments = "-jar JavaProg.jar";
process = new Process();
process.StartInfo = startInfo;
try {
    process.Start();
}
...

The process is then running continuously until I want it to stop. The java program has a shutdown hook that should be able to catch normal kill signals. E.g., if I run the jar from a bat script, then pressing Ctrl+c in the cmd window will trigger the shutdown hook, but closing the cmd window will terminate the process without triggering the shutdown hook (similar to End Process in the task manager).

So in order to stop the java program from C# I tried:

process.CloseMainWindow();

or

process.Kill();

The CloseMainWindow method has no effect on the java process, and Kill terminates it without triggering the shutdown hook. So what can I do in order to close the java program gracefully from within the C# code?? [Do I need to make modifications in my Java program to intercept the CloseMainWindow signal? Is there a way to mimic the behavior of Ctrl+c on the cmd window from C#? Must I create some path of communication between my C# and Java codes like a pipe or socket?]

P.S. The C# code is simply a wrapper for the java code in order to run it as a service on windows (I can't use existing tools such as RunAsService for that purpose).

General description of the program: My java program doesn't create any windows. It has a few threads, the main one runs in a loop just waiting for connections, another performs a specific task on an incoming connection, another thread does periodic updates from a web server, and there's the shutdown hook. Usually, the program is run from the command prompt (or terminal on linux), and takes user input only when it is loading for the first time, after which it can be run again without more user input. The program outputs logs to a file. My shutdown hook:

...
shutdownHook = new ShutdownHook();
Runtime.getRuntime().addShutdownHook(shutdownHook);
...
class ShutdownHook extends Thread {
    public void run() {
        // log the shutdown is started
        // terminate classes
        // interrupt and join the other threads
        // log the shutdown is done
    }
}
giladrv
  • 1,024
  • 1
  • 9
  • 22
  • I doubt this has anything to do with Java. Or do you mean to say that you can kill other processes this way with no problem? – fge Dec 03 '14 at 12:15
  • How does your Java program look like? Does it create a window or does it run in the shell? – helb Dec 03 '14 at 12:17
  • Is the shutdown hook triggered if you kill the process using TaskManager? – helb Dec 03 '14 at 12:26
  • @fgw: my first time using C#, so no.. :) – giladrv Dec 03 '14 at 12:34
  • @helb: edited my post. the shutdown hook is not triggered when killing the process from TaskManager. – giladrv Dec 03 '14 at 12:35
  • @giladrv Then maybe your shutdown hook does not work. Have a look at http://stackoverflow.com/questions/2541597/how-to-gracefully-handle-the-sigkill-signal-in-java – helb Dec 03 '14 at 12:40
  • Maybe you should just kludge it. Write to a file, shutdown.txt and poll the file. When the file exists close your process and delete the file. You'd have to be careful with how you manage not closing the next process to start up. You could be pretty safe with "delete the file", if the file does not exist, shut down. – Derek Dec 03 '14 at 12:52
  • @helb: but my shutdown hook does work, it catches ctrl+c from cmd. – giladrv Dec 03 '14 at 12:56
  • @Derek: this is not a good approach at all. See my note about the pipe/socket method. – giladrv Dec 03 '14 at 12:58

3 Answers3

2

The best way of doing this is for your C# program to get a handle to the Java program's stdin. That way, the C# program can send a message to the Java program whenever it likes, and the Java program can listen out for a message asking it to die.

This has the advantage that you don't need to worry about shutdown hooks: the program can do whatever processing it needs to when it receives a shutdown message. It is also a lot more flexible: if, later on, you want the C# program to send other control messages, that can be easily added.

On the Java side, you'd need a separate thread that opens System.in and reads from it, and performs whatever shutdown you need when it gets the right message in.

On the C# side, it looks as though you want

startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;

and then when you want to send a message:

process.StandardInput.WriteLine(...some message...);

(but I am a Java coder, so I am uncertain as to whether I've got the C# right here).

chiastic-security
  • 20,430
  • 4
  • 39
  • 67
0

This attempts to close all notepad windows. Note that you can end up getting prompted if you want to save.

  [DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = false )]
  static extern IntPtr SendMessage( IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam );

  static uint WM_CLOSE = 0x10;

  public void CloseWindow( IntPtr hWindow )
  {
     SendMessage( hWindow, WM_CLOSE, IntPtr.Zero, IntPtr.Zero );
  }

  public void test_close()
  {
     foreach ( System.Diagnostics.Process p in System.Diagnostics.Process.GetProcessesByName( "notepad" ) )
     {
        CloseWindow(p.MainWindowHandle);
     }
  }
Derek
  • 7,615
  • 5
  • 33
  • 58
  • In the scenario described by the OP, this would close all Java applications, right? This may not be a good solution... – helb Dec 03 '14 at 12:37
  • Forgot about running as java.exe - is his program compiled with a different exe name? Otherwise you would want to get a list of all the desktop windows and probably go by window caption. Also, there are ways to get the command line of a running process (see WMI). Does the command line include info about his actual process? – Derek Dec 03 '14 at 12:49
  • Meanwhile the OP posted that his application does **not** create a window. So your approach would not work anyway. – helb Dec 03 '14 at 12:51
0

You need to use GenerateConsoleCtrlEvent:

You can call this using P/Invoke.

This will allow you to generate a Ctrl+C event which your Java program will handle in the same way as it does if you press Ctrl+C in the command window.

Note: However this will only work if the process has a console. Java initialises the Ctrl+C handler on startup so you need to make sure the program has a console when it starts. You can do this by calling AllocConsole in the calling program to create a console, and the java program will inherit the console.

Ben
  • 34,935
  • 6
  • 74
  • 113
  • @giladrv Probably it doesn't work because the Java program doesn't have a console. If your .Net program is starting the java program, it can give itself a console and the Java program will inherit it. To try this, call AllocConsole using P/Invoke before you start the java program. http://msdn.microsoft.com/en-us/library/windows/desktop/ms681944(v=vs.85).aspx – Ben Dec 07 '14 at 08:53
  • The author here: http://stackoverflow.com/questions/16139571/how-to-cleanly-shut-down-a-console-app-started-with-process-start, claims it will not work, so I'm just going to implement a tcp server-client between the java and .net. – giladrv Dec 07 '14 at 08:55
  • @giladrv, the author there hasn't tried `AllocConsole`, because he isn't writing a service, and he specifically doesn't want it to have a console window. It would take two minutes to try, the TCP server more like two days.... :-) In any case if all you want is a shutdown signal, why not use an named Event object with `CreateEvent`? Set the event when it is time to shutdown, and test it periodically. – Ben Dec 07 '14 at 09:01
  • For now I only need the shutdown signal, but in the (near) future more complex communication will probably be necessary between these two components. – giladrv Dec 07 '14 at 09:04