2011-10-12 139 views
0

我已经编写了一个启动java.exe或ruby.exe的服务(我知道有一些解决方案,但由于某些原因需要我自己的服务)。从服务启动一个EXE文件,并通过发送SIGBREAK来停止它

到目前为止,该服务的工作发现,我从注册表收集我的配置,然后启动服务。当服务停止时,我得到我的进程并发送.Kill()。 目前为止这么好。 但我发现,.Kill()是一个问题,因为ruby.exe(我使用thin来启动服务)或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(); 

如果参数contais码头数据开始SOLR或红宝石情况下,我用“ruby.exe薄开始......”。

现在就停止服务,我试过:

[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,我想我甚至不有一个窗口,我不能分配这样的过程。

那么有没有人有一个想法,我可以如何分配进程并发送停止信号给它? 我可以生活在只是杀死进程,但这只是一个服务重启不可能等待很长时间。 感谢您提供任何提示,提示和解决方案。

+0

Windows不会做信号。这是* nix丑陋。 – cHao

+0

Pinvoke GenerateConsoleCtrlEvent()。 –

+0

您是否尝试过'Process.CloseMainWindow()'([MSDN](http://msdn.microsoft.com/zh-cn/library/system.diagnostics.process.closemainwindow.aspx))? – AntonR

回答

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);  
+0

我也试过了。但不得不使用GenerateConsoleCtrlEvent(CtrlCEvent,(uint)Process.GetProcessById(i).Id); (转换为uint),但java.exe仍在运行。 – YvesR

+0

我找到了。 https://github.com/fauna/mongrel/blob/master/projects/mongrel_service/native/console_process.bas。杂种服务是用FreeBASIC编写的,但似乎有效。从我对旧的rails系统的看法,停止服务通过ctrl + c事件终止ruby.exe。那么为什么FBasic可以访问控制台和.NET呢?!?! – YvesR

+0

我终于放弃了尝试。控制台程序中的任何示例都可用。我还在我的代码中添加了像FreeBasic服务一样的AllocConsole(),结果相同。无论出于何种原因,似乎无法将控制台窗口控制在服务之外。伤心。 – YvesR

相关问题