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)