+/* ---------------------------- the 95 way ------------------------------- */
+
+static BOOL CALLBACK
+find_child_console (HWND hwnd, struct nt_process_data *cp)
+{
+ DWORD thread_id;
+ DWORD process_id;
+
+ thread_id = GetWindowThreadProcessId (hwnd, &process_id);
+ if (process_id == cp->dwProcessId)
+ {
+ char window_class[32];
+
+ GetClassName (hwnd, window_class, sizeof (window_class));
+ if (strcmp (window_class,
+ msw_windows9x_p ()
+ ? "tty"
+ : "ConsoleWindowClass") == 0)
+ {
+ cp->hwnd = hwnd;
+ return FALSE;
+ }
+ }
+ /* keep looking */
+ return TRUE;
+}
+
+static int
+send_signal_the_95_way (struct nt_process_data *cp, int pid, int signo)
+{
+ HANDLE h_process;
+ int close_process = 0;
+ int rc = 1;
+
+ if (cp)
+ {
+ pid = cp->dwProcessId;
+ h_process = cp->h_process;
+
+ /* Try to locate console window for process. */
+ EnumWindows (find_child_console, (LPARAM) cp);
+ }
+ else
+ {
+ close_process = 1;
+ /* Try to open the process with required privileges */
+ h_process = OpenProcess (PROCESS_TERMINATE, FALSE, pid);
+ if (!h_process)
+ return 0;
+ }
+
+ if (signo == SIGINT)
+ {
+ if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd)
+ {
+ BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
+ BYTE vk_break_code = VK_CANCEL;
+ BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
+ HWND foreground_window;
+
+ if (break_scan_code == 0)
+ {
+ /* Fake Ctrl-C if we can't manage Ctrl-Break. */
+ vk_break_code = 'C';
+ break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
+ }
+
+ foreground_window = GetForegroundWindow ();
+ if (foreground_window)
+ {
+ /* NT 5.0, and apparently also Windows 98, will not allow
+ a Window to be set to foreground directly without the
+ user's involvement. The workaround is to attach
+ ourselves to the thread that owns the foreground
+ window, since that is the only thread that can set the
+ foreground window. */
+ DWORD foreground_thread, child_thread;
+ foreground_thread =
+ GetWindowThreadProcessId (foreground_window, NULL);
+ if (foreground_thread == GetCurrentThreadId ()
+ || !AttachThreadInput (GetCurrentThreadId (),
+ foreground_thread, TRUE))
+ foreground_thread = 0;
+
+ child_thread = GetWindowThreadProcessId (cp->hwnd, NULL);
+ if (child_thread == GetCurrentThreadId ()
+ || !AttachThreadInput (GetCurrentThreadId (),
+ child_thread, TRUE))
+ child_thread = 0;
+
+ /* Set the foreground window to the child. */
+ if (SetForegroundWindow (cp->hwnd))
+ {
+ /* Generate keystrokes as if user had typed Ctrl-Break or
+ Ctrl-C. */
+ keybd_event (VK_CONTROL, control_scan_code, 0, 0);
+ keybd_event (vk_break_code, break_scan_code,
+ (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0);
+ keybd_event (vk_break_code, break_scan_code,
+ (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY)
+ | KEYEVENTF_KEYUP, 0);
+ keybd_event (VK_CONTROL, control_scan_code,
+ KEYEVENTF_KEYUP, 0);
+
+ /* Sleep for a bit to give time for Emacs frame to respond
+ to focus change events (if Emacs was active app). */
+ Sleep (100);
+
+ SetForegroundWindow (foreground_window);
+ }
+ /* Detach from the foreground and child threads now that
+ the foreground switching is over. */
+ if (foreground_thread)
+ AttachThreadInput (GetCurrentThreadId (),
+ foreground_thread, FALSE);
+ if (child_thread)
+ AttachThreadInput (GetCurrentThreadId (),
+ child_thread, FALSE);
+ }
+ }
+ /* Ctrl-Break is NT equivalent of SIGINT. */
+ else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
+ {
+#if 0 /* FSF Emacs */
+ DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d "
+ "for pid %lu\n", GetLastError (), pid));
+ errno = EINVAL;
+#endif
+ rc = 0;
+ }
+ }
+ else
+ {
+ if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd)
+ {
+#if 1
+ if (msw_windows9x_p ())
+ {
+/*
+ Another possibility is to try terminating the VDM out-right by
+ calling the Shell VxD (id 0x17) V86 interface, function #4
+ "SHELL_Destroy_VM", ie.
+
+ mov edx,4
+ mov ebx,vm_handle
+ call shellapi
+
+ First need to determine the current VM handle, and then arrange for
+ the shellapi call to be made from the system vm (by using
+ Switch_VM_and_callback).
+
+ Could try to invoke DestroyVM through CallVxD.
+
+*/
+#if 0
+ /* On Win95, posting WM_QUIT causes the 16-bit subsystem
+ to hang when cmdproxy is used in conjunction with
+ command.com for an interactive shell. Posting
+ WM_CLOSE pops up a dialog that, when Yes is selected,
+ does the same thing. TerminateProcess is also less
+ than ideal in that subprocesses tend to stick around
+ until the machine is shutdown, but at least it
+ doesn't freeze the 16-bit subsystem. */
+ PostMessage (cp->hwnd, WM_QUIT, 0xff, 0);
+#endif
+ if (!TerminateProcess (h_process, 0xff))
+ {
+#if 0 /* FSF Emacs */
+ DebPrint (("sys_kill.TerminateProcess returned %d "
+ "for pid %lu\n", GetLastError (), pid));
+ errno = EINVAL;
+#endif
+ rc = 0;
+ }
+ }
+ else
+#endif
+ PostMessage (cp->hwnd, WM_CLOSE, 0, 0);
+ }
+ /* Kill the process. On W32 this doesn't kill child processes
+ so it doesn't work very well for shells which is why it's not
+ used in every case. */
+ else if (!TerminateProcess (h_process, 0xff))
+ {
+#if 0 /* FSF Emacs */
+ DebPrint (("sys_kill.TerminateProcess returned %d "
+ "for pid %lu\n", GetLastError (), pid));
+ errno = EINVAL;
+#endif
+ rc = 0;
+ }
+ }
+
+ if (close_process)
+ CloseHandle (h_process);
+
+ return rc;
+}
+
+/* -------------------------- all-OS functions ---------------------------- */
+
+static int
+send_signal (struct nt_process_data *cp, int pid, int signo)
+{
+ return send_signal_the_nt_way (cp, pid, signo)
+ || send_signal_the_95_way (cp, pid, signo);
+}
+