Mercurial > hg > xemacs-beta
comparison src/process-nt.c @ 771:943eaba38521
[xemacs-hg @ 2002-03-13 08:51:24 by ben]
The big ben-mule-21-5 check-in!
Various files were added and deleted. See CHANGES-ben-mule.
There are still some test suite failures. No crashes, though.
Many of the failures have to do with problems in the test suite itself
rather than in the actual code. I'll be addressing these in the next
day or so -- none of the test suite failures are at all critical.
Meanwhile I'll be trying to address the biggest issues -- i.e. build
or run failures, which will almost certainly happen on various platforms.
All comments should be sent to ben@xemacs.org -- use a Cc: if necessary
when sending to mailing lists. There will be pre- and post- tags,
something like
pre-ben-mule-21-5-merge-in, and
post-ben-mule-21-5-merge-in.
author | ben |
---|---|
date | Wed, 13 Mar 2002 08:54:06 +0000 |
parents | fdefd0186b75 |
children | 7b1f30330a19 |
comparison
equal
deleted
inserted
replaced
770:336a418893b5 | 771:943eaba38521 |
---|---|
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, 2000, 2001 Ben Wing. | 5 Copyright (C) 1995, 1996, 2000, 2001, 2002 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 |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
22 Boston, MA 02111-1307, USA. */ | 22 Boston, MA 02111-1307, USA. */ |
23 | 23 |
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 /* Mule-ized as of 8-6-00 */ | |
27 | |
26 #include <config.h> | 28 #include <config.h> |
27 #include "lisp.h" | 29 #include "lisp.h" |
28 | 30 |
29 #include "buffer.h" | |
30 #include "console-msw.h" | 31 #include "console-msw.h" |
31 #include "hash.h" | 32 #include "hash.h" |
32 #include "lstream.h" | 33 #include "lstream.h" |
33 #include "nt.h" | |
34 #include "process.h" | 34 #include "process.h" |
35 #include "procimpl.h" | 35 #include "procimpl.h" |
36 #include "sysdep.h" | |
37 | 36 |
38 #include "syssignal.h" | 37 #include "syssignal.h" |
39 #include "sysfile.h" | 38 #include "sysfile.h" |
40 #include "sysproc.h" | 39 #include "sysproc.h" |
41 | 40 |
62 /* Control whether create_child cause the process to inherit Emacs' | 61 /* Control whether create_child cause the process to inherit Emacs' |
63 error mode setting. The default is t, to minimize the possibility of | 62 error mode setting. The default is t, to minimize the possibility of |
64 subprocesses blocking when accessing unmounted drives. */ | 63 subprocesses blocking when accessing unmounted drives. */ |
65 Lisp_Object Vmswindows_start_process_inherit_error_mode; | 64 Lisp_Object Vmswindows_start_process_inherit_error_mode; |
66 | 65 |
67 #define NT_DATA(p) ((struct nt_process_data*)((p)->process_data)) | 66 #define NT_DATA(p) ((struct nt_process_data *)((p)->process_data)) |
68 | 67 |
69 /*-----------------------------------------------------------------------*/ | 68 /*-----------------------------------------------------------------------*/ |
70 /* Process helpers */ | 69 /* Process helpers */ |
71 /*-----------------------------------------------------------------------*/ | 70 /*-----------------------------------------------------------------------*/ |
72 | 71 |
116 * thread, which immediately terminates after that. | 115 * thread, which immediately terminates after that. |
117 */ | 116 */ |
118 | 117 |
119 static int | 118 static int |
120 alloc_process_memory (HANDLE h_process, Bytecount size, | 119 alloc_process_memory (HANDLE h_process, Bytecount size, |
121 process_memory* pmc) | 120 process_memory *pmc) |
122 { | 121 { |
123 LPTHREAD_START_ROUTINE adr_ExitThread = | 122 LPTHREAD_START_ROUTINE adr_ExitThread = |
124 (LPTHREAD_START_ROUTINE) | 123 (LPTHREAD_START_ROUTINE) |
125 GetProcAddress (GetModuleHandle ("kernel32"), "ExitThread"); | 124 GetProcAddress (qxeGetModuleHandle (XETEXT ("kernel32")), "ExitThread"); |
126 DWORD dw_unused; | 125 DWORD dw_unused; |
127 CONTEXT context; | 126 CONTEXT context; |
128 MEMORY_BASIC_INFORMATION mbi; | 127 MEMORY_BASIC_INFORMATION mbi; |
129 | 128 |
130 pmc->h_process = h_process; | 129 pmc->h_process = h_process; |
131 pmc->h_thread = CreateRemoteThread (h_process, NULL, size, | 130 pmc->h_thread = CreateRemoteThread (h_process, NULL, size, |
132 adr_ExitThread, NULL, | 131 adr_ExitThread, NULL, |
133 CREATE_SUSPENDED, &dw_unused); | 132 CREATE_SUSPENDED, &dw_unused); |
134 if (pmc->h_thread == NULL) | 133 if (pmc->h_thread == NULL) |
135 return 0; | 134 return 0; |
136 | 135 |
137 /* Get context, for thread's stack pointer */ | 136 /* Get context, for thread's stack pointer */ |
138 context.ContextFlags = CONTEXT_CONTROL; | 137 context.ContextFlags = CONTEXT_CONTROL; |
165 pmc->address = 0; | 164 pmc->address = 0; |
166 return 0; | 165 return 0; |
167 } | 166 } |
168 | 167 |
169 static void | 168 static void |
170 free_process_memory (process_memory* pmc) | 169 free_process_memory (process_memory *pmc) |
171 { | 170 { |
172 ResumeThread (pmc->h_thread); | 171 ResumeThread (pmc->h_thread); |
173 } | 172 } |
174 | 173 |
175 /* | 174 /* |
270 { | 269 { |
271 void (WINAPI *adr_ExitProcess) (UINT); | 270 void (WINAPI *adr_ExitProcess) (UINT); |
272 } sigkill_data; | 271 } sigkill_data; |
273 | 272 |
274 static DWORD WINAPI | 273 static DWORD WINAPI |
275 sigkill_proc (sigkill_data* data) | 274 sigkill_proc (sigkill_data *data) |
276 { | 275 { |
277 (*data->adr_ExitProcess)(255); | 276 (*data->adr_ExitProcess)(255); |
278 return 1; | 277 return 1; |
279 } | 278 } |
280 | 279 |
286 BOOL (WINAPI *adr_GenerateConsoleCtrlEvent) (DWORD, DWORD); | 285 BOOL (WINAPI *adr_GenerateConsoleCtrlEvent) (DWORD, DWORD); |
287 DWORD event; | 286 DWORD event; |
288 } sigint_data; | 287 } sigint_data; |
289 | 288 |
290 static DWORD WINAPI | 289 static DWORD WINAPI |
291 sigint_proc (sigint_data* data) | 290 sigint_proc (sigint_data *data) |
292 { | 291 { |
293 return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0); | 292 return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0); |
294 } | 293 } |
295 | 294 |
296 /* | 295 /* |
300 { | 299 { |
301 BOOL (WINAPI *adr_SetConsoleCtrlHandler) (LPVOID, BOOL); | 300 BOOL (WINAPI *adr_SetConsoleCtrlHandler) (LPVOID, BOOL); |
302 } sig_enable_data; | 301 } sig_enable_data; |
303 | 302 |
304 static DWORD WINAPI | 303 static DWORD WINAPI |
305 sig_enable_proc (sig_enable_data* data) | 304 sig_enable_proc (sig_enable_data *data) |
306 { | 305 { |
307 (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE); | 306 (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE); |
308 return 1; | 307 return 1; |
309 } | 308 } |
310 | 309 |
315 | 314 |
316 static int | 315 static int |
317 send_signal_the_nt_way (struct nt_process_data *cp, int pid, int signo) | 316 send_signal_the_nt_way (struct nt_process_data *cp, int pid, int signo) |
318 { | 317 { |
319 HANDLE h_process; | 318 HANDLE h_process; |
320 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 319 HMODULE h_kernel = qxeGetModuleHandle (XETEXT ("kernel32")); |
321 int close_process = 0; | 320 int close_process = 0; |
322 DWORD retval; | 321 DWORD retval; |
323 | 322 |
324 assert (h_kernel != NULL); | 323 assert (h_kernel != NULL); |
325 | 324 |
352 | 351 |
353 d.adr_ExitProcess = | 352 d.adr_ExitProcess = |
354 (void (WINAPI *) (UINT)) GetProcAddress (h_kernel, "ExitProcess"); | 353 (void (WINAPI *) (UINT)) GetProcAddress (h_kernel, "ExitProcess"); |
355 assert (d.adr_ExitProcess); | 354 assert (d.adr_ExitProcess); |
356 retval = run_in_other_process (h_process, | 355 retval = run_in_other_process (h_process, |
357 (LPTHREAD_START_ROUTINE)sigkill_proc, | 356 (LPTHREAD_START_ROUTINE) sigkill_proc, |
358 &d, sizeof (d)); | 357 &d, sizeof (d)); |
359 break; | 358 break; |
360 } | 359 } |
361 case SIGINT: | 360 case SIGINT: |
362 { | 361 { |
365 (BOOL (WINAPI *) (DWORD, DWORD)) | 364 (BOOL (WINAPI *) (DWORD, DWORD)) |
366 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); | 365 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); |
367 assert (d.adr_GenerateConsoleCtrlEvent); | 366 assert (d.adr_GenerateConsoleCtrlEvent); |
368 d.event = CTRL_C_EVENT; | 367 d.event = CTRL_C_EVENT; |
369 retval = run_in_other_process (h_process, | 368 retval = run_in_other_process (h_process, |
370 (LPTHREAD_START_ROUTINE)sigint_proc, | 369 (LPTHREAD_START_ROUTINE) sigint_proc, |
371 &d, sizeof (d)); | 370 &d, sizeof (d)); |
372 break; | 371 break; |
373 } | 372 } |
374 default: | 373 default: |
375 assert (0); | 374 assert (0); |
384 * Enable CTRL_C_EVENT handling in a new child process | 383 * Enable CTRL_C_EVENT handling in a new child process |
385 */ | 384 */ |
386 static void | 385 static void |
387 enable_child_signals (HANDLE h_process) | 386 enable_child_signals (HANDLE h_process) |
388 { | 387 { |
389 HMODULE h_kernel = GetModuleHandle ("kernel32"); | 388 HMODULE h_kernel = qxeGetModuleHandle (XETEXT ("kernel32")); |
390 sig_enable_data d; | 389 sig_enable_data d; |
391 | 390 |
392 assert (h_kernel != NULL); | 391 assert (h_kernel != NULL); |
393 d.adr_SetConsoleCtrlHandler = | 392 d.adr_SetConsoleCtrlHandler = |
394 (BOOL (WINAPI *) (LPVOID, BOOL)) | 393 (BOOL (WINAPI *) (LPVOID, BOOL)) |
410 struct nt_process_data *cp = (struct nt_process_data *) putada; | 409 struct nt_process_data *cp = (struct nt_process_data *) putada; |
411 | 410 |
412 thread_id = GetWindowThreadProcessId (hwnd, &process_id); | 411 thread_id = GetWindowThreadProcessId (hwnd, &process_id); |
413 if (process_id == cp->dwProcessId) | 412 if (process_id == cp->dwProcessId) |
414 { | 413 { |
415 char window_class[32]; | 414 Extbyte window_class[32]; |
416 | 415 |
417 GetClassName (hwnd, window_class, sizeof (window_class)); | 416 /* GetClassNameA to avoid problems with Unicode return values */ |
417 GetClassNameA (hwnd, window_class, sizeof (window_class)); | |
418 if (strcmp (window_class, | 418 if (strcmp (window_class, |
419 mswindows_windows9x_p () | 419 mswindows_windows9x_p |
420 ? "tty" | 420 ? "tty" |
421 : "ConsoleWindowClass") == 0) | 421 : "ConsoleWindowClass") == 0) |
422 { | 422 { |
423 cp->hwnd = hwnd; | 423 cp->hwnd = hwnd; |
424 return FALSE; | 424 return FALSE; |
454 | 454 |
455 if (signo == SIGINT) | 455 if (signo == SIGINT) |
456 { | 456 { |
457 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | 457 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) |
458 { | 458 { |
459 BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0); | 459 BYTE control_scan_code = (BYTE) MapVirtualKeyA (VK_CONTROL, 0); |
460 BYTE vk_break_code = VK_CANCEL; | 460 BYTE vk_break_code = VK_CANCEL; |
461 BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | 461 BYTE break_scan_code = (BYTE) MapVirtualKeyA (vk_break_code, 0); |
462 HWND foreground_window; | 462 HWND foreground_window; |
463 | 463 |
464 if (break_scan_code == 0) | 464 if (break_scan_code == 0) |
465 { | 465 { |
466 /* Fake Ctrl-C if we can't manage Ctrl-Break. */ | 466 /* Fake Ctrl-C if we can't manage Ctrl-Break. */ |
467 vk_break_code = 'C'; | 467 vk_break_code = 'C'; |
468 break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0); | 468 break_scan_code = (BYTE) MapVirtualKeyA (vk_break_code, 0); |
469 } | 469 } |
470 | 470 |
471 foreground_window = GetForegroundWindow (); | 471 foreground_window = GetForegroundWindow (); |
472 if (foreground_window) | 472 if (foreground_window) |
473 { | 473 { |
535 else | 535 else |
536 { | 536 { |
537 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | 537 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) |
538 { | 538 { |
539 #if 1 | 539 #if 1 |
540 if (mswindows_windows9x_p ()) | 540 if (mswindows_windows9x_p) |
541 { | 541 { |
542 /* | 542 /* |
543 Another possibility is to try terminating the VDM out-right by | 543 Another possibility is to try terminating the VDM out-right by |
544 calling the Shell VxD (id 0x17) V86 interface, function #4 | 544 calling the Shell VxD (id 0x17) V86 interface, function #4 |
545 "SHELL_Destroy_VM", ie. | 545 "SHELL_Destroy_VM", ie. |
603 /* -------------------------- all-OS functions ---------------------------- */ | 603 /* -------------------------- all-OS functions ---------------------------- */ |
604 | 604 |
605 static int | 605 static int |
606 send_signal (struct nt_process_data *cp, int pid, int signo) | 606 send_signal (struct nt_process_data *cp, int pid, int signo) |
607 { | 607 { |
608 return (!mswindows_windows9x_p () && send_signal_the_nt_way (cp, pid, signo)) | 608 return (!mswindows_windows9x_p && send_signal_the_nt_way (cp, pid, signo)) |
609 || send_signal_the_95_way (cp, pid, signo); | 609 || send_signal_the_95_way (cp, pid, signo); |
610 } | 610 } |
611 | 611 |
612 /* | 612 /* |
613 * Signal error if SIGNO is not supported | 613 * Signal error if SIGNO is not supported |
653 WSADATA wsa_data; | 653 WSADATA wsa_data; |
654 /* Request Winsock v1.1 Note the order: (minor=1, major=1) */ | 654 /* Request Winsock v1.1 Note the order: (minor=1, major=1) */ |
655 WSAStartup (MAKEWORD (1,1), &wsa_data); | 655 WSAStartup (MAKEWORD (1,1), &wsa_data); |
656 } | 656 } |
657 | 657 |
658 DOESNT_RETURN | |
659 mswindows_report_process_error (const char *string, Lisp_Object data, | |
660 int errnum) | |
661 { | |
662 report_file_type_error (Qprocess_error, mswindows_lisp_error (errnum), | |
663 string, data); | |
664 } | |
665 | |
666 static DOESNT_RETURN | 658 static DOESNT_RETURN |
667 mswindows_report_winsock_error (const char *string, Lisp_Object data, | 659 mswindows_report_winsock_error (const char *string, Lisp_Object data, |
668 int errnum) | 660 int errnum) |
669 { | 661 { |
670 report_file_type_error (Qnetwork_error, mswindows_lisp_error (errnum), | 662 report_file_type_error (Qnetwork_error, mswindows_lisp_error (errnum), |
672 } | 664 } |
673 | 665 |
674 static void | 666 static void |
675 ensure_console_window_exists (void) | 667 ensure_console_window_exists (void) |
676 { | 668 { |
677 if (mswindows_windows9x_p ()) | 669 if (mswindows_windows9x_p) |
678 mswindows_hide_console (); | 670 mswindows_hide_console (); |
679 } | 671 } |
680 | 672 |
681 int | 673 int |
682 compare_env (const void *strp1, const void *strp2) | 674 mswindows_compare_env (const void *strp1, const void *strp2) |
683 { | 675 { |
684 const char *str1 = *(const char**)strp1, *str2 = *(const char**)strp2; | 676 const Intbyte *str1 = *(const Intbyte **)strp1, |
677 *str2 = *(const Intbyte **)strp2; | |
685 | 678 |
686 while (*str1 && *str2 && *str1 != '=' && *str2 != '=') | 679 while (*str1 && *str2 && *str1 != '=' && *str2 != '=') |
687 { | 680 { |
688 if ((*str1) > (*str2)) | 681 if ((*str1) > (*str2)) |
689 return 1; | 682 return 1; |
718 /* Synched up with sys_spawnve in FSF 20.6. Significantly different | 711 /* Synched up with sys_spawnve in FSF 20.6. Significantly different |
719 but still synchable. */ | 712 but still synchable. */ |
720 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr; | 713 HANDLE hmyshove, hmyslurp, hprocin, hprocout, hprocerr; |
721 Extbyte *command_line; | 714 Extbyte *command_line; |
722 BOOL do_io, windowed; | 715 BOOL do_io, windowed; |
723 char *proc_env; | 716 Extbyte *proc_env; |
724 | 717 |
725 /* No need to DOS-ize the filename; expand-file-name (called prior) | 718 /* No need to DOS-ize the filename; expand-file-name (called prior) |
726 already does this. */ | 719 already does this. */ |
727 | 720 |
728 /* Find out whether the application is windowed or not */ | 721 /* Find out whether the application is windowed or not */ |
729 if (xSHGetFileInfoA) | 722 { |
730 { | 723 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most |
731 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most | 724 errors. This leads to bogus error message. */ |
732 errors. This leads to bogus error message. */ | 725 DWORD image_type; |
733 DWORD image_type; | 726 Intbyte *p = qxestrrchr (XSTRING_DATA (program), '.'); |
734 char *p = strrchr ((char *)XSTRING_DATA (program), '.'); | 727 if (p != NULL && |
735 if (p != NULL && | 728 (qxestrcasecmp (p, ".exe") == 0 || |
736 (stricmp (p, ".exe") == 0 || | 729 qxestrcasecmp (p, ".com") == 0 || |
737 stricmp (p, ".com") == 0 || | 730 qxestrcasecmp (p, ".bat") == 0 || |
738 stricmp (p, ".bat") == 0 || | 731 qxestrcasecmp (p, ".cmd") == 0)) |
739 stricmp (p, ".cmd") == 0)) | 732 { |
740 { | 733 Extbyte *progext; |
741 image_type = xSHGetFileInfoA ((char *)XSTRING_DATA (program), 0,NULL, | 734 LISP_STRING_TO_TSTR (program, progext); |
742 0, SHGFI_EXETYPE); | 735 image_type = qxeSHGetFileInfo (progext, 0, NULL, 0, SHGFI_EXETYPE); |
743 } | 736 } |
744 else | 737 else |
745 { | 738 { |
746 char progname[PATH_MAX]; | 739 DECLARE_EISTRING (progext); |
747 sprintf (progname, "%s.exe", (char *)XSTRING_DATA (program)); | 740 eicpy_lstr (progext, program); |
748 image_type = xSHGetFileInfoA (progname, 0, NULL, 0, SHGFI_EXETYPE); | 741 eicat_c (progext, ".exe"); |
749 } | 742 eito_external (progext, Qmswindows_tstr); |
750 if (image_type == 0) | 743 image_type = qxeSHGetFileInfo (eiextdata (progext), 0, NULL, 0, |
751 mswindows_report_process_error | 744 SHGFI_EXETYPE); |
752 ("Error starting", | 745 } |
753 program, | 746 if (image_type == 0) |
754 GetLastError () == ERROR_FILE_NOT_FOUND | 747 mswindows_report_process_error |
755 ? ERROR_BAD_FORMAT : GetLastError ()); | 748 ("Determining executable file type", |
756 windowed = HIWORD (image_type) != 0; | 749 program, |
757 } | 750 GetLastError () == ERROR_FILE_NOT_FOUND |
758 else /* NT 3.5; we have no idea so just guess. */ | 751 ? ERROR_BAD_FORMAT : GetLastError ()); |
759 windowed = 0; | 752 windowed = HIWORD (image_type) != 0; |
753 } | |
754 | |
760 | 755 |
761 /* 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 |
762 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 |
763 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 |
764 is non-zero */ | 759 is non-zero */ |
816 /* Luser wrote his/her own clever version */ | 811 /* Luser wrote his/her own clever version */ |
817 invalid_argument | 812 invalid_argument |
818 ("Bogus return value from `mswindows-construct-process-command-line'", | 813 ("Bogus return value from `mswindows-construct-process-command-line'", |
819 args_or_ret); | 814 args_or_ret); |
820 | 815 |
821 LISP_STRING_TO_EXTERNAL (args_or_ret, command_line, Qmswindows_tstr); | 816 LISP_STRING_TO_TSTR (args_or_ret, command_line); |
822 | 817 |
823 UNGCPRO; /* args_or_ret */ | 818 UNGCPRO; /* args_or_ret */ |
824 } | 819 } |
825 | 820 |
826 /* 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 |
827 Vprocess_environment terminated by 2 nuls. */ | 822 Vprocess_environment terminated by 2 nuls. */ |
828 | 823 |
829 { | 824 { |
830 char **env; | 825 Intbyte **env; |
831 REGISTER Lisp_Object tem; | 826 REGISTER Lisp_Object tem; |
832 REGISTER char **new_env; | 827 REGISTER Intbyte **new_env; |
833 REGISTER int new_length = 0, i, new_space; | 828 REGISTER int new_length = 0, i; |
834 char *penv; | |
835 | 829 |
836 for (tem = Vprocess_environment; | 830 for (tem = Vprocess_environment; |
837 (CONSP (tem) | 831 (CONSP (tem) |
838 && STRINGP (XCAR (tem))); | 832 && STRINGP (XCAR (tem))); |
839 tem = XCDR (tem)) | 833 tem = XCDR (tem)) |
840 new_length++; | 834 new_length++; |
841 | 835 |
842 /* FSF adds an extra env var to hold the current process ID of the | 836 /* FSF adds an extra env var to hold the current process ID of the |
843 Emacs process. Apparently this is used only by emacsserver.c, | 837 Emacs process. Apparently this is used only by emacsserver.c, |
844 which we have superseded to gnuserv.c. (#### Does it work under | 838 which we have superseded by gnuserv.c. (#### Does it work under |
845 MS Windows?) | 839 MS Windows?) |
846 | 840 |
847 sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d", | 841 sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d", |
848 GetCurrentProcessId ()); | 842 GetCurrentProcessId ()); |
849 arglen += strlen (ppid_env_var_buffer) + 1; | 843 arglen += strlen (ppid_env_var_buffer) + 1; |
850 numenv++; | 844 numenv++; |
851 */ | 845 */ |
852 | 846 |
853 /* new_length + 1 to include terminating 0. */ | 847 /* new_length + 1 to include terminating 0. */ |
854 env = new_env = alloca_array (char *, new_length + 1); | 848 env = new_env = alloca_array (Intbyte *, new_length + 1); |
855 | 849 |
856 /* Copy the Vprocess_environment strings into new_env. */ | 850 /* Copy the Vprocess_environment strings into new_env. */ |
857 for (tem = Vprocess_environment; | 851 for (tem = Vprocess_environment; |
858 (CONSP (tem) | 852 (CONSP (tem) |
859 && STRINGP (XCAR (tem))); | 853 && STRINGP (XCAR (tem))); |
860 tem = XCDR (tem)) | 854 tem = XCDR (tem)) |
861 { | 855 { |
862 char **ep = env; | 856 Intbyte **ep = env; |
863 char *string = (char *) XSTRING_DATA (XCAR (tem)); | 857 Intbyte *string = XSTRING_DATA (XCAR (tem)); |
864 /* See if this string duplicates any string already in the env. | 858 /* See if this string duplicates any string already in the env. |
865 If so, don't put it in. | 859 If so, don't put it in. |
866 When an env var has multiple definitions, | 860 When an env var has multiple definitions, |
867 we keep the definition that comes first in process-environment. */ | 861 we keep the definition that comes first in process-environment. */ |
868 for (; ep != new_env; ep++) | 862 for (; ep != new_env; ep++) |
869 { | 863 { |
870 char *p = *ep, *q = string; | 864 Intbyte *p = *ep, *q = string; |
871 while (1) | 865 while (1) |
872 { | 866 { |
873 if (*q == 0) | 867 if (*q == 0) |
874 /* The string is malformed; might as well drop it. */ | 868 /* The string is malformed; might as well drop it. */ |
875 goto duplicate; | 869 goto duplicate; |
885 } | 879 } |
886 *new_env = 0; | 880 *new_env = 0; |
887 | 881 |
888 /* Sort the environment variables */ | 882 /* Sort the environment variables */ |
889 new_length = new_env - env; | 883 new_length = new_env - env; |
890 qsort (env, new_length, sizeof (char *), compare_env); | 884 qsort (env, new_length, sizeof (Intbyte *), mswindows_compare_env); |
891 | 885 |
892 /* Work out how much space to allocate */ | 886 { |
893 new_space = 0; | 887 DECLARE_EISTRING (envout); |
894 for (i = 0; i < new_length; i++) | 888 |
895 { | 889 for (i = 0; i < new_length; i++) |
896 new_space += strlen(env[i]) + 1; | 890 { |
897 } | 891 eicat_raw (envout, env[i], strlen (env[i])); |
898 new_space++; | 892 eicat_raw (envout, "\0", 1); |
899 | 893 } |
900 /* Allocate space and copy variables into it */ | 894 |
901 penv = proc_env = (char*) alloca(new_space); | 895 eicat_raw (envout, "\0", 1); |
902 for (i = 0; i < new_length; i++) | 896 eito_external (envout, Qmswindows_tstr); |
903 { | 897 proc_env = eiextdata (envout); |
904 strcpy(penv, env[i]); | 898 } |
905 penv += strlen(env[i]) + 1; | |
906 } | |
907 *penv = 0; | |
908 } | 899 } |
909 | 900 |
910 #if 0 | 901 #if 0 |
911 /* #### we need to port this. */ | 902 /* #### we need to port this. */ |
912 /* On Windows 95, if cmdname is a DOS app, we invoke a helper | 903 /* On Windows 95, if cmdname is a DOS app, we invoke a helper |
913 application to start it by specifying the helper app as cmdname, | 904 application to start it by specifying the helper app as cmdname, |
914 while leaving the real app name as argv[0]. */ | 905 while leaving the real app name as argv[0]. */ |
915 if (is_dos_app) | 906 if (is_dos_app) |
916 { | 907 { |
917 cmdname = (char*) alloca (MAXPATHLEN); | 908 cmdname = (Intbyte *) alloca (PATH_MAX); |
918 if (egetenv ("CMDPROXY")) | 909 if (egetenv ("CMDPROXY")) |
919 strcpy ((char*)cmdname, egetenv ("CMDPROXY")); | 910 qxestrcpy (cmdname, egetenv ("CMDPROXY")); |
920 else | 911 else |
921 { | 912 { |
922 strcpy ((char*)cmdname, XSTRING_DATA (Vinvocation_directory)); | 913 qxestrcpy (cmdname, XSTRING_DATA (Vinvocation_directory)); |
923 strcat ((char*)cmdname, "cmdproxy.exe"); | 914 qxestrcat (cmdname, (Intbyte *) "cmdproxy.exe"); |
924 } | 915 } |
925 } | 916 } |
926 #endif | 917 #endif |
927 | 918 |
928 /* Create process */ | 919 /* Create process */ |
929 { | 920 { |
930 STARTUPINFO si; | 921 STARTUPINFOW si; |
931 PROCESS_INFORMATION pi; | 922 PROCESS_INFORMATION pi; |
932 DWORD err; | 923 DWORD err; |
933 DWORD flags; | 924 DWORD flags; |
934 | 925 |
935 xzero (si); | 926 xzero (si); |
942 si.hStdError = hprocerr; | 933 si.hStdError = hprocerr; |
943 si.dwFlags |= STARTF_USESTDHANDLES; | 934 si.dwFlags |= STARTF_USESTDHANDLES; |
944 } | 935 } |
945 | 936 |
946 flags = CREATE_SUSPENDED; | 937 flags = CREATE_SUSPENDED; |
947 if (mswindows_windows9x_p ()) | 938 if (mswindows_windows9x_p) |
948 flags |= (!NILP (Vmswindows_start_process_share_console) | 939 flags |= (!NILP (Vmswindows_start_process_share_console) |
949 ? CREATE_NEW_PROCESS_GROUP | 940 ? CREATE_NEW_PROCESS_GROUP |
950 : CREATE_NEW_CONSOLE); | 941 : CREATE_NEW_CONSOLE); |
951 else | 942 else |
952 flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; | 943 flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; |
953 if (NILP (Vmswindows_start_process_inherit_error_mode)) | 944 if (NILP (Vmswindows_start_process_inherit_error_mode)) |
954 flags |= CREATE_DEFAULT_ERROR_MODE; | 945 flags |= CREATE_DEFAULT_ERROR_MODE; |
955 | 946 |
956 ensure_console_window_exists (); | 947 ensure_console_window_exists (); |
957 | 948 |
958 err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE, flags, | 949 { |
959 proc_env, (char *) XSTRING_DATA (cur_dir), &si, &pi) | 950 Extbyte *curdirext; |
960 ? 0 : GetLastError ()); | 951 |
952 LISP_STRING_TO_TSTR (cur_dir, curdirext); | |
953 | |
954 err = (qxeCreateProcess (NULL, command_line, NULL, NULL, TRUE, | |
955 (XEUNICODE_P ? | |
956 flags | CREATE_UNICODE_ENVIRONMENT : | |
957 flags), proc_env, | |
958 curdirext, &si, &pi) | |
959 ? 0 : GetLastError ()); | |
960 } | |
961 | 961 |
962 if (do_io) | 962 if (do_io) |
963 { | 963 { |
964 /* These just have been inherited; we do not need a copy */ | 964 /* These just have been inherited; we do not need a copy */ |
965 CloseHandle (hprocin); | 965 CloseHandle (hprocin); |
983 /* The process started successfully */ | 983 /* The process started successfully */ |
984 if (do_io) | 984 if (do_io) |
985 { | 985 { |
986 NT_DATA(p)->h_process = pi.hProcess; | 986 NT_DATA(p)->h_process = pi.hProcess; |
987 NT_DATA(p)->dwProcessId = pi.dwProcessId; | 987 NT_DATA(p)->dwProcessId = pi.dwProcessId; |
988 init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0); | 988 init_process_io_handles (p, (void *)hmyslurp, (void *)hmyshove, 0); |
989 } | 989 } |
990 else | 990 else |
991 { | 991 { |
992 /* Indicate as if the process has exited immediately. */ | 992 /* Indicate as if the process has exited immediately. */ |
993 p->status_symbol = Qexit; | 993 p->status_symbol = Qexit; |
1011 * | 1011 * |
1012 * The method is called only for real child processes. | 1012 * The method is called only for real child processes. |
1013 */ | 1013 */ |
1014 | 1014 |
1015 static void | 1015 static void |
1016 nt_update_status_if_terminated (Lisp_Process* p) | 1016 nt_update_status_if_terminated (Lisp_Process *p) |
1017 { | 1017 { |
1018 DWORD exit_code; | 1018 DWORD exit_code; |
1019 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) | 1019 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) |
1020 && exit_code != STILL_ACTIVE) | 1020 && exit_code != STILL_ACTIVE) |
1021 { | 1021 { |
1043 | 1043 |
1044 /* #### If only this function could be somehow merged with | 1044 /* #### If only this function could be somehow merged with |
1045 unix_send_process... */ | 1045 unix_send_process... */ |
1046 | 1046 |
1047 static void | 1047 static void |
1048 nt_send_process (Lisp_Object proc, struct lstream* lstream) | 1048 nt_send_process (Lisp_Object proc, struct lstream *lstream) |
1049 { | 1049 { |
1050 volatile Lisp_Object vol_proc = proc; | 1050 volatile Lisp_Object vol_proc = proc; |
1051 Lisp_Process *volatile p = XPROCESS (proc); | 1051 Lisp_Process *volatile p = XPROCESS (proc); |
1052 | 1052 |
1053 /* use a reasonable-sized buffer (somewhere around the size of the | 1053 /* use a reasonable-sized buffer (somewhere around the size of the |
1056 Intbyte chunkbuf[512]; | 1056 Intbyte chunkbuf[512]; |
1057 Bytecount chunklen; | 1057 Bytecount chunklen; |
1058 | 1058 |
1059 while (1) | 1059 while (1) |
1060 { | 1060 { |
1061 Bytecount writeret; | 1061 int writeret; |
1062 | 1062 |
1063 chunklen = Lstream_read (lstream, chunkbuf, 512); | 1063 chunklen = Lstream_read (lstream, chunkbuf, 512); |
1064 if (chunklen <= 0) | 1064 if (chunklen <= 0) |
1065 break; /* perhaps should abort() if < 0? | 1065 break; /* perhaps should abort() if < 0? |
1066 This should never happen. */ | 1066 This should never happen. */ |
1067 | 1067 |
1068 /* Lstream_write() will never successfully write less than the | 1068 /* Lstream_write() will never successfully write less than the |
1069 amount sent in. In the worst case, it just buffers the | 1069 amount sent in. In the worst case, it just buffers the |
1070 unwritten data. */ | 1070 unwritten data. */ |
1071 writeret = Lstream_write (XLSTREAM (DATA_OUTSTREAM(p)), chunkbuf, | 1071 writeret = Lstream_write (XLSTREAM (DATA_OUTSTREAM (p)), chunkbuf, |
1072 chunklen); | 1072 chunklen); |
1073 Lstream_flush (XLSTREAM (DATA_OUTSTREAM(p))); | 1073 Lstream_flush (XLSTREAM (DATA_OUTSTREAM (p))); |
1074 if (writeret < 0) | 1074 if (writeret < 0) |
1075 { | 1075 { |
1076 p->status_symbol = Qexit; | 1076 p->status_symbol = Qexit; |
1077 p->exit_code = ERROR_BROKEN_PIPE; | 1077 p->exit_code = ERROR_BROKEN_PIPE; |
1078 p->core_dumped = 0; | 1078 p->core_dumped = 0; |
1157 /* Return 0 for success, or error code */ | 1157 /* Return 0 for success, or error code */ |
1158 | 1158 |
1159 static int | 1159 static int |
1160 get_internet_address (Lisp_Object host, struct sockaddr_in *address) | 1160 get_internet_address (Lisp_Object host, struct sockaddr_in *address) |
1161 { | 1161 { |
1162 char buf [MAXGETHOSTSTRUCT]; | 1162 Char_Binary buf[MAXGETHOSTSTRUCT]; |
1163 HWND hwnd; | 1163 HWND hwnd; |
1164 HANDLE hasync; | 1164 HANDLE hasync; |
1165 int errcode = 0; | 1165 int errcode = 0; |
1166 | 1166 |
1167 address->sin_family = AF_INET; | 1167 address->sin_family = AF_INET; |
1175 return 0; | 1175 return 0; |
1176 } | 1176 } |
1177 } | 1177 } |
1178 | 1178 |
1179 /* Create a window which will receive completion messages */ | 1179 /* Create a window which will receive completion messages */ |
1180 hwnd = CreateWindow ("STATIC", NULL, WS_OVERLAPPED, 0, 0, 1, 1, | 1180 hwnd = qxeCreateWindow (XETEXT ("STATIC"), NULL, WS_OVERLAPPED, 0, 0, 1, 1, |
1181 NULL, NULL, NULL, NULL); | 1181 NULL, NULL, NULL, NULL); |
1182 assert (hwnd); | 1182 assert (hwnd); |
1183 | 1183 |
1184 /* Post name resolution request */ | 1184 /* Post name resolution request */ |
1185 hasync = WSAAsyncGetHostByName (hwnd, XM_SOCKREPLY, XSTRING_DATA (host), | 1185 { |
1186 buf, sizeof (buf)); | 1186 Extbyte *hostext; |
1187 if (hasync == NULL) | 1187 |
1188 { | 1188 LISP_STRING_TO_EXTERNAL (host, hostext, Qmswindows_host_name_encoding); |
1189 errcode = WSAGetLastError (); | 1189 |
1190 goto done; | 1190 hasync = WSAAsyncGetHostByName (hwnd, XM_SOCKREPLY, hostext, |
1191 } | 1191 buf, sizeof (buf)); |
1192 if (hasync == NULL) | |
1193 { | |
1194 errcode = WSAGetLastError (); | |
1195 goto done; | |
1196 } | |
1197 } | |
1192 | 1198 |
1193 /* Set a timer to poll for quit every 250 ms */ | 1199 /* Set a timer to poll for quit every 250 ms */ |
1194 SetTimer (hwnd, SOCK_TIMER_ID, 250, NULL); | 1200 SetTimer (hwnd, SOCK_TIMER_ID, 250, NULL); |
1195 | 1201 |
1196 while (1) | 1202 while (1) |
1220 KillTimer (hwnd, SOCK_TIMER_ID); | 1226 KillTimer (hwnd, SOCK_TIMER_ID); |
1221 DestroyWindow (hwnd); | 1227 DestroyWindow (hwnd); |
1222 if (!errcode) | 1228 if (!errcode) |
1223 { | 1229 { |
1224 /* BUF starts with struct hostent */ | 1230 /* BUF starts with struct hostent */ |
1225 struct hostent* he = (struct hostent*) buf; | 1231 struct hostent *he = (struct hostent *) buf; |
1226 address->sin_addr.s_addr = *(unsigned long*)he->h_addr_list[0]; | 1232 address->sin_addr.s_addr = * (unsigned long *) he->h_addr_list[0]; |
1227 } | 1233 } |
1228 return errcode; | 1234 return errcode; |
1229 } | 1235 } |
1230 | 1236 |
1231 static Lisp_Object | 1237 static Lisp_Object |
1249 deactivate and close it via delete-process */ | 1255 deactivate and close it via delete-process */ |
1250 | 1256 |
1251 static void | 1257 static void |
1252 nt_open_network_stream (Lisp_Object name, Lisp_Object host, | 1258 nt_open_network_stream (Lisp_Object name, Lisp_Object host, |
1253 Lisp_Object service, | 1259 Lisp_Object service, |
1254 Lisp_Object protocol, void** vinfd, void** voutfd) | 1260 Lisp_Object protocol, void **vinfd, void **voutfd) |
1255 { | 1261 { |
1256 /* !!#### not Mule-ized */ | |
1257 struct sockaddr_in address; | 1262 struct sockaddr_in address; |
1258 SOCKET s; | 1263 SOCKET s; |
1259 int port; | 1264 int port; |
1260 int retval; | 1265 int retval; |
1261 int errnum; | 1266 int errnum; |
1268 if (INTP (service)) | 1273 if (INTP (service)) |
1269 port = htons ((unsigned short) XINT (service)); | 1274 port = htons ((unsigned short) XINT (service)); |
1270 else | 1275 else |
1271 { | 1276 { |
1272 struct servent *svc_info; | 1277 struct servent *svc_info; |
1278 Extbyte *servext; | |
1279 | |
1273 CHECK_STRING (service); | 1280 CHECK_STRING (service); |
1274 svc_info = getservbyname ((char *) XSTRING_DATA (service), "tcp"); | 1281 LISP_STRING_TO_EXTERNAL (service, servext, |
1282 Qmswindows_service_name_encoding); | |
1283 | |
1284 svc_info = getservbyname (servext, "tcp"); | |
1275 if (svc_info == 0) | 1285 if (svc_info == 0) |
1276 invalid_argument ("Unknown service", service); | 1286 invalid_argument ("Unknown service", service); |
1277 port = svc_info->s_port; | 1287 port = svc_info->s_port; |
1278 } | 1288 } |
1279 | 1289 |
1307 /* Wait while connection is established */ | 1317 /* Wait while connection is established */ |
1308 { | 1318 { |
1309 HWND hwnd; | 1319 HWND hwnd; |
1310 | 1320 |
1311 /* Create a window which will receive completion messages */ | 1321 /* Create a window which will receive completion messages */ |
1312 hwnd = CreateWindow ("STATIC", NULL, WS_OVERLAPPED, 0, 0, 1, 1, | 1322 hwnd = qxeCreateWindow (XETEXT ("STATIC"), NULL, WS_OVERLAPPED, 0, 0, 1, 1, |
1313 NULL, NULL, NULL, NULL); | 1323 NULL, NULL, NULL, NULL); |
1314 assert (hwnd); | 1324 assert (hwnd); |
1315 | 1325 |
1316 /* Post request */ | 1326 /* Post request */ |
1317 if (WSAAsyncSelect (s, hwnd, XM_SOCKREPLY, FD_CONNECT)) | 1327 if (WSAAsyncSelect (s, hwnd, XM_SOCKREPLY, FD_CONNECT)) |
1318 { | 1328 { |
1410 } | 1420 } |
1411 } | 1421 } |
1412 #endif | 1422 #endif |
1413 | 1423 |
1414 /* We are connected at this point */ | 1424 /* We are connected at this point */ |
1415 *vinfd = (void*)s; | 1425 *vinfd = (void *)s; |
1416 DuplicateHandle (GetCurrentProcess(), (HANDLE)s, | 1426 DuplicateHandle (GetCurrentProcess(), (HANDLE)s, |
1417 GetCurrentProcess(), (LPHANDLE)voutfd, | 1427 GetCurrentProcess(), (LPHANDLE)voutfd, |
1418 0, FALSE, DUPLICATE_SAME_ACCESS); | 1428 0, FALSE, DUPLICATE_SAME_ACCESS); |
1419 return; | 1429 return; |
1420 | 1430 |
1426 errnum); | 1436 errnum); |
1427 } | 1437 } |
1428 } | 1438 } |
1429 | 1439 |
1430 #endif | 1440 #endif |
1441 | |
1442 | |
1443 DEFUN ("mswindows-set-process-priority", Fmswindows_set_process_priority, 2, 2, "", /* | |
1444 Set the priority of PROCESS to PRIORITY. | |
1445 If PROCESS is nil, the priority of Emacs is changed, otherwise the | |
1446 priority of the process whose pid is PROCESS is changed. | |
1447 PRIORITY should be one of the symbols high, normal, or low; | |
1448 any other symbol will be interpreted as normal. | |
1449 | |
1450 If successful, the return value is t, otherwise nil. | |
1451 */ | |
1452 (process, priority)) | |
1453 { | |
1454 HANDLE proc_handle = GetCurrentProcess (); | |
1455 DWORD priority_class = NORMAL_PRIORITY_CLASS; | |
1456 Lisp_Object result = Qnil; | |
1457 | |
1458 CHECK_SYMBOL (priority); | |
1459 | |
1460 if (!NILP (process)) | |
1461 { | |
1462 DWORD pid; | |
1463 struct Lisp_Process *p = 0; | |
1464 | |
1465 if (PROCESSP (process)) | |
1466 { | |
1467 CHECK_LIVE_PROCESS (process); | |
1468 p = XPROCESS (process); | |
1469 pid = NT_DATA (p)->dwProcessId; | |
1470 } | |
1471 else | |
1472 { | |
1473 CHECK_INT (process); | |
1474 | |
1475 /* Allow pid to be an internally generated one, or one obtained | |
1476 externally. This is necessary because real pids on Win95 are | |
1477 negative. */ | |
1478 | |
1479 pid = XINT (process); | |
1480 p = find_process_from_pid (pid); | |
1481 if (p != NULL) | |
1482 pid = NT_DATA (p)->dwProcessId; | |
1483 } | |
1484 | |
1485 /* #### Should we be using the existing process handle from NT_DATA(p)? | |
1486 Will we fail if we open it a second time? */ | |
1487 proc_handle = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid); | |
1488 } | |
1489 | |
1490 if (EQ (priority, Qhigh)) | |
1491 priority_class = HIGH_PRIORITY_CLASS; | |
1492 else if (EQ (priority, Qlow)) | |
1493 priority_class = IDLE_PRIORITY_CLASS; | |
1494 | |
1495 if (proc_handle != NULL) | |
1496 { | |
1497 if (SetPriorityClass (proc_handle, priority_class)) | |
1498 result = Qt; | |
1499 if (!NILP (process)) | |
1500 CloseHandle (proc_handle); | |
1501 } | |
1502 | |
1503 return result; | |
1504 } | |
1505 | |
1431 | 1506 |
1432 /*-----------------------------------------------------------------------*/ | 1507 /*-----------------------------------------------------------------------*/ |
1433 /* Initialization */ | 1508 /* Initialization */ |
1434 /*-----------------------------------------------------------------------*/ | 1509 /*-----------------------------------------------------------------------*/ |
1435 | 1510 |
1455 } | 1530 } |
1456 | 1531 |
1457 void | 1532 void |
1458 syms_of_process_nt (void) | 1533 syms_of_process_nt (void) |
1459 { | 1534 { |
1535 DEFSUBR (Fmswindows_set_process_priority); | |
1460 DEFSYMBOL (Qmswindows_construct_process_command_line); | 1536 DEFSYMBOL (Qmswindows_construct_process_command_line); |
1461 } | 1537 } |
1462 | 1538 |
1463 void | 1539 void |
1464 vars_of_process_nt (void) | 1540 vars_of_process_nt (void) |