Mercurial > hg > xemacs-beta
comparison src/process-nt.c @ 442:abe6d1db359e r21-2-36
Import from CVS: tag r21-2-36
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:35:02 +0200 |
parents | 8de8e3f6228a |
children | 0784d089fdc9 |
comparison
equal
deleted
inserted
replaced
441:72a7cfa4a488 | 442:abe6d1db359e |
---|---|
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 "buffer.h" | |
30 #include "console-msw.h" | |
29 #include "hash.h" | 31 #include "hash.h" |
30 #include "lstream.h" | 32 #include "lstream.h" |
33 #include "nt.h" | |
31 #include "process.h" | 34 #include "process.h" |
32 #include "procimpl.h" | 35 #include "procimpl.h" |
33 #include "sysdep.h" | 36 #include "sysdep.h" |
34 | 37 |
35 #ifndef __MINGW32__ | |
36 #include <shellapi.h> | 38 #include <shellapi.h> |
37 #else | |
38 #include <errno.h> | 39 #include <errno.h> |
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> |
43 #endif | 43 #endif |
44 | 44 |
45 /* Bound by win32-native.el */ | |
46 Lisp_Object Qmswindows_construct_process_command_line; | |
47 | |
45 /* Arbitrary size limit for code fragments passed to run_in_other_process */ | 48 /* Arbitrary size limit for code fragments passed to run_in_other_process */ |
46 #define FRAGMENT_CODE_SIZE 32 | 49 #define FRAGMENT_CODE_SIZE 32 |
47 | 50 |
48 /* Bound by winnt.el */ | |
49 Lisp_Object Qnt_quote_process_args; | |
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 int need_enable_child_signals; | 55 DWORD dwProcessId; |
56 HWND hwnd; /* console window */ | |
56 }; | 57 }; |
58 | |
59 /* Control how args are quoted to ensure correct parsing by child | |
60 process. */ | |
61 Lisp_Object Vmswindows_quote_process_args; | |
62 | |
63 /* Control whether create_child causes the process to inherit Emacs' | |
64 console window, or be given a new one of its own. The default is | |
65 nil, to allow multiple DOS programs to run on Win95. Having separate | |
66 consoles also allows Emacs to cleanly terminate process groups. */ | |
67 Lisp_Object Vmswindows_start_process_share_console; | |
68 | |
69 /* Control whether create_child cause the process to inherit Emacs' | |
70 error mode setting. The default is t, to minimize the possibility of | |
71 subprocesses blocking when accessing unmounted drives. */ | |
72 Lisp_Object Vmswindows_start_process_inherit_error_mode; | |
57 | 73 |
58 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) | 74 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) |
59 | 75 |
60 /*-----------------------------------------------------------------------*/ | 76 /*-----------------------------------------------------------------------*/ |
61 /* Process helpers */ | 77 /* Process helpers */ |
66 HANDLE | 82 HANDLE |
67 get_nt_process_handle (Lisp_Process *p) | 83 get_nt_process_handle (Lisp_Process *p) |
68 { | 84 { |
69 return (NT_DATA (p)->h_process); | 85 return (NT_DATA (p)->h_process); |
70 } | 86 } |
87 | |
88 static struct Lisp_Process * | |
89 find_process_from_pid (DWORD pid) | |
90 { | |
91 Lisp_Object tail, proc; | |
92 | |
93 for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail)) | |
94 { | |
95 proc = XCAR (tail); | |
96 if (NT_DATA (XPROCESS (proc))->dwProcessId == pid) | |
97 return XPROCESS (proc); | |
98 } | |
99 return 0; | |
100 } | |
101 | |
71 | 102 |
72 /*-----------------------------------------------------------------------*/ | 103 /*-----------------------------------------------------------------------*/ |
73 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */ | 104 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */ |
74 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/ | 105 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/ |
75 /*-----------------------------------------------------------------------*/ | 106 /*-----------------------------------------------------------------------*/ |
166 run_in_other_process (HANDLE h_process, | 197 run_in_other_process (HANDLE h_process, |
167 LPTHREAD_START_ROUTINE routine, | 198 LPTHREAD_START_ROUTINE routine, |
168 LPVOID data, size_t data_size) | 199 LPVOID data, size_t data_size) |
169 { | 200 { |
170 process_memory pm; | 201 process_memory pm; |
171 CONST size_t code_size = FRAGMENT_CODE_SIZE; | 202 const size_t code_size = FRAGMENT_CODE_SIZE; |
172 /* Need at most 3 extra bytes of memory, for data alignment */ | 203 /* Need at most 3 extra bytes of memory, for data alignment */ |
173 size_t total_size = code_size + data_size + 3; | 204 size_t total_size = code_size + data_size + 3; |
174 LPVOID remote_data; | 205 LPVOID remote_data; |
175 HANDLE h_thread; | 206 HANDLE h_thread; |
176 DWORD dw_unused; | 207 DWORD dw_unused; |
221 } | 252 } |
222 | 253 |
223 /*-----------------------------------------------------------------------*/ | 254 /*-----------------------------------------------------------------------*/ |
224 /* Sending signals */ | 255 /* Sending signals */ |
225 /*-----------------------------------------------------------------------*/ | 256 /*-----------------------------------------------------------------------*/ |
257 | |
258 /* ---------------------------- the NT way ------------------------------- */ | |
226 | 259 |
227 /* | 260 /* |
228 * We handle the following signals: | 261 * We handle the following signals: |
229 * | 262 * |
230 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess | 263 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess |
285 /* | 318 /* |
286 * Send signal SIGNO to process H_PROCESS. | 319 * Send signal SIGNO to process H_PROCESS. |
287 * Return nonzero if successful. | 320 * Return nonzero if successful. |
288 */ | 321 */ |
289 | 322 |
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 | 323 static int |
296 send_signal (HANDLE h_process, int signo) | 324 send_signal_the_nt_way (struct nt_process_data *cp, int pid, int signo) |
297 { | 325 { |
326 HANDLE h_process; | |
298 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 327 HMODULE h_kernel = GetModuleHandle ("kernel32"); |
328 int close_process = 0; | |
299 DWORD retval; | 329 DWORD retval; |
300 | 330 |
301 assert (h_kernel != NULL); | 331 assert (h_kernel != NULL); |
302 | 332 |
333 if (cp) | |
334 { | |
335 pid = cp->dwProcessId; | |
336 h_process = cp->h_process; | |
337 } | |
338 else | |
339 { | |
340 close_process = 1; | |
341 /* Try to open the process with required privileges */ | |
342 h_process = OpenProcess (PROCESS_CREATE_THREAD | |
343 | PROCESS_QUERY_INFORMATION | |
344 | PROCESS_VM_OPERATION | |
345 | PROCESS_VM_WRITE, | |
346 FALSE, pid); | |
347 if (!h_process) | |
348 return 0; | |
349 } | |
350 | |
303 switch (signo) | 351 switch (signo) |
304 { | 352 { |
305 case SIGKILL: | 353 case SIGKILL: |
306 case SIGTERM: | 354 case SIGTERM: |
307 case SIGQUIT: | 355 case SIGQUIT: |
308 case SIGHUP: | 356 case SIGHUP: |
309 { | 357 { |
310 sigkill_data d; | 358 sigkill_data d; |
311 d.adr_ExitProcess = GetProcAddress (h_kernel, "ExitProcess"); | 359 |
360 d.adr_ExitProcess = | |
361 (void (WINAPI *) (UINT)) GetProcAddress (h_kernel, "ExitProcess"); | |
312 assert (d.adr_ExitProcess); | 362 assert (d.adr_ExitProcess); |
313 retval = run_in_other_process (h_process, | 363 retval = run_in_other_process (h_process, |
314 (LPTHREAD_START_ROUTINE)sigkill_proc, | 364 (LPTHREAD_START_ROUTINE)sigkill_proc, |
315 &d, sizeof (d)); | 365 &d, sizeof (d)); |
316 break; | 366 break; |
317 } | 367 } |
318 case SIGINT: | 368 case SIGINT: |
319 { | 369 { |
320 sigint_data d; | 370 sigint_data d; |
321 d.adr_GenerateConsoleCtrlEvent = | 371 d.adr_GenerateConsoleCtrlEvent = |
372 (BOOL (WINAPI *) (DWORD, DWORD)) | |
322 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); | 373 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); |
323 assert (d.adr_GenerateConsoleCtrlEvent); | 374 assert (d.adr_GenerateConsoleCtrlEvent); |
324 d.event = CTRL_C_EVENT; | 375 d.event = CTRL_C_EVENT; |
325 retval = run_in_other_process (h_process, | 376 retval = run_in_other_process (h_process, |
326 (LPTHREAD_START_ROUTINE)sigint_proc, | 377 (LPTHREAD_START_ROUTINE)sigint_proc, |
329 } | 380 } |
330 default: | 381 default: |
331 assert (0); | 382 assert (0); |
332 } | 383 } |
333 | 384 |
385 if (close_process) | |
386 CloseHandle (h_process); | |
334 return (int)retval > 0 ? 1 : 0; | 387 return (int)retval > 0 ? 1 : 0; |
335 } | 388 } |
336 | 389 |
337 /* | 390 /* |
338 * Enable CTRL_C_EVENT handling in a new child process | 391 * Enable CTRL_C_EVENT handling in a new child process |
343 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 396 HMODULE h_kernel = GetModuleHandle ("kernel32"); |
344 sig_enable_data d; | 397 sig_enable_data d; |
345 | 398 |
346 assert (h_kernel != NULL); | 399 assert (h_kernel != NULL); |
347 d.adr_SetConsoleCtrlHandler = | 400 d.adr_SetConsoleCtrlHandler = |
401 (BOOL (WINAPI *) (LPVOID, BOOL)) | |
348 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); | 402 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); |
349 assert (d.adr_SetConsoleCtrlHandler); | 403 assert (d.adr_SetConsoleCtrlHandler); |
350 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc, | 404 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc, |
351 &d, sizeof (d)); | 405 &d, sizeof (d)); |
352 } | 406 } |
353 | 407 |
354 #pragma warning (default : 4113) | 408 #pragma warning (default : 4113) |
355 | 409 |
410 /* ---------------------------- the 95 way ------------------------------- */ | |
411 | |
412 static BOOL CALLBACK | |
413 find_child_console (HWND hwnd, long putada) | |
414 { | |
415 DWORD thread_id; | |
416 DWORD process_id; | |
417 struct nt_process_data *cp = (struct nt_process_data *) putada; | |
418 | |
419 thread_id = GetWindowThreadProcessId (hwnd, &process_id); | |
420 if (process_id == cp->dwProcessId) | |
421 { | |
422 char window_class[32]; | |
423 | |
424 GetClassName (hwnd, window_class, sizeof (window_class)); | |
425 if (strcmp (window_class, | |
426 mswindows_windows9x_p () | |
427 ? "tty" | |
428 : "ConsoleWindowClass") == 0) | |
429 { | |
430 cp->hwnd = hwnd; | |
431 return FALSE; | |
432 } | |
433 } | |
434 /* keep looking */ | |
435 return TRUE; | |
436 } | |
437 | |
438 static int | |
439 send_signal_the_95_way (struct nt_process_data *cp, int pid, int signo) | |
440 { | |
441 HANDLE h_process; | |
442 int close_process = 0; | |
443 int rc = 1; | |
444 | |
445 if (cp) | |
446 { | |
447 pid = cp->dwProcessId; | |
448 h_process = cp->h_process; | |
449 | |
450 /* Try to locate console window for process. */ | |
451 EnumWindows (find_child_console, (LPARAM) cp); | |
452 } | |
453 else | |
454 { | |
455 close_process = 1; | |
456 /* Try to open the process with required privileges */ | |
457 h_process = OpenProcess (PROCESS_TERMINATE, FALSE, pid); | |
458 if (!h_process) | |
459 return 0; | |
460 } | |
461 | |
462 if (signo == SIGINT) | |
463 { | |
464 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
465 { | |
466 BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0); | |
467 BYTE vk_break_code = VK_CANCEL; | |
468 BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | |
469 HWND foreground_window; | |
470 | |
471 if (break_scan_code == 0) | |
472 { | |
473 /* Fake Ctrl-C if we can't manage Ctrl-Break. */ | |
474 vk_break_code = 'C'; | |
475 break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | |
476 } | |
477 | |
478 foreground_window = GetForegroundWindow (); | |
479 if (foreground_window) | |
480 { | |
481 /* NT 5.0, and apparently also Windows 98, will not allow | |
482 a Window to be set to foreground directly without the | |
483 user's involvement. The workaround is to attach | |
484 ourselves to the thread that owns the foreground | |
485 window, since that is the only thread that can set the | |
486 foreground window. */ | |
487 DWORD foreground_thread, child_thread; | |
488 foreground_thread = | |
489 GetWindowThreadProcessId (foreground_window, NULL); | |
490 if (foreground_thread == GetCurrentThreadId () | |
491 || !AttachThreadInput (GetCurrentThreadId (), | |
492 foreground_thread, TRUE)) | |
493 foreground_thread = 0; | |
494 | |
495 child_thread = GetWindowThreadProcessId (cp->hwnd, NULL); | |
496 if (child_thread == GetCurrentThreadId () | |
497 || !AttachThreadInput (GetCurrentThreadId (), | |
498 child_thread, TRUE)) | |
499 child_thread = 0; | |
500 | |
501 /* Set the foreground window to the child. */ | |
502 if (SetForegroundWindow (cp->hwnd)) | |
503 { | |
504 /* Generate keystrokes as if user had typed Ctrl-Break or | |
505 Ctrl-C. */ | |
506 keybd_event (VK_CONTROL, control_scan_code, 0, 0); | |
507 keybd_event (vk_break_code, break_scan_code, | |
508 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0); | |
509 keybd_event (vk_break_code, break_scan_code, | |
510 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY) | |
511 | KEYEVENTF_KEYUP, 0); | |
512 keybd_event (VK_CONTROL, control_scan_code, | |
513 KEYEVENTF_KEYUP, 0); | |
514 | |
515 /* Sleep for a bit to give time for Emacs frame to respond | |
516 to focus change events (if Emacs was active app). */ | |
517 Sleep (100); | |
518 | |
519 SetForegroundWindow (foreground_window); | |
520 } | |
521 /* Detach from the foreground and child threads now that | |
522 the foreground switching is over. */ | |
523 if (foreground_thread) | |
524 AttachThreadInput (GetCurrentThreadId (), | |
525 foreground_thread, FALSE); | |
526 if (child_thread) | |
527 AttachThreadInput (GetCurrentThreadId (), | |
528 child_thread, FALSE); | |
529 } | |
530 } | |
531 /* Ctrl-Break is NT equivalent of SIGINT. */ | |
532 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid)) | |
533 { | |
534 #if 0 /* FSF Emacs */ | |
535 DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d " | |
536 "for pid %lu\n", GetLastError (), pid)); | |
537 errno = EINVAL; | |
538 #endif | |
539 rc = 0; | |
540 } | |
541 } | |
542 else | |
543 { | |
544 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
545 { | |
546 #if 1 | |
547 if (mswindows_windows9x_p ()) | |
548 { | |
549 /* | |
550 Another possibility is to try terminating the VDM out-right by | |
551 calling the Shell VxD (id 0x17) V86 interface, function #4 | |
552 "SHELL_Destroy_VM", ie. | |
553 | |
554 mov edx,4 | |
555 mov ebx,vm_handle | |
556 call shellapi | |
557 | |
558 First need to determine the current VM handle, and then arrange for | |
559 the shellapi call to be made from the system vm (by using | |
560 Switch_VM_and_callback). | |
561 | |
562 Could try to invoke DestroyVM through CallVxD. | |
563 | |
564 */ | |
565 #if 0 | |
566 /* On Win95, posting WM_QUIT causes the 16-bit subsystem | |
567 to hang when cmdproxy is used in conjunction with | |
568 command.com for an interactive shell. Posting | |
569 WM_CLOSE pops up a dialog that, when Yes is selected, | |
570 does the same thing. TerminateProcess is also less | |
571 than ideal in that subprocesses tend to stick around | |
572 until the machine is shutdown, but at least it | |
573 doesn't freeze the 16-bit subsystem. */ | |
574 PostMessage (cp->hwnd, WM_QUIT, 0xff, 0); | |
575 #endif | |
576 if (!TerminateProcess (h_process, 0xff)) | |
577 { | |
578 #if 0 /* FSF Emacs */ | |
579 DebPrint (("sys_kill.TerminateProcess returned %d " | |
580 "for pid %lu\n", GetLastError (), pid)); | |
581 errno = EINVAL; | |
582 #endif | |
583 rc = 0; | |
584 } | |
585 } | |
586 else | |
587 #endif | |
588 PostMessage (cp->hwnd, WM_CLOSE, 0, 0); | |
589 } | |
590 /* Kill the process. On W32 this doesn't kill child processes | |
591 so it doesn't work very well for shells which is why it's not | |
592 used in every case. */ | |
593 else if (!TerminateProcess (h_process, 0xff)) | |
594 { | |
595 #if 0 /* FSF Emacs */ | |
596 DebPrint (("sys_kill.TerminateProcess returned %d " | |
597 "for pid %lu\n", GetLastError (), pid)); | |
598 errno = EINVAL; | |
599 #endif | |
600 rc = 0; | |
601 } | |
602 } | |
603 | |
604 if (close_process) | |
605 CloseHandle (h_process); | |
606 | |
607 return rc; | |
608 } | |
609 | |
610 /* -------------------------- all-OS functions ---------------------------- */ | |
611 | |
612 static int | |
613 send_signal (struct nt_process_data *cp, int pid, int signo) | |
614 { | |
615 return (!mswindows_windows9x_p () && send_signal_the_nt_way (cp, pid, signo)) | |
616 || send_signal_the_95_way (cp, pid, signo); | |
617 } | |
618 | |
356 /* | 619 /* |
357 * Signal error if SIGNO is not supported | 620 * Signal error if SIGNO is not supported |
358 */ | 621 */ |
359 static void | 622 static void |
360 validate_signal_number (int signo) | 623 validate_signal_number (int signo) |
361 { | 624 { |
362 if (signo != SIGKILL && signo != SIGTERM | 625 if (signo != SIGKILL && signo != SIGTERM |
363 && signo != SIGQUIT && signo != SIGINT | 626 && signo != SIGQUIT && signo != SIGINT |
364 && signo != SIGHUP) | 627 && signo != SIGHUP) |
365 signal_simple_error ("Signal number not supported", make_int (signo)); | 628 invalid_argument ("Signal number not supported", make_int (signo)); |
366 } | 629 } |
367 | 630 |
368 /*-----------------------------------------------------------------------*/ | 631 /*-----------------------------------------------------------------------*/ |
369 /* Process methods */ | 632 /* Process methods */ |
370 /*-----------------------------------------------------------------------*/ | 633 /*-----------------------------------------------------------------------*/ |
381 | 644 |
382 static void | 645 static void |
383 nt_finalize_process_data (Lisp_Process *p, int for_disksave) | 646 nt_finalize_process_data (Lisp_Process *p, int for_disksave) |
384 { | 647 { |
385 assert (!for_disksave); | 648 assert (!for_disksave); |
386 if (NT_DATA(p)->h_process) | 649 if (NT_DATA (p)->h_process) |
387 CloseHandle (NT_DATA(p)->h_process); | 650 CloseHandle (NT_DATA (p)->h_process); |
388 } | 651 } |
389 | 652 |
390 /* | 653 /* |
391 * Initialize XEmacs process implementation once | 654 * Initialize XEmacs process implementation once |
392 */ | 655 */ |
411 | 674 |
412 static void | 675 static void |
413 signal_cannot_launch (Lisp_Object image_file, DWORD err) | 676 signal_cannot_launch (Lisp_Object image_file, DWORD err) |
414 { | 677 { |
415 mswindows_set_errno (err); | 678 mswindows_set_errno (err); |
416 signal_simple_error_2 ("Error starting", image_file, lisp_strerror (errno)); | 679 report_file_error ("Error starting", image_file); |
680 } | |
681 | |
682 static void | |
683 ensure_console_window_exists (void) | |
684 { | |
685 if (mswindows_windows9x_p ()) | |
686 mswindows_hide_console (); | |
687 } | |
688 | |
689 int | |
690 compare_env (const void *strp1, const void *strp2) | |
691 { | |
692 const char *str1 = *(const char**)strp1, *str2 = *(const char**)strp2; | |
693 | |
694 while (*str1 && *str2 && *str1 != '=' && *str2 != '=') | |
695 { | |
696 if ((*str1) > (*str2)) | |
697 return 1; | |
698 else if ((*str1) < (*str2)) | |
699 return -1; | |
700 str1++, str2++; | |
701 } | |
702 | |
703 if (*str1 == '=' && *str2 == '=') | |
704 return 0; | |
705 else if (*str1 == '=') | |
706 return -1; | |
707 else | |
708 return 1; | |
417 } | 709 } |
418 | 710 |
419 static int | 711 static int |
420 nt_create_process (Lisp_Process *p, | 712 nt_create_process (Lisp_Process *p, |
421 Lisp_Object *argv, int nargv, | 713 Lisp_Object *argv, int nargv, |
422 Lisp_Object program, Lisp_Object cur_dir) | 714 Lisp_Object program, Lisp_Object cur_dir) |
423 { | 715 { |
716 /* Synched up with sys_spawnve in FSF 20.6. Significantly different | |
717 but still synchable. */ | |
424 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr; | 718 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr; |
425 LPTSTR command_line; | 719 Extbyte *command_line; |
426 BOOL do_io, windowed; | 720 BOOL do_io, windowed; |
427 char *proc_env; | 721 char *proc_env; |
428 | 722 |
723 /* No need to DOS-ize the filename; expand-file-name (called prior) | |
724 already does this. */ | |
725 | |
429 /* Find out whether the application is windowed or not */ | 726 /* Find out whether the application is windowed or not */ |
430 { | 727 if (xSHGetFileInfoA) |
431 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most | 728 { |
432 errors. This leads to bogus error message. */ | 729 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most |
433 DWORD image_type; | 730 errors. This leads to bogus error message. */ |
434 char *p = strrchr ((char *)XSTRING_DATA (program), '.'); | 731 DWORD image_type; |
435 if (p != NULL && | 732 char *p = strrchr ((char *)XSTRING_DATA (program), '.'); |
436 (stricmp (p, ".exe") == 0 || | 733 if (p != NULL && |
437 stricmp (p, ".com") == 0 || | 734 (stricmp (p, ".exe") == 0 || |
438 stricmp (p, ".bat") == 0 || | 735 stricmp (p, ".com") == 0 || |
439 stricmp (p, ".cmd") == 0)) | 736 stricmp (p, ".bat") == 0 || |
440 { | 737 stricmp (p, ".cmd") == 0)) |
441 image_type = SHGetFileInfo ((char *)XSTRING_DATA (program), 0,NULL, | 738 { |
442 0, SHGFI_EXETYPE); | 739 image_type = xSHGetFileInfoA ((char *)XSTRING_DATA (program), 0,NULL, |
443 } | 740 0, SHGFI_EXETYPE); |
444 else | 741 } |
445 { | 742 else |
446 char progname[MAX_PATH]; | 743 { |
447 sprintf (progname, "%s.exe", (char *)XSTRING_DATA (program)); | 744 char progname[MAX_PATH]; |
448 image_type = SHGetFileInfo (progname, 0, NULL, 0, SHGFI_EXETYPE); | 745 sprintf (progname, "%s.exe", (char *)XSTRING_DATA (program)); |
449 } | 746 image_type = xSHGetFileInfoA (progname, 0, NULL, 0, SHGFI_EXETYPE); |
450 if (image_type == 0) | 747 } |
451 signal_cannot_launch (program, (GetLastError () == ERROR_FILE_NOT_FOUND | 748 if (image_type == 0) |
452 ? ERROR_BAD_FORMAT : GetLastError ())); | 749 signal_cannot_launch (program, (GetLastError () == ERROR_FILE_NOT_FOUND |
453 windowed = HIWORD (image_type) != 0; | 750 ? ERROR_BAD_FORMAT : GetLastError ())); |
454 } | 751 windowed = HIWORD (image_type) != 0; |
752 } | |
753 else /* NT 3.5; we have no idea so just guess. */ | |
754 windowed = 0; | |
455 | 755 |
456 /* Decide whether to do I/O on process handles, or just mark the | 756 /* Decide whether to do I/O on process handles, or just mark the |
457 process exited immediately upon successful launching. We do I/O if the | 757 process exited immediately upon successful launching. We do I/O if the |
458 process is a console one, or if it is windowed but windowed_process_io | 758 process is a console one, or if it is windowed but windowed_process_io |
459 is non-zero */ | 759 is non-zero */ |
471 | 771 |
472 CreatePipe (&hprocin, &hmyshove, &sa, 0); | 772 CreatePipe (&hprocin, &hmyshove, &sa, 0); |
473 CreatePipe (&hmyslurp, &hprocout, &sa, 0); | 773 CreatePipe (&hmyslurp, &hprocout, &sa, 0); |
474 | 774 |
475 /* Duplicate the stdout handle for use as stderr */ | 775 /* Duplicate the stdout handle for use as stderr */ |
476 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), &hprocerr, | 776 DuplicateHandle(GetCurrentProcess(), hprocout, GetCurrentProcess(), |
477 0, TRUE, DUPLICATE_SAME_ACCESS); | 777 &hprocerr, 0, TRUE, DUPLICATE_SAME_ACCESS); |
478 | 778 |
479 /* Stupid Win32 allows to create a pipe with *both* ends either | 779 /* Stupid Win32 allows to create a pipe with *both* ends either |
480 inheritable or not. We need process ends inheritable, and local | 780 inheritable or not. We need process ends inheritable, and local |
481 ends not inheritable. */ | 781 ends not inheritable. */ |
482 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp, | 782 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), |
483 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | 783 &htmp, 0, FALSE, |
784 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
484 hmyshove = htmp; | 785 hmyshove = htmp; |
485 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), &htmp, | 786 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), |
486 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | 787 &htmp, 0, FALSE, |
788 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
487 hmyslurp = htmp; | 789 hmyslurp = htmp; |
488 } | 790 } |
489 | 791 |
490 /* Convert an argv vector into Win32 style command line by a call to | 792 /* Convert an argv vector into Win32 style command line by a call to |
491 lisp function `nt-quote-process-args' which see (in winnt.el)*/ | 793 lisp function `mswindows-construct-process-command-line' |
794 (in win32-native.el) */ | |
492 { | 795 { |
493 int i; | 796 int i; |
494 Lisp_Object args_or_ret = Qnil; | 797 Lisp_Object args_or_ret = Qnil; |
495 struct gcpro gcpro1; | 798 struct gcpro gcpro1; |
496 | 799 |
499 for (i = 0; i < nargv; ++i) | 802 for (i = 0; i < nargv; ++i) |
500 args_or_ret = Fcons (*argv++, args_or_ret); | 803 args_or_ret = Fcons (*argv++, args_or_ret); |
501 args_or_ret = Fnreverse (args_or_ret); | 804 args_or_ret = Fnreverse (args_or_ret); |
502 args_or_ret = Fcons (program, args_or_ret); | 805 args_or_ret = Fcons (program, args_or_ret); |
503 | 806 |
504 args_or_ret = call1 (Qnt_quote_process_args, args_or_ret); | 807 args_or_ret = call1 (Qmswindows_construct_process_command_line, |
808 args_or_ret); | |
505 | 809 |
506 if (!STRINGP (args_or_ret)) | 810 if (!STRINGP (args_or_ret)) |
507 /* Luser wrote his/her own clever version */ | 811 /* Luser wrote his/her own clever version */ |
508 error ("Bogus return value from `nt-quote-process-args'"); | 812 invalid_argument |
509 | 813 ("Bogus return value from `mswindows-construct-process-command-line'", |
510 command_line = alloca_array (char, (XSTRING_LENGTH (program) | 814 args_or_ret); |
511 + XSTRING_LENGTH (args_or_ret) + 2)); | 815 |
512 strcpy (command_line, XSTRING_DATA (program)); | 816 LISP_STRING_TO_EXTERNAL (args_or_ret, command_line, Qmswindows_tstr); |
513 strcat (command_line, " "); | |
514 strcat (command_line, XSTRING_DATA (args_or_ret)); | |
515 | 817 |
516 UNGCPRO; /* args_or_ret */ | 818 UNGCPRO; /* args_or_ret */ |
517 } | 819 } |
518 | 820 |
519 /* Set `proc_env' to a nul-separated array of the strings in | 821 /* Set `proc_env' to a nul-separated array of the strings in |
520 Vprocess_environment terminated by 2 nuls. */ | 822 Vprocess_environment terminated by 2 nuls. */ |
521 | 823 |
522 { | 824 { |
523 extern int compare_env (const char **strp1, const char **strp2); | |
524 char **env; | 825 char **env; |
525 REGISTER Lisp_Object tem; | 826 REGISTER Lisp_Object tem; |
526 REGISTER char **new_env; | 827 REGISTER char **new_env; |
527 REGISTER int new_length = 0, i, new_space; | 828 REGISTER int new_length = 0, i, new_space; |
528 char *penv; | 829 char *penv; |
530 for (tem = Vprocess_environment; | 831 for (tem = Vprocess_environment; |
531 (CONSP (tem) | 832 (CONSP (tem) |
532 && STRINGP (XCAR (tem))); | 833 && STRINGP (XCAR (tem))); |
533 tem = XCDR (tem)) | 834 tem = XCDR (tem)) |
534 new_length++; | 835 new_length++; |
836 | |
837 /* FSF adds an extra env var to hold the current process ID of the | |
838 Emacs process. Apparently this is used only by emacsserver.c, | |
839 which we have superseded to gnuserv.c. (#### Does it work under | |
840 MS Windows?) | |
841 | |
842 sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d", | |
843 GetCurrentProcessId ()); | |
844 arglen += strlen (ppid_env_var_buffer) + 1; | |
845 numenv++; | |
846 */ | |
535 | 847 |
536 /* new_length + 1 to include terminating 0. */ | 848 /* new_length + 1 to include terminating 0. */ |
537 env = new_env = alloca_array (char *, new_length + 1); | 849 env = new_env = alloca_array (char *, new_length + 1); |
538 | 850 |
539 /* Copy the Vprocess_environment strings into new_env. */ | 851 /* Copy the Vprocess_environment strings into new_env. */ |
579 new_space += strlen(env[i]) + 1; | 891 new_space += strlen(env[i]) + 1; |
580 } | 892 } |
581 new_space++; | 893 new_space++; |
582 | 894 |
583 /* Allocate space and copy variables into it */ | 895 /* Allocate space and copy variables into it */ |
584 penv = proc_env = alloca(new_space); | 896 penv = proc_env = (char*) alloca(new_space); |
585 for (i = 0; i < new_length; i++) | 897 for (i = 0; i < new_length; i++) |
586 { | 898 { |
587 strcpy(penv, env[i]); | 899 strcpy(penv, env[i]); |
588 penv += strlen(env[i]) + 1; | 900 penv += strlen(env[i]) + 1; |
589 } | 901 } |
590 *penv = 0; | 902 *penv = 0; |
591 } | 903 } |
904 | |
905 #if 0 | |
906 /* #### we need to port this. */ | |
907 /* On Windows 95, if cmdname is a DOS app, we invoke a helper | |
908 application to start it by specifying the helper app as cmdname, | |
909 while leaving the real app name as argv[0]. */ | |
910 if (is_dos_app) | |
911 { | |
912 cmdname = (char*) alloca (MAXPATHLEN); | |
913 if (egetenv ("CMDPROXY")) | |
914 strcpy ((char*)cmdname, egetenv ("CMDPROXY")); | |
915 else | |
916 { | |
917 strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory)); | |
918 strcat ((char*)cmdname, "cmdproxy.exe"); | |
919 } | |
920 } | |
921 #endif | |
592 | 922 |
593 /* Create process */ | 923 /* Create process */ |
594 { | 924 { |
595 STARTUPINFO si; | 925 STARTUPINFO si; |
596 PROCESS_INFORMATION pi; | 926 PROCESS_INFORMATION pi; |
597 DWORD err; | 927 DWORD err; |
928 DWORD flags; | |
598 | 929 |
599 xzero (si); | 930 xzero (si); |
600 si.dwFlags = STARTF_USESHOWWINDOW; | 931 si.dwFlags = STARTF_USESHOWWINDOW; |
601 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; | 932 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; |
602 if (do_io) | 933 if (do_io) |
605 si.hStdOutput = hprocout; | 936 si.hStdOutput = hprocout; |
606 si.hStdError = hprocerr; | 937 si.hStdError = hprocerr; |
607 si.dwFlags |= STARTF_USESTDHANDLES; | 938 si.dwFlags |= STARTF_USESTDHANDLES; |
608 } | 939 } |
609 | 940 |
610 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, | 941 flags = CREATE_SUSPENDED; |
611 CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP | 942 if (mswindows_windows9x_p ()) |
612 | CREATE_SUSPENDED, | 943 flags |= (!NILP (Vmswindows_start_process_share_console) |
944 ? CREATE_NEW_PROCESS_GROUP | |
945 : CREATE_NEW_CONSOLE); | |
946 else | |
947 flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; | |
948 if (NILP (Vmswindows_start_process_inherit_error_mode)) | |
949 flags |= CREATE_DEFAULT_ERROR_MODE; | |
950 | |
951 ensure_console_window_exists (); | |
952 | |
953 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, flags, | |
613 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi) | 954 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi) |
614 ? 0 : GetLastError ()); | 955 ? 0 : GetLastError ()); |
615 | 956 |
616 if (do_io) | 957 if (do_io) |
617 { | 958 { |
634 | 975 |
635 /* The process started successfully */ | 976 /* The process started successfully */ |
636 if (do_io) | 977 if (do_io) |
637 { | 978 { |
638 NT_DATA(p)->h_process = pi.hProcess; | 979 NT_DATA(p)->h_process = pi.hProcess; |
980 NT_DATA(p)->dwProcessId = pi.dwProcessId; | |
639 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0); | 981 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0); |
640 } | 982 } |
641 else | 983 else |
642 { | 984 { |
643 /* Indicate as if the process has exited immediately. */ | 985 /* Indicate as if the process has exited immediately. */ |
644 p->status_symbol = Qexit; | 986 p->status_symbol = Qexit; |
645 CloseHandle (pi.hProcess); | 987 CloseHandle (pi.hProcess); |
646 } | 988 } |
647 | 989 |
990 if (!windowed) | |
991 enable_child_signals (pi.hProcess); | |
992 | |
648 ResumeThread (pi.hThread); | 993 ResumeThread (pi.hThread); |
649 CloseHandle (pi.hThread); | 994 CloseHandle (pi.hThread); |
650 | |
651 /* Remember to enable child signals later if this is not a windowed | |
652 app. Can't do it right now because that screws up the MKS Toolkit | |
653 shell. */ | |
654 if (!windowed) | |
655 { | |
656 NT_DATA(p)->need_enable_child_signals = 10; | |
657 kick_status_notify (); | |
658 } | |
659 | 995 |
660 return ((int)pi.dwProcessId); | 996 return ((int)pi.dwProcessId); |
661 } | 997 } |
662 } | 998 } |
663 | 999 |
671 | 1007 |
672 static void | 1008 static void |
673 nt_update_status_if_terminated (Lisp_Process* p) | 1009 nt_update_status_if_terminated (Lisp_Process* p) |
674 { | 1010 { |
675 DWORD exit_code; | 1011 DWORD exit_code; |
676 | |
677 if (NT_DATA(p)->need_enable_child_signals > 1) | |
678 { | |
679 NT_DATA(p)->need_enable_child_signals -= 1; | |
680 kick_status_notify (); | |
681 } | |
682 else if (NT_DATA(p)->need_enable_child_signals == 1) | |
683 { | |
684 enable_child_signals(NT_DATA(p)->h_process); | |
685 NT_DATA(p)->need_enable_child_signals = 0; | |
686 } | |
687 | |
688 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) | 1012 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) |
689 && exit_code != STILL_ACTIVE) | 1013 && exit_code != STILL_ACTIVE) |
690 { | 1014 { |
691 p->tick++; | 1015 p->tick++; |
692 p->core_dumped = 0; | 1016 p->core_dumped = 0; |
720 Lisp_Process *volatile p = XPROCESS (proc); | 1044 Lisp_Process *volatile p = XPROCESS (proc); |
721 | 1045 |
722 /* use a reasonable-sized buffer (somewhere around the size of the | 1046 /* use a reasonable-sized buffer (somewhere around the size of the |
723 stream buffer) so as to avoid inundating the stream with blocked | 1047 stream buffer) so as to avoid inundating the stream with blocked |
724 data. */ | 1048 data. */ |
725 Bufbyte chunkbuf[128]; | 1049 Bufbyte chunkbuf[512]; |
726 Bytecount chunklen; | 1050 Bytecount chunklen; |
727 | 1051 |
728 while (1) | 1052 while (1) |
729 { | 1053 { |
730 ssize_t writeret; | 1054 ssize_t writeret; |
731 | 1055 |
732 chunklen = Lstream_read (lstream, chunkbuf, 128); | 1056 chunklen = Lstream_read (lstream, chunkbuf, 512); |
733 if (chunklen <= 0) | 1057 if (chunklen <= 0) |
734 break; /* perhaps should abort() if < 0? | 1058 break; /* perhaps should abort() if < 0? |
735 This should never happen. */ | 1059 This should never happen. */ |
736 | 1060 |
737 /* Lstream_write() will never successfully write less than the | 1061 /* Lstream_write() will never successfully write less than the |
746 p->exit_code = ERROR_BROKEN_PIPE; | 1070 p->exit_code = ERROR_BROKEN_PIPE; |
747 p->core_dumped = 0; | 1071 p->core_dumped = 0; |
748 p->tick++; | 1072 p->tick++; |
749 process_tick++; | 1073 process_tick++; |
750 deactivate_process (*((Lisp_Object *) (&vol_proc))); | 1074 deactivate_process (*((Lisp_Object *) (&vol_proc))); |
751 error ("Broken pipe error sending to process %s; closed it", | 1075 invalid_operation ("Broken pipe error sending to process; closed it", |
752 XSTRING_DATA (p->name)); | 1076 p->name); |
753 } | 1077 } |
754 | 1078 |
755 { | 1079 { |
756 int wait_ms = 25; | 1080 int wait_ms = 25; |
757 while (Lstream_was_blocked_p (XLSTREAM (p->pipe_outstream))) | 1081 while (Lstream_was_blocked_p (XLSTREAM (p->pipe_outstream))) |
785 nt_kill_child_process (Lisp_Object proc, int signo, | 1109 nt_kill_child_process (Lisp_Object proc, int signo, |
786 int current_group, int nomsg) | 1110 int current_group, int nomsg) |
787 { | 1111 { |
788 Lisp_Process *p = XPROCESS (proc); | 1112 Lisp_Process *p = XPROCESS (proc); |
789 | 1113 |
790 /* Enable child signals if necessary. This may lose the first | |
791 but it's better than nothing. */ | |
792 if (NT_DATA(p)->need_enable_child_signals > 0) | |
793 { | |
794 enable_child_signals(NT_DATA(p)->h_process); | |
795 NT_DATA(p)->need_enable_child_signals = 0; | |
796 } | |
797 | |
798 /* Signal error if SIGNO cannot be sent */ | 1114 /* Signal error if SIGNO cannot be sent */ |
799 validate_signal_number (signo); | 1115 validate_signal_number (signo); |
800 | 1116 |
801 /* Send signal */ | 1117 /* Send signal */ |
802 if (!send_signal (NT_DATA(p)->h_process, signo)) | 1118 if (!send_signal (NT_DATA (p), 0, signo)) |
803 error ("Cannot send signal to process"); | 1119 invalid_operation ("Cannot send signal to process", proc); |
804 } | 1120 } |
805 | 1121 |
806 /* | 1122 /* |
807 * Kill any process in the system given its PID. | 1123 * Kill any process in the system given its PID |
808 * | 1124 * |
809 * Returns zero if a signal successfully sent, or | 1125 * Returns zero if a signal successfully sent, or |
810 * negative number upon failure | 1126 * negative number upon failure |
811 */ | 1127 */ |
812 static int | 1128 static int |
813 nt_kill_process_by_pid (int pid, int signo) | 1129 nt_kill_process_by_pid (int pid, int signo) |
814 { | 1130 { |
815 HANDLE h_process; | 1131 struct Lisp_Process *p; |
816 int send_result; | 1132 |
817 | |
818 /* Signal error if SIGNO cannot be sent */ | 1133 /* Signal error if SIGNO cannot be sent */ |
819 validate_signal_number (signo); | 1134 validate_signal_number (signo); |
820 | 1135 |
821 /* Try to open the process with required privileges */ | 1136 p = find_process_from_pid (pid); |
822 h_process = OpenProcess (PROCESS_CREATE_THREAD | 1137 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 } | 1138 } |
836 | 1139 |
837 /*-----------------------------------------------------------------------*/ | 1140 /*-----------------------------------------------------------------------*/ |
838 /* Sockets connections */ | 1141 /* Sockets connections */ |
839 /*-----------------------------------------------------------------------*/ | 1142 /*-----------------------------------------------------------------------*/ |
940 differences are in status display and process deletion. A network | 1243 differences are in status display and process deletion. A network |
941 connection has no PID; you cannot signal it. All you can do is | 1244 connection has no PID; you cannot signal it. All you can do is |
942 deactivate and close it via delete-process */ | 1245 deactivate and close it via delete-process */ |
943 | 1246 |
944 static void | 1247 static void |
945 nt_open_network_stream (Lisp_Object name, Lisp_Object host, Lisp_Object service, | 1248 nt_open_network_stream (Lisp_Object name, Lisp_Object host, |
1249 Lisp_Object service, | |
946 Lisp_Object protocol, void** vinfd, void** voutfd) | 1250 Lisp_Object protocol, void** vinfd, void** voutfd) |
947 { | 1251 { |
1252 /* !!#### not Mule-ized */ | |
948 struct sockaddr_in address; | 1253 struct sockaddr_in address; |
949 SOCKET s; | 1254 SOCKET s; |
950 int port; | 1255 int port; |
951 int retval; | 1256 int retval; |
952 | 1257 |
953 CHECK_STRING (host); | 1258 CHECK_STRING (host); |
954 | 1259 |
955 if (!EQ (protocol, Qtcp)) | 1260 if (!EQ (protocol, Qtcp)) |
956 error ("Unsupported protocol \"%s\"", | 1261 invalid_argument ("Unsupported protocol", protocol); |
957 string_data (symbol_name (XSYMBOL (protocol)))); | |
958 | 1262 |
959 if (INTP (service)) | 1263 if (INTP (service)) |
960 port = htons ((unsigned short) XINT (service)); | 1264 port = htons ((unsigned short) XINT (service)); |
961 else | 1265 else |
962 { | 1266 { |
963 struct servent *svc_info; | 1267 struct servent *svc_info; |
964 CHECK_STRING (service); | 1268 CHECK_STRING (service); |
965 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp"); | 1269 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp"); |
966 if (svc_info == 0) | 1270 if (svc_info == 0) |
967 error ("Unknown service \"%s\"", XSTRING_DATA (service)); | 1271 invalid_argument ("Unknown service", service); |
968 port = svc_info->s_port; | 1272 port = svc_info->s_port; |
969 } | 1273 } |
970 | 1274 |
971 get_internet_address (host, &address, ERROR_ME); | 1275 get_internet_address (host, &address, ERROR_ME); |
972 address.sin_port = port; | 1276 address.sin_port = port; |
1024 0, FALSE, DUPLICATE_SAME_ACCESS); | 1328 0, FALSE, DUPLICATE_SAME_ACCESS); |
1025 return; | 1329 return; |
1026 | 1330 |
1027 connect_failed: | 1331 connect_failed: |
1028 closesocket (s); | 1332 closesocket (s); |
1029 if (INTP (service)) { | 1333 if (INTP (service)) |
1030 warn_when_safe(Qstream, Qwarning, | 1334 { |
1031 "failure to open network stream to host \"%s\" for service \"%d\"", | 1335 warn_when_safe (Qstream, Qwarning, |
1032 XSTRING_DATA (host), | 1336 "failure to open network stream to host \"%s\" for service \"%d\"", |
1033 (unsigned short) XINT (service)); | 1337 XSTRING_DATA (host), |
1034 } | 1338 (unsigned short) XINT (service)); |
1035 else { | 1339 } |
1036 warn_when_safe(Qstream, Qwarning, | 1340 else |
1037 "failure to open network stream to host \"%s\" for service \"%s\"", | 1341 { |
1038 XSTRING_DATA (host), | 1342 warn_when_safe (Qstream, Qwarning, |
1039 XSTRING_DATA (service)); | 1343 "failure to open network stream to host \"%s\" for service \"%s\"", |
1040 } | 1344 XSTRING_DATA (host), |
1345 XSTRING_DATA (service)); | |
1346 } | |
1041 report_file_error ("connection failed", list2 (host, name)); | 1347 report_file_error ("connection failed", list2 (host, name)); |
1042 } | 1348 } |
1043 | 1349 |
1044 #endif | 1350 #endif |
1045 | 1351 |
1069 } | 1375 } |
1070 | 1376 |
1071 void | 1377 void |
1072 syms_of_process_nt (void) | 1378 syms_of_process_nt (void) |
1073 { | 1379 { |
1074 defsymbol (&Qnt_quote_process_args, "nt-quote-process-args"); | 1380 DEFSYMBOL (Qmswindows_construct_process_command_line); |
1075 } | 1381 } |
1076 | 1382 |
1077 void | 1383 void |
1078 vars_of_process_nt (void) | 1384 vars_of_process_nt (void) |
1079 { | 1385 { |
1080 } | 1386 DEFVAR_LISP ("mswindows-quote-process-args", |
1387 &Vmswindows_quote_process_args /* | |
1388 Non-nil enables quoting of process arguments to ensure correct parsing. | |
1389 Because Windows does not directly pass argv arrays to child processes, | |
1390 programs have to reconstruct the argv array by parsing the command | |
1391 line string. For an argument to contain a space, it must be enclosed | |
1392 in double quotes or it will be parsed as multiple arguments. | |
1393 | |
1394 If the value is a character, that character will be used to escape any | |
1395 quote characters that appear, otherwise a suitable escape character | |
1396 will be chosen based on the type of the program (normal or Cygwin). | |
1397 */ ); | |
1398 Vmswindows_quote_process_args = Qt; | |
1399 | |
1400 DEFVAR_LISP ("mswindows-start-process-share-console", | |
1401 &Vmswindows_start_process_share_console /* | |
1402 When nil, new child processes are given a new console. | |
1403 When non-nil, they share the Emacs console; this has the limitation of | |
1404 allowing only only DOS subprocess to run at a time (whether started directly | |
1405 or indirectly by Emacs), and preventing Emacs from cleanly terminating the | |
1406 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't | |
1407 otherwise respond to interrupts from Emacs. | |
1408 */ ); | |
1409 Vmswindows_start_process_share_console = Qnil; | |
1410 | |
1411 DEFVAR_LISP ("mswindows-start-process-inherit-error-mode", | |
1412 &Vmswindows_start_process_inherit_error_mode /* | |
1413 "When nil, new child processes revert to the default error mode. | |
1414 When non-nil, they inherit their error mode setting from Emacs, which stops | |
1415 them blocking when trying to access unmounted drives etc. | |
1416 */ ); | |
1417 Vmswindows_start_process_inherit_error_mode = Qt; | |
1418 } |