我使用
从c#启动了一个java程序...
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();
}
...
然后该过程持续运行,直到我希望它停止。 java程序有一个关闭钩子,应该能够捕获正常的kill信号。例如,如果我从bat脚本运行jar,然后在cmd窗口中按Ctrl + c将触发关闭挂钩,但关闭cmd窗口将终止进程而不触发关闭挂钩(类似于任务管理器中的End Process) )。
所以为了从C#停止java程序,我尝试了:
process.CloseMainWindow();
或
process.Kill();
CloseMainWindow方法对java进程没有影响,Kill终止它而不触发关闭钩子。那么我该怎样做才能从C#代码中优雅地关闭java程序? [我是否需要在我的Java程序中进行修改以拦截CloseMainWindow信号?有没有办法模仿C#的cmd窗口上Ctrl + c的行为?我必须在C#和Java代码之间创建一些通信路径,例如管道或套接字吗?]
P.S。 C#代码只是java代码的包装器,以便在Windows上作为服务运行它(我不能为此目的使用RunAsService等现有工具)。
该计划的一般说明: 我的java程序不会创建任何窗口。它有几个线程,主要是在循环中运行,只是等待连接,另一个线程在传入连接上执行特定任务,另一个线程从Web服务器定期更新,并且有关闭钩子。通常,程序从命令提示符(或linux上的终端)运行,并且仅在第一次加载时才接受用户输入,之后可以在没有更多用户输入的情况下再次运行它。程序将日志输出到文件。我的关机钩:
...
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
}
}
答案 0 :(得分:0)
这会尝试关闭所有记事本窗口。请注意,如果要保存,最终会收到提示。
[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);
}
}
答案 1 :(得分:0)
执行此操作的最佳方法是让您的C#程序获取Java程序的stdin句柄。这样,C#程序可以随时向Java程序发送消息,Java程序可以监听一条消息,要求它死掉。
这样做的好处是您不必担心关闭挂钩:程序可以在收到关闭消息时执行所需的任何处理。它也更加灵活:如果以后,您希望C#程序发送其他控制消息,可以轻松添加。
在Java方面,您需要一个单独的线程打开System.in
并从中读取,并在收到正确的消息时执行您需要的任何关闭。
在C#方面,看起来好像你想要
startInfo.RedirectStandardInput = true;
startInfo.UseShellExecute = false;
然后当你想发送信息时:
process.StandardInput.WriteLine(...some message...);
(但我是一名Java编码员,所以我不确定我是否在这里获得了C#。)
答案 2 :(得分:0)
您需要使用GenerateConsoleCtrlEvent
:
您可以使用P / Invoke调用此方法。
这将允许您生成一个Ctrl + C事件,Java程序将以与在命令窗口中按Ctrl + C时相同的方式处理该事件。
注意:但是,只有在进程有控制台的情况下,这才有效。 Java在启动时初始化Ctrl + C处理程序,因此您需要确保程序在启动时具有控制台。您可以通过调用调用程序中的AllocConsole
来创建控制台,并且java程序将继承控制台。