2011-10-12 156 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

相關問題