【问题标题】:Start a EXE file from a service and stop it by sending SIGBREAK从服务启动 EXE 文件并通过发送 SIGBREAK 停止它
【发布时间】:2011-10-12 14:37:48
【问题描述】:

我编写了一个启动 java.exe 或 ruby​​.exe 的服务(我知道有一些解决方案,但由于某些原因我需要自己的服务)。

到目前为止,该服务工作正常,我从注册表中收集我的配置,然后启动服务。当服务停止时,我得到我的进程并发送一个 .Kill()。 到目前为止,一切都很好。 但我发现,.Kill() 是一个问题,因为 ruby​​.exe(我使用瘦启动服务)或 java.exe(我用它启动 SOLR)侦听 tcp 套接字端口.如果此端口被使用并且我终止进程窗口将阻塞端口 72 秒(按设计)。

如果我从 shell 命令 shell 执行 solr:start 和 thin -start 并使用 Ctrl+C 停止它,进程将终止并且端口可立即使用。

所以我的猜测是:如果我设法将 ctrl-c 发送到进程,它会正确终止。

所以我找到了这个帖子How to Run an exe from windows service and stop service when the exe process quits?,其中发布了概念证明。 但是通过从窗口服务启动进程,我没有 windowHandle。

我这样开始我的服务:

m_process.StartInfo = new ProcessStartInfo
                                  {
                                      FileName = "java"
                                      , Arguments = arguments
                                      , UseShellExecute = true
                                      , WorkingDirectory = workDirectory
                                      , CreateNoWindow = false
                                  };
m_process.Start();

参数包含启动 SOLR 的码头数据或在 ruby​​ 案例中我使用“ruby.exe thin start ...”。

现在停止我尝试的服务:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32")]
public static extern int SetForegroundWindow(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

foreach (int i in m_processList)
  {
    MyLogEvent(Process.GetProcessById(i).MainModule.ModuleName);
    MyLogEvent(Process.GetProcessById(i).MainWindowTitle);
    try
    {
      IntPtr ptr = FindWindow(null, Process.GetProcessById(i).MainWindowTitle);
      {
        SetForegroundWindow(ptr);
        Thread.Sleep(1000);
        InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.CANCEL);
        // SendKeys.Send("^{BREAK}");
        Thread.Sleep(1000);
      }
      //Process.GetProcessById(i).Kill();
    }
    catch(Exception ex)
    {
      MyLogEvent(ex.ToString());
      Process.GetProcessById(i).Kill();
    }
  }

但由于我没有 WindowTitle,我想我什至没有窗口我无法像这样分配进程。

那么有人知道我如何分配进程并向它发送停止信号吗? 我可以忍受只是杀死进程,但这只是一个服务重启,如果不等待很长时间是不可能的。 感谢您提供任何提示、提示和解决方案。

【问题讨论】:

  • Windows 不做信号。那是 *nix 丑陋。
  • Pinvoke GenerateConsoleCtrlEvent().
  • 你试过Process.CloseMainWindow() (MSDN)吗?
  • 好像没有窗口,已经试过不同的窗口句柄了。

标签: c# service process


【解决方案1】:

GenerateConsoleCtrlEvent 可能有用

 m_process.StartInfo = new ProcessStartInfo
                              {
                                  FileName = "java"
                                  , Arguments = arguments
                                  , UseShellExecute = true
                                  , WorkingDirectory = workDirectory
                                  , CreateNoWindow = false
                              };
 var process = m_process.Start();

何时终止子应用程序...

 GenerateConsoleCtrlEvent(CTRL_C_EVENT, process.Id);

成员声明

 public const UInt32 CTRL_C_EVENT = 0;

[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent,
   uint dwProcessGroupId);     

【讨论】:

  • 我也试过了。但不得不使用 GenerateConsoleCtrlEvent(CtrlCEvent, (uint)Process.GetProcessById(i).Id); (转换为 uint),但 java.exe 仍在运行。
  • 我找到了这个。 github.com/fauna/mongrel/blob/master/projects/mongrel_service/…。 mongrel 服务是用 FreeBASIC 编写的,但它似乎可以工作。根据我对旧 Rails 系统的体验,停止服务会通过 ctrl+c 事件正确终止 ruby​​.exe。那么为什么 FBasic 不能访问控制台和 .NET 呢?!?!
  • 我终于放弃尝试了。控制台程序中的任何示例都有效。我还像 FreeBasic 服务在我的代码中一样添加了 AllocConsole(),结果相同。无论出于何种原因,似乎无法从服务中控制控制台窗口。伤心。
猜你喜欢
  • 2012-05-06
  • 1970-01-01
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 2013-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多