Mercurial > hg > xemacs-beta
comparison src/process-nt.c @ 404:2f8bb876ab1d r21-2-32
Import from CVS: tag r21-2-32
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:16:07 +0200 |
parents | a86b2b5e0111 |
children | b8cc9ab3f761 |
comparison
equal
deleted
inserted
replaced
403:9f011ab08d48 | 404:2f8bb876ab1d |
---|---|
1 /* Asynchronous subprocess implementation for Win32 | 1 /* Asynchronous subprocess implementation for Win32 |
2 Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995 | 2 Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995 |
3 Free Software Foundation, Inc. | 3 Free Software Foundation, Inc. |
4 Copyright (C) 1995 Sun Microsystems, Inc. | 4 Copyright (C) 1995 Sun Microsystems, Inc. |
5 Copyright (C) 1995, 1996 Ben Wing. | 5 Copyright (C) 1995, 1996, 2000 Ben Wing. |
6 | 6 |
7 This file is part of XEmacs. | 7 This file is part of XEmacs. |
8 | 8 |
9 XEmacs is free software; you can redistribute it and/or modify it | 9 XEmacs is free software; you can redistribute it and/or modify it |
10 under the terms of the GNU General Public License as published by the | 10 under the terms of the GNU General Public License as published by the |
24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */ | 24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */ |
25 | 25 |
26 #include <config.h> | 26 #include <config.h> |
27 #include "lisp.h" | 27 #include "lisp.h" |
28 | 28 |
29 #include "console-msw.h" | |
29 #include "hash.h" | 30 #include "hash.h" |
30 #include "lstream.h" | 31 #include "lstream.h" |
31 #include "process.h" | 32 #include "process.h" |
32 #include "procimpl.h" | 33 #include "procimpl.h" |
33 #include "sysdep.h" | 34 #include "sysdep.h" |
34 | 35 |
35 #ifndef __MINGW32__ | |
36 #include <shellapi.h> | 36 #include <shellapi.h> |
37 #else | 37 #ifdef __MINGW32__ |
38 #include <errno.h> | 38 #include <errno.h> |
39 #endif | 39 #endif |
40 #include <signal.h> | 40 #include <signal.h> |
41 #ifdef HAVE_SOCKETS | 41 #ifdef HAVE_SOCKETS |
42 #include <winsock.h> | 42 #include <winsock.h> |
50 | 50 |
51 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */ | 51 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */ |
52 struct nt_process_data | 52 struct nt_process_data |
53 { | 53 { |
54 HANDLE h_process; | 54 HANDLE h_process; |
55 DWORD dwProcessId; | |
56 HWND hwnd; /* console window */ | |
55 int need_enable_child_signals; | 57 int need_enable_child_signals; |
56 }; | 58 }; |
59 | |
60 /* Control whether create_child causes the process to inherit Emacs' | |
61 console window, or be given a new one of its own. The default is | |
62 nil, to allow multiple DOS programs to run on Win95. Having separate | |
63 consoles also allows Emacs to cleanly terminate process groups. */ | |
64 Lisp_Object Vmswindows_start_process_share_console; | |
65 | |
66 /* Control whether create_child cause the process to inherit Emacs' | |
67 error mode setting. The default is t, to minimize the possibility of | |
68 subprocesses blocking when accessing unmounted drives. */ | |
69 Lisp_Object Vmswindows_start_process_inherit_error_mode; | |
57 | 70 |
58 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) | 71 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) |
59 | 72 |
60 /*-----------------------------------------------------------------------*/ | 73 /*-----------------------------------------------------------------------*/ |
61 /* Process helpers */ | 74 /* Process helpers */ |
66 HANDLE | 79 HANDLE |
67 get_nt_process_handle (Lisp_Process *p) | 80 get_nt_process_handle (Lisp_Process *p) |
68 { | 81 { |
69 return (NT_DATA (p)->h_process); | 82 return (NT_DATA (p)->h_process); |
70 } | 83 } |
84 | |
85 static struct Lisp_Process * | |
86 find_process_from_pid (DWORD pid) | |
87 { | |
88 Lisp_Object tail, proc; | |
89 | |
90 for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail)) | |
91 { | |
92 proc = XCAR (tail); | |
93 if (NT_DATA (XPROCESS (proc))->dwProcessId == pid) | |
94 return XPROCESS (proc); | |
95 } | |
96 return 0; | |
97 } | |
98 | |
71 | 99 |
72 /*-----------------------------------------------------------------------*/ | 100 /*-----------------------------------------------------------------------*/ |
73 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */ | 101 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */ |
74 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/ | 102 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/ |
75 /*-----------------------------------------------------------------------*/ | 103 /*-----------------------------------------------------------------------*/ |
222 | 250 |
223 /*-----------------------------------------------------------------------*/ | 251 /*-----------------------------------------------------------------------*/ |
224 /* Sending signals */ | 252 /* Sending signals */ |
225 /*-----------------------------------------------------------------------*/ | 253 /*-----------------------------------------------------------------------*/ |
226 | 254 |
255 /* ---------------------------- the NT way ------------------------------- */ | |
256 | |
227 /* | 257 /* |
228 * We handle the following signals: | 258 * We handle the following signals: |
229 * | 259 * |
230 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess | 260 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess |
231 * executed by the remote process | 261 * executed by the remote process |
285 /* | 315 /* |
286 * Send signal SIGNO to process H_PROCESS. | 316 * Send signal SIGNO to process H_PROCESS. |
287 * Return nonzero if successful. | 317 * Return nonzero if successful. |
288 */ | 318 */ |
289 | 319 |
290 /* This code assigns a return value of GetProcAddress to function pointers | |
291 of many different types. Instead of heavy obscure casts, we just disable | |
292 warnings about assignments to different function pointer types. */ | |
293 #pragma warning (disable : 4113) | |
294 | |
295 static int | 320 static int |
296 send_signal (HANDLE h_process, int signo) | 321 send_signal_the_nt_way (struct nt_process_data *cp, int pid, int signo) |
297 { | 322 { |
323 HANDLE h_process; | |
298 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 324 HMODULE h_kernel = GetModuleHandle ("kernel32"); |
325 int close_process = 0; | |
299 DWORD retval; | 326 DWORD retval; |
300 | 327 |
301 assert (h_kernel != NULL); | 328 assert (h_kernel != NULL); |
302 | 329 |
330 if (cp) | |
331 { | |
332 pid = cp->dwProcessId; | |
333 h_process = cp->h_process; | |
334 } | |
335 else | |
336 { | |
337 close_process = 1; | |
338 /* Try to open the process with required privileges */ | |
339 h_process = OpenProcess (PROCESS_CREATE_THREAD | |
340 | PROCESS_QUERY_INFORMATION | |
341 | PROCESS_VM_OPERATION | |
342 | PROCESS_VM_WRITE, | |
343 FALSE, pid); | |
344 if (!h_process) | |
345 return 0; | |
346 } | |
347 | |
303 switch (signo) | 348 switch (signo) |
304 { | 349 { |
305 case SIGKILL: | 350 case SIGKILL: |
306 case SIGTERM: | 351 case SIGTERM: |
307 case SIGQUIT: | 352 case SIGQUIT: |
308 case SIGHUP: | 353 case SIGHUP: |
309 { | 354 { |
310 sigkill_data d; | 355 sigkill_data d; |
311 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess"); | 356 |
357 d.adr_ExitProcess = | |
358 (void (WINAPI *) (UINT)) GetProcAddress (h_kernel, "ExitProcess"); | |
312 assert (d.adr_ExitProcess); | 359 assert (d.adr_ExitProcess); |
313 retval = run_in_other_process (h_process, | 360 retval = run_in_other_process (h_process, |
314 (LPTHREAD_START_ROUTINE)sigkill_proc, | 361 (LPTHREAD_START_ROUTINE)sigkill_proc, |
315 &d, sizeof (d)); | 362 &d, sizeof (d)); |
316 break; | 363 break; |
317 } | 364 } |
318 case SIGINT: | 365 case SIGINT: |
319 { | 366 { |
320 sigint_data d; | 367 sigint_data d; |
321 d.adr_GenerateConsoleCtrlEvent = | 368 d.adr_GenerateConsoleCtrlEvent = |
369 (BOOL (WINAPI *) (DWORD, DWORD)) | |
322 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); | 370 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); |
323 assert (d.adr_GenerateConsoleCtrlEvent); | 371 assert (d.adr_GenerateConsoleCtrlEvent); |
324 d.event = CTRL_C_EVENT; | 372 d.event = CTRL_C_EVENT; |
325 retval = run_in_other_process (h_process, | 373 retval = run_in_other_process (h_process, |
326 (LPTHREAD_START_ROUTINE)sigint_proc, | 374 (LPTHREAD_START_ROUTINE)sigint_proc, |
329 } | 377 } |
330 default: | 378 default: |
331 assert (0); | 379 assert (0); |
332 } | 380 } |
333 | 381 |
382 if (close_process) | |
383 CloseHandle (h_process); | |
334 return (int)retval > 0 ? 1 : 0; | 384 return (int)retval > 0 ? 1 : 0; |
335 } | 385 } |
336 | 386 |
337 /* | 387 /* |
338 * Enable CTRL_C_EVENT handling in a new child process | 388 * Enable CTRL_C_EVENT handling in a new child process |
343 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 393 HMODULE h_kernel = GetModuleHandle ("kernel32"); |
344 sig_enable_data d; | 394 sig_enable_data d; |
345 | 395 |
346 assert (h_kernel != NULL); | 396 assert (h_kernel != NULL); |
347 d.adr_SetConsoleCtrlHandler = | 397 d.adr_SetConsoleCtrlHandler = |
398 (BOOL (WINAPI *) (LPVOID, BOOL)) | |
348 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); | 399 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); |
349 assert (d.adr_SetConsoleCtrlHandler); | 400 assert (d.adr_SetConsoleCtrlHandler); |
350 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc, | 401 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc, |
351 &d, sizeof (d)); | 402 &d, sizeof (d)); |
352 } | 403 } |
353 | 404 |
354 #pragma warning (default : 4113) | 405 #pragma warning (default : 4113) |
355 | 406 |
407 /* ---------------------------- the 95 way ------------------------------- */ | |
408 | |
409 static BOOL CALLBACK | |
410 find_child_console (HWND hwnd, struct nt_process_data *cp) | |
411 { | |
412 DWORD thread_id; | |
413 DWORD process_id; | |
414 | |
415 thread_id = GetWindowThreadProcessId (hwnd, &process_id); | |
416 if (process_id == cp->dwProcessId) | |
417 { | |
418 char window_class[32]; | |
419 | |
420 GetClassName (hwnd, window_class, sizeof (window_class)); | |
421 if (strcmp (window_class, | |
422 msw_windows9x_p () | |
423 ? "tty" | |
424 : "ConsoleWindowClass") == 0) | |
425 { | |
426 cp->hwnd = hwnd; | |
427 return FALSE; | |
428 } | |
429 } | |
430 /* keep looking */ | |
431 return TRUE; | |
432 } | |
433 | |
434 static int | |
435 send_signal_the_95_way (struct nt_process_data *cp, int pid, int signo) | |
436 { | |
437 HANDLE h_process; | |
438 int close_process = 0; | |
439 int rc = 1; | |
440 | |
441 if (cp) | |
442 { | |
443 pid = cp->dwProcessId; | |
444 h_process = cp->h_process; | |
445 | |
446 /* Try to locate console window for process. */ | |
447 EnumWindows (find_child_console, (LPARAM) cp); | |
448 } | |
449 else | |
450 { | |
451 close_process = 1; | |
452 /* Try to open the process with required privileges */ | |
453 h_process = OpenProcess (PROCESS_TERMINATE, FALSE, pid); | |
454 if (!h_process) | |
455 return 0; | |
456 } | |
457 | |
458 if (signo == SIGINT) | |
459 { | |
460 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
461 { | |
462 BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0); | |
463 BYTE vk_break_code = VK_CANCEL; | |
464 BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | |
465 HWND foreground_window; | |
466 | |
467 if (break_scan_code == 0) | |
468 { | |
469 /* Fake Ctrl-C if we can't manage Ctrl-Break. */ | |
470 vk_break_code = 'C'; | |
471 break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | |
472 } | |
473 | |
474 foreground_window = GetForegroundWindow (); | |
475 if (foreground_window) | |
476 { | |
477 /* NT 5.0, and apparently also Windows 98, will not allow | |
478 a Window to be set to foreground directly without the | |
479 user's involvement. The workaround is to attach | |
480 ourselves to the thread that owns the foreground | |
481 window, since that is the only thread that can set the | |
482 foreground window. */ | |
483 DWORD foreground_thread, child_thread; | |
484 foreground_thread = | |
485 GetWindowThreadProcessId (foreground_window, NULL); | |
486 if (foreground_thread == GetCurrentThreadId () | |
487 || !AttachThreadInput (GetCurrentThreadId (), | |
488 foreground_thread, TRUE)) | |
489 foreground_thread = 0; | |
490 | |
491 child_thread = GetWindowThreadProcessId (cp->hwnd, NULL); | |
492 if (child_thread == GetCurrentThreadId () | |
493 || !AttachThreadInput (GetCurrentThreadId (), | |
494 child_thread, TRUE)) | |
495 child_thread = 0; | |
496 | |
497 /* Set the foreground window to the child. */ | |
498 if (SetForegroundWindow (cp->hwnd)) | |
499 { | |
500 /* Generate keystrokes as if user had typed Ctrl-Break or | |
501 Ctrl-C. */ | |
502 keybd_event (VK_CONTROL, control_scan_code, 0, 0); | |
503 keybd_event (vk_break_code, break_scan_code, | |
504 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0); | |
505 keybd_event (vk_break_code, break_scan_code, | |
506 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY) | |
507 | KEYEVENTF_KEYUP, 0); | |
508 keybd_event (VK_CONTROL, control_scan_code, | |
509 KEYEVENTF_KEYUP, 0); | |
510 | |
511 /* Sleep for a bit to give time for Emacs frame to respond | |
512 to focus change events (if Emacs was active app). */ | |
513 Sleep (100); | |
514 | |
515 SetForegroundWindow (foreground_window); | |
516 } | |
517 /* Detach from the foreground and child threads now that | |
518 the foreground switching is over. */ | |
519 if (foreground_thread) | |
520 AttachThreadInput (GetCurrentThreadId (), | |
521 foreground_thread, FALSE); | |
522 if (child_thread) | |
523 AttachThreadInput (GetCurrentThreadId (), | |
524 child_thread, FALSE); | |
525 } | |
526 } | |
527 /* Ctrl-Break is NT equivalent of SIGINT. */ | |
528 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid)) | |
529 { | |
530 #if 0 /* FSF Emacs */ | |
531 DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d " | |
532 "for pid %lu\n", GetLastError (), pid)); | |
533 errno = EINVAL; | |
534 #endif | |
535 rc = 0; | |
536 } | |
537 } | |
538 else | |
539 { | |
540 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
541 { | |
542 #if 1 | |
543 if (msw_windows9x_p ()) | |
544 { | |
545 /* | |
546 Another possibility is to try terminating the VDM out-right by | |
547 calling the Shell VxD (id 0x17) V86 interface, function #4 | |
548 "SHELL_Destroy_VM", ie. | |
549 | |
550 mov edx,4 | |
551 mov ebx,vm_handle | |
552 call shellapi | |
553 | |
554 First need to determine the current VM handle, and then arrange for | |
555 the shellapi call to be made from the system vm (by using | |
556 Switch_VM_and_callback). | |
557 | |
558 Could try to invoke DestroyVM through CallVxD. | |
559 | |
560 */ | |
561 #if 0 | |
562 /* On Win95, posting WM_QUIT causes the 16-bit subsystem | |
563 to hang when cmdproxy is used in conjunction with | |
564 command.com for an interactive shell. Posting | |
565 WM_CLOSE pops up a dialog that, when Yes is selected, | |
566 does the same thing. TerminateProcess is also less | |
567 than ideal in that subprocesses tend to stick around | |
568 until the machine is shutdown, but at least it | |
569 doesn't freeze the 16-bit subsystem. */ | |
570 PostMessage (cp->hwnd, WM_QUIT, 0xff, 0); | |
571 #endif | |
572 if (!TerminateProcess (h_process, 0xff)) | |
573 { | |
574 #if 0 /* FSF Emacs */ | |
575 DebPrint (("sys_kill.TerminateProcess returned %d " | |
576 "for pid %lu\n", GetLastError (), pid)); | |
577 errno = EINVAL; | |
578 #endif | |
579 rc = 0; | |
580 } | |
581 } | |
582 else | |
583 #endif | |
584 PostMessage (cp->hwnd, WM_CLOSE, 0, 0); | |
585 } | |
586 /* Kill the process. On W32 this doesn't kill child processes | |
587 so it doesn't work very well for shells which is why it's not | |
588 used in every case. */ | |
589 else if (!TerminateProcess (h_process, 0xff)) | |
590 { | |
591 #if 0 /* FSF Emacs */ | |
592 DebPrint (("sys_kill.TerminateProcess returned %d " | |
593 "for pid %lu\n", GetLastError (), pid)); | |
594 errno = EINVAL; | |
595 #endif | |
596 rc = 0; | |
597 } | |
598 } | |
599 | |
600 if (close_process) | |
601 CloseHandle (h_process); | |
602 | |
603 return rc; | |
604 } | |
605 | |
606 /* -------------------------- all-OS functions ---------------------------- */ | |
607 | |
608 static int | |
609 send_signal (struct nt_process_data *cp, int pid, int signo) | |
610 { | |
611 return send_signal_the_nt_way (cp, pid, signo) | |
612 || send_signal_the_95_way (cp, pid, signo); | |
613 } | |
614 | |
356 /* | 615 /* |
357 * Signal error if SIGNO is not supported | 616 * Signal error if SIGNO is not supported |
358 */ | 617 */ |
359 static void | 618 static void |
360 validate_signal_number (int signo) | 619 validate_signal_number (int signo) |
381 | 640 |
382 static void | 641 static void |
383 nt_finalize_process_data (Lisp_Process *p, int for_disksave) | 642 nt_finalize_process_data (Lisp_Process *p, int for_disksave) |
384 { | 643 { |
385 assert (!for_disksave); | 644 assert (!for_disksave); |
386 if (NT_DATA(p)->h_process) | 645 if (NT_DATA (p)->h_process) |
387 CloseHandle (NT_DATA(p)->h_process); | 646 CloseHandle (NT_DATA (p)->h_process); |
388 } | 647 } |
389 | 648 |
390 /* | 649 /* |
391 * Initialize XEmacs process implementation once | 650 * Initialize XEmacs process implementation once |
392 */ | 651 */ |
412 static void | 671 static void |
413 signal_cannot_launch (Lisp_Object image_file, DWORD err) | 672 signal_cannot_launch (Lisp_Object image_file, DWORD err) |
414 { | 673 { |
415 mswindows_set_errno (err); | 674 mswindows_set_errno (err); |
416 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); | 675 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); |
676 } | |
677 | |
678 static void | |
679 ensure_console_window_exists () | |
680 { | |
681 if (msw_windows9x_p ()) | |
682 msw_hide_console (); | |
417 } | 683 } |
418 | 684 |
419 static int | 685 static int |
420 nt_create_process (Lisp_Process *p, | 686 nt_create_process (Lisp_Process *p, |
421 Lisp_Object *argv, int nargv, | 687 Lisp_Object *argv, int nargv, |
593 /* Create process */ | 859 /* Create process */ |
594 { | 860 { |
595 STARTUPINFO si; | 861 STARTUPINFO si; |
596 PROCESS_INFORMATION pi; | 862 PROCESS_INFORMATION pi; |
597 DWORD err; | 863 DWORD err; |
864 DWORD flags; | |
598 | 865 |
599 xzero (si); | 866 xzero (si); |
600 si.dwFlags = STARTF_USESHOWWINDOW; | 867 si.dwFlags = STARTF_USESHOWWINDOW; |
601 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; | 868 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; |
602 if (do_io) | 869 if (do_io) |
605 si.hStdOutput = hprocout; | 872 si.hStdOutput = hprocout; |
606 si.hStdError = hprocerr; | 873 si.hStdError = hprocerr; |
607 si.dwFlags |= STARTF_USESTDHANDLES; | 874 si.dwFlags |= STARTF_USESTDHANDLES; |
608 } | 875 } |
609 | 876 |
610 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, | 877 flags = CREATE_SUSPENDED; |
611 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP | 878 if (msw_windows9x_p ()) |
612 | CREATE_SUSPENDED, | 879 flags |= (!NILP (Vmswindows_start_process_share_console) |
880 ? CREATE_NEW_PROCESS_GROUP | |
881 : CREATE_NEW_CONSOLE); | |
882 else | |
883 flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; | |
884 if (NILP (Vmswindows_start_process_inherit_error_mode)) | |
885 flags |= CREATE_DEFAULT_ERROR_MODE; | |
886 | |
887 ensure_console_window_exists (); | |
888 | |
889 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, flags, | |
613 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi) | 890 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi) |
614 ? 0 : GetLastError ()); | 891 ? 0 : GetLastError ()); |
615 | 892 |
616 if (do_io) | 893 if (do_io) |
617 { | 894 { |
634 | 911 |
635 /* The process started successfully */ | 912 /* The process started successfully */ |
636 if (do_io) | 913 if (do_io) |
637 { | 914 { |
638 NT_DATA(p)->h_process = pi.hProcess; | 915 NT_DATA(p)->h_process = pi.hProcess; |
916 NT_DATA(p)->dwProcessId = pi.dwProcessId; | |
639 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0); | 917 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0); |
640 } | 918 } |
641 else | 919 else |
642 { | 920 { |
643 /* Indicate as if the process has exited immediately. */ | 921 /* Indicate as if the process has exited immediately. */ |
787 { | 1065 { |
788 Lisp_Process *p = XPROCESS (proc); | 1066 Lisp_Process *p = XPROCESS (proc); |
789 | 1067 |
790 /* Enable child signals if necessary. This may lose the first | 1068 /* Enable child signals if necessary. This may lose the first |
791 but it's better than nothing. */ | 1069 but it's better than nothing. */ |
792 if (NT_DATA(p)->need_enable_child_signals > 0) | 1070 if (NT_DATA (p)->need_enable_child_signals > 0) |
793 { | 1071 { |
794 enable_child_signals(NT_DATA(p)->h_process); | 1072 enable_child_signals (NT_DATA(p)->h_process); |
795 NT_DATA(p)->need_enable_child_signals = 0; | 1073 NT_DATA (p)->need_enable_child_signals = 0; |
796 } | 1074 } |
797 | 1075 |
798 /* Signal error if SIGNO cannot be sent */ | 1076 /* Signal error if SIGNO cannot be sent */ |
799 validate_signal_number (signo); | 1077 validate_signal_number (signo); |
800 | 1078 |
801 /* Send signal */ | 1079 /* Send signal */ |
802 if (!send_signal (NT_DATA(p)->h_process, signo)) | 1080 if (!send_signal (NT_DATA (p), 0, signo)) |
803 error ("Cannot send signal to process"); | 1081 signal_simple_error ("Cannot send signal to process", proc); |
804 } | 1082 } |
805 | 1083 |
806 /* | 1084 /* |
807 * Kill any process in the system given its PID. | 1085 * Kill any process in the system given its PID. |
808 * | 1086 * |
810 * negative number upon failure | 1088 * negative number upon failure |
811 */ | 1089 */ |
812 static int | 1090 static int |
813 nt_kill_process_by_pid (int pid, int signo) | 1091 nt_kill_process_by_pid (int pid, int signo) |
814 { | 1092 { |
815 HANDLE h_process; | 1093 struct Lisp_Process *p; |
816 int send_result; | 1094 |
817 | |
818 /* Signal error if SIGNO cannot be sent */ | 1095 /* Signal error if SIGNO cannot be sent */ |
819 validate_signal_number (signo); | 1096 validate_signal_number (signo); |
820 | 1097 |
821 /* Try to open the process with required privileges */ | 1098 p = find_process_from_pid (pid); |
822 h_process = OpenProcess (PROCESS_CREATE_THREAD | 1099 return send_signal (p ? NT_DATA (p) : 0, pid, signo) ? 0 : -1; |
823 | PROCESS_QUERY_INFORMATION | |
824 | PROCESS_VM_OPERATION | |
825 | PROCESS_VM_WRITE, | |
826 FALSE, pid); | |
827 if (h_process == NULL) | |
828 return -1; | |
829 | |
830 send_result = send_signal (h_process, signo); | |
831 | |
832 CloseHandle (h_process); | |
833 | |
834 return send_result ? 0 : -1; | |
835 } | 1100 } |
836 | 1101 |
837 /*-----------------------------------------------------------------------*/ | 1102 /*-----------------------------------------------------------------------*/ |
838 /* Sockets connections */ | 1103 /* Sockets connections */ |
839 /*-----------------------------------------------------------------------*/ | 1104 /*-----------------------------------------------------------------------*/ |
940 differences are in status display and process deletion. A network | 1205 differences are in status display and process deletion. A network |
941 connection has no PID; you cannot signal it. All you can do is | 1206 connection has no PID; you cannot signal it. All you can do is |
942 deactivate and close it via delete-process */ | 1207 deactivate and close it via delete-process */ |
943 | 1208 |
944 static void | 1209 static void |
945 nt_open_network_stream (Lisp_Object name, Lisp_Object host, Lisp_Object service, | 1210 nt_open_network_stream (Lisp_Object name, Lisp_Object host, |
1211 Lisp_Object service, | |
946 Lisp_Object protocol, void** vinfd, void** voutfd) | 1212 Lisp_Object protocol, void** vinfd, void** voutfd) |
947 { | 1213 { |
1214 /* !!#### not Mule-ized */ | |
948 struct sockaddr_in address; | 1215 struct sockaddr_in address; |
949 SOCKET s; | 1216 SOCKET s; |
950 int port; | 1217 int port; |
951 int retval; | 1218 int retval; |
952 | 1219 |
953 CHECK_STRING (host); | 1220 CHECK_STRING (host); |
954 | 1221 |
955 if (!EQ (protocol, Qtcp)) | 1222 if (!EQ (protocol, Qtcp)) |
956 error ("Unsupported protocol \"%s\"", | 1223 signal_simple_error ("Unsupported protocol", protocol); |
957 string_data (symbol_name (XSYMBOL (protocol)))); | |
958 | 1224 |
959 if (INTP (service)) | 1225 if (INTP (service)) |
960 port = htons ((unsigned short) XINT (service)); | 1226 port = htons ((unsigned short) XINT (service)); |
961 else | 1227 else |
962 { | 1228 { |
963 struct servent *svc_info; | 1229 struct servent *svc_info; |
964 CHECK_STRING (service); | 1230 CHECK_STRING (service); |
965 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp"); | 1231 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp"); |
966 if (svc_info == 0) | 1232 if (svc_info == 0) |
967 error ("Unknown service \"%s\"", XSTRING_DATA (service)); | 1233 signal_simple_error ("Unknown service", service); |
968 port = svc_info->s_port; | 1234 port = svc_info->s_port; |
969 } | 1235 } |
970 | 1236 |
971 get_internet_address (host, &address, ERROR_ME); | 1237 get_internet_address (host, &address, ERROR_ME); |
972 address.sin_port = port; | 1238 address.sin_port = port; |
1024 0, FALSE, DUPLICATE_SAME_ACCESS); | 1290 0, FALSE, DUPLICATE_SAME_ACCESS); |
1025 return; | 1291 return; |
1026 | 1292 |
1027 connect_failed: | 1293 connect_failed: |
1028 closesocket (s); | 1294 closesocket (s); |
1029 if (INTP (service)) { | 1295 if (INTP (service)) |
1030 warn_when_safe(Qstream, Qwarning, | 1296 { |
1031 "failure to open network stream to host \"%s\" for service \"%d\"", | 1297 warn_when_safe (Qstream, Qwarning, |
1032 XSTRING_DATA (host), | 1298 "failure to open network stream to host \"%s\" for service \"%d\"", |
1033 (unsigned short) XINT (service)); | 1299 XSTRING_DATA (host), |
1034 } | 1300 (unsigned short) XINT (service)); |
1035 else { | 1301 } |
1036 warn_when_safe(Qstream, Qwarning, | 1302 else |
1037 "failure to open network stream to host \"%s\" for service \"%s\"", | 1303 { |
1038 XSTRING_DATA (host), | 1304 warn_when_safe (Qstream, Qwarning, |
1039 XSTRING_DATA (service)); | 1305 "failure to open network stream to host \"%s\" for service \"%s\"", |
1040 } | 1306 XSTRING_DATA (host), |
1307 XSTRING_DATA (service)); | |
1308 } | |
1041 report_file_error ("connection failed", list2 (host, name)); | 1309 report_file_error ("connection failed", list2 (host, name)); |
1042 } | 1310 } |
1043 | 1311 |
1044 #endif | 1312 #endif |
1045 | 1313 |
1075 } | 1343 } |
1076 | 1344 |
1077 void | 1345 void |
1078 vars_of_process_nt (void) | 1346 vars_of_process_nt (void) |
1079 { | 1347 { |
1080 } | 1348 DEFVAR_LISP ("mswindows-start-process-share-console", |
1349 &Vmswindows_start_process_share_console /* | |
1350 When nil, new child processes are given a new console. | |
1351 When non-nil, they share the Emacs console; this has the limitation of | |
1352 allowing only only DOS subprocess to run at a time (whether started directly | |
1353 or indirectly by Emacs), and preventing Emacs from cleanly terminating the | |
1354 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't | |
1355 otherwise respond to interrupts from Emacs. | |
1356 */ ); | |
1357 Vmswindows_start_process_share_console = Qnil; | |
1358 | |
1359 DEFVAR_LISP ("mswindows-start-process-inherit-error-mode", | |
1360 &Vmswindows_start_process_inherit_error_mode /* | |
1361 "When nil, new child processes revert to the default error mode. | |
1362 When non-nil, they inherit their error mode setting from Emacs, which stops | |
1363 them blocking when trying to access unmounted drives etc. | |
1364 */ ); | |
1365 Vmswindows_start_process_inherit_error_mode = Qt; | |
1366 } |