Saya telah (di masa lalu) yang ditulis cross-platform (Windows / Unix) aplikasi yang, ketika mulai dari baris perintah, menangani-diketik pengguna Ctrl- Ckombinasi dengan cara yang sama (yaitu untuk mengakhiri aplikasi bersih).
Apakah mungkin pada Windows untuk mengirim Ctrl- C/ SIGINT / setara dengan proses dari proses lain (tidak terkait) untuk meminta agar dihentikan dengan bersih (memberinya kesempatan untuk merapikan sumber daya, dll.)?
jstack
dapat digunakan dengan andal sebagai gantinya untuk masalah khusus ini: stackoverflow.com/a/47723393/603516Jawaban:
Solusi terdekat yang saya temukan adalah aplikasi pihak ketiga SendSignal . Penulis mencantumkan kode sumber dan yang dapat dieksekusi. Saya telah memverifikasi bahwa itu berfungsi di bawah jendela 64-bit (berjalan sebagai program 32-bit, mematikan program 32-bit lainnya), tetapi saya belum menemukan cara untuk menyematkan kode ke dalam program windows (baik 32-bit atau 64-bit).
Bagaimana itu bekerja:
(Awali dengan
start
jika menjalankannya dalam file batch.)sumber
Saya telah melakukan beberapa penelitian seputar topik ini, yang ternyata lebih populer dari yang saya perkirakan. Balasan KindDragon adalah salah satu poin penting.
Saya menulis posting blog yang lebih panjang tentang topik tersebut dan membuat program demo yang berfungsi, yang mendemonstrasikan penggunaan jenis sistem ini untuk menutup aplikasi baris perintah dalam beberapa mode yang bagus. Posting itu juga mencantumkan tautan eksternal yang saya gunakan dalam penelitian saya.
Singkatnya, program demo tersebut melakukan hal berikut:
Sunting: Solusi yang diubah dari KindDragon untuk mereka yang tertarik dengan kode di sini dan sekarang. Jika Anda berencana untuk memulai program lain setelah menghentikan yang pertama, Anda harus mengaktifkan kembali penanganan Ctrl-C, jika tidak, proses selanjutnya akan mewarisi status nonaktif induknya dan tidak akan merespons Ctrl-C.
[DllImport("kernel32.dll", SetLastError = true)] static extern bool AttachConsole(uint dwProcessId); [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] static extern bool FreeConsole(); [DllImport("kernel32.dll")] static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType); // Enumerated type for the control messages sent to the handler routine enum CtrlTypes : uint { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT } [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId); public void StopProgram(Process proc) { //This does not require the console window to be visible. if (AttachConsole((uint)proc.Id)) { // Disable Ctrl-C handling for our program SetConsoleCtrlHandler(null, true); GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); //Moved this command up on suggestion from Timothy Jannace (see comments below) FreeConsole(); // Must wait here. If we don't and re-enable Ctrl-C // handling below too fast, we might terminate ourselves. proc.WaitForExit(2000); //Re-enable Ctrl-C handling or any subsequently started //programs will inherit the disabled state. SetConsoleCtrlHandler(null, false); } }
Juga, rencanakan solusi darurat jika
AttachConsole()
atau sinyal yang dikirim gagal, misalnya tidur maka ini:if (!proc.HasExited) { try { proc.Kill(); } catch (InvalidOperationException e){} }
sumber
wait()
saya menghapus Re-enable Ctrl-C (SetConsoleCtrlHandler(null, false);
). Saya melakukan beberapa tes (beberapa panggilan, juga pada proses yang sudah dihentikan) dan saya tidak menemukan efek samping (belum?).Saya kira saya agak terlambat dalam pertanyaan ini tetapi saya akan tetap menulis sesuatu untuk siapa pun yang memiliki masalah yang sama. Ini adalah jawaban yang sama seperti yang saya berikan untuk pertanyaan ini .
Masalah saya adalah bahwa saya ingin aplikasi saya menjadi aplikasi GUI tetapi proses yang dijalankan harus dijalankan di latar belakang tanpa jendela konsol interaktif yang terpasang. Saya pikir solusi ini juga harus berfungsi ketika proses induk adalah proses konsol. Anda mungkin harus menghapus bendera "CREATE_NO_WINDOW".
Saya berhasil menyelesaikan ini menggunakan GenerateConsoleCtrlEvent () dengan aplikasi pembungkus. Bagian yang sulit adalah bahwa dokumentasinya tidak begitu jelas tentang bagaimana tepatnya itu dapat digunakan dan jebakannya.
Solusi saya didasarkan pada apa yang dijelaskan di sini . Tapi itu juga tidak benar-benar menjelaskan semua detail dan dengan kesalahan, jadi inilah detail tentang cara membuatnya berfungsi.
Buat aplikasi pembantu baru "Helper.exe". Aplikasi ini akan berada di antara aplikasi Anda (induk) dan proses anak yang ingin Anda tutup. Ini juga akan menciptakan proses anak yang sebenarnya. Anda harus memiliki proses "orang tengah" ini atau GenerateConsoleCtrlEvent () akan gagal.
Gunakan beberapa jenis mekanisme IPC untuk berkomunikasi dari induk ke proses helper bahwa helper harus menutup proses anak. Saat helper mendapatkan acara ini, ia memanggil "GenerateConsoleCtrlEvent (CTRL_BREAK, 0)" yang menutup sendiri dan proses turunannya. Saya menggunakan objek acara untuk ini sendiri yang diselesaikan oleh orang tua ketika ingin membatalkan proses anak.
Untuk membuat Helper.exe Anda, buatlah dengan CREATE_NO_WINDOW dan CREATE_NEW_PROCESS_GROUP. Dan saat membuat proses anak, buatlah tanpa flag (0) yang berarti itu akan mendapatkan konsol dari induknya. Gagal melakukan ini akan menyebabkan acara diabaikan.
Sangat penting bahwa setiap langkah dilakukan seperti ini. Saya telah mencoba semua jenis kombinasi tetapi kombinasi ini adalah satu-satunya yang berhasil. Anda tidak dapat mengirim acara CTRL_C. Ini akan mengembalikan kesuksesan tetapi akan diabaikan oleh prosesnya. CTRL_BREAK adalah satu-satunya yang berhasil. Tidak terlalu penting karena keduanya akan memanggil ExitProcess () pada akhirnya.
Anda juga tidak dapat memanggil GenerateConsoleCtrlEvent () dengan id grup proses dari id proses anak secara langsung memungkinkan proses pembantu untuk terus hidup. Ini juga akan gagal.
Saya menghabiskan sepanjang hari mencoba untuk membuat ini bekerja. Solusi ini berfungsi untuk saya, tetapi jika ada yang ingin ditambahkan, harap lakukan. Saya mencari banyak orang dengan masalah serupa tetapi tidak ada solusi pasti untuk masalah tersebut. Cara kerja GenerateConsoleCtrlEvent () juga agak aneh jadi jika ada yang tahu lebih banyak detailnya, silakan bagikan.
sumber
Edit:
Untuk Aplikasi GUI, cara "normal" untuk menangani ini dalam pengembangan Windows adalah dengan mengirim pesan WM_CLOSE ke jendela utama proses.
Untuk aplikasi konsol, Anda perlu menggunakan SetConsoleCtrlHandler untuk menambahkan
CTRL_C_EVENT
.Jika aplikasi tidak menghormati itu, Anda dapat menelepon TerminateProcess .
sumber
Entah bagaimana
GenerateConsoleCtrlEvent()
mengembalikan kesalahan jika Anda memanggilnya untuk proses lain, tetapi Anda dapat melampirkan ke aplikasi konsol lain dan mengirim acara ke semua proses anak.sumber
Berikut adalah kode yang saya gunakan di aplikasi C ++ saya.
Poin positif:
Poin negatif:
Contoh penggunaan:
sumber
sumber
Ini harus dibuat sangat jelas karena saat ini belum. Ada versi SendSignal yang dimodifikasi dan dikompilasi untuk mengirim Ctrl-C (secara default hanya mengirim Ctrl + Break). Berikut beberapa binari:
Saya juga telah mencerminkan file-file itu untuk berjaga-jaga:
versi 32-bit: https://www.dropbox.com/s/r96jxglhkm4sjz2/SendSignalCtrlC.exe?dl=0
64-bit: https://www.dropbox.com /s/hhe0io7mcgcle1c/SendSignalCtrlC64.exe?dl=0
Penafian: Saya tidak membuat file-file itu. Tidak ada modifikasi yang dilakukan pada file asli yang dikompilasi. Satu-satunya platform yang diuji adalah Windows 7 64-bit. Direkomendasikan untuk menyesuaikan sumber yang tersedia di http://www.latenighthacking.com/projects/2003/sendSignal/ dan mengkompilasinya sendiri.
sumber
Di Java, menggunakan JNA dengan pustaka Kernel32.dll, mirip dengan solusi C ++. Menjalankan metode utama CtrlCSender sebagai Proses yang hanya mendapatkan konsol dari proses untuk mengirim acara Ctrl + C dan menghasilkan acara tersebut. Karena berjalan secara terpisah tanpa konsol, acara Ctrl + C tidak perlu dinonaktifkan dan diaktifkan lagi.
CtrlCSender.java - Berdasarkan Nemo1024 dan KindDragon jawaban.
Diberikan ID proses yang diketahui, aplikasi penghibur ini akan melampirkan konsol dari proses yang ditargetkan dan menghasilkan Peristiwa CTRL + C di atasnya.
Aplikasi Utama - Menjalankan CtrlCSender sebagai proses penghiburan terpisah
sumber
Iya. The
windows-kill
proyek tidak persis apa yang Anda inginkan:sumber
Solusi yang saya temukan dari sini cukup sederhana jika Anda memiliki python 3.x tersedia di baris perintah Anda. Pertama, simpan file (ctrl_c.py) dengan isinya:
Kemudian hubungi:
Jika itu tidak berhasil, saya sarankan untuk mencoba proyek windows-kill: https://github.com/alirdn/windows-kill
sumber
Seorang teman saya menyarankan cara yang sama sekali berbeda untuk memecahkan masalah dan itu berhasil untuk saya. Gunakan vbscript seperti di bawah ini. Ini dimulai dan aplikasi, biarkan berjalan selama 7 detik dan tutup menggunakan ctrl + c .
Contoh VBScript
sumber
Saya menemukan semua ini terlalu rumit dan menggunakan SendKeys untuk mengirim CTRL- Ckeystroke ke jendela baris perintah (yaitu jendela cmd.exe) sebagai solusi.
sumber
sumber
SIGINT dapat dikirim ke program menggunakan windows-kill , dengan sintaks
windows-kill -SIGINT PID
, di manaPID
dapat diperoleh dengan pslist Microsoft .Mengenai menangkap SIGINT, jika program Anda menggunakan Python maka Anda dapat mengimplementasikan pemrosesan / penangkapan SIGINT seperti dalam solusi ini .
sumber
Berdasarkan id proses, kita dapat mengirim sinyal ke proses untuk menghentikan secara paksa atau anggun atau sinyal lainnya.
Buat daftar semua proses:
Untuk menghentikan proses:
Rincian:
http://tweaks.com/windows/39559/kill-processes-from-command-prompt/
sumber