Mercurial > hg > xemacs-beta
annotate src/process-nt.c @ 4952:19a72041c5ed
Mule-izing, various fixes related to char * arguments
-------------------- ChangeLog entries follow: --------------------
modules/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c:
* postgresql/postgresql.c (CHECK_LIVE_CONNECTION):
* postgresql/postgresql.c (print_pgresult):
* postgresql/postgresql.c (Fpq_conn_defaults):
* postgresql/postgresql.c (Fpq_connectdb):
* postgresql/postgresql.c (Fpq_connect_start):
* postgresql/postgresql.c (Fpq_result_status):
* postgresql/postgresql.c (Fpq_res_status):
Mule-ize large parts of it.
2010-01-26 Ben Wing <ben@xemacs.org>
* ldap/eldap.c (print_ldap):
* ldap/eldap.c (allocate_ldap):
Use write_ascstring().
src/ChangeLog addition:
2010-01-26 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (build_ascstring):
* alloc.c (build_msg_cistring):
* alloc.c (staticpro_1):
* alloc.c (staticpro_name):
* alloc.c (staticpro_nodump_1):
* alloc.c (staticpro_nodump_name):
* alloc.c (unstaticpro_nodump_1):
* alloc.c (mcpro_1):
* alloc.c (mcpro_name):
* alloc.c (object_memory_usage_stats):
* alloc.c (common_init_alloc_early):
* alloc.c (init_alloc_once_early):
* buffer.c (print_buffer):
* buffer.c (vars_of_buffer):
* buffer.c (common_init_complex_vars_of_buffer):
* buffer.c (init_initial_directory):
* bytecode.c (invalid_byte_code):
* bytecode.c (print_compiled_function):
* bytecode.c (mark_compiled_function):
* chartab.c (print_table_entry):
* chartab.c (print_char_table):
* config.h.in:
* console-gtk.c:
* console-gtk.c (gtk_device_to_console_connection):
* console-gtk.c (gtk_semi_canonicalize_console_connection):
* console-gtk.c (gtk_canonicalize_console_connection):
* console-gtk.c (gtk_semi_canonicalize_device_connection):
* console-gtk.c (gtk_canonicalize_device_connection):
* console-stream.c (stream_init_frame_1):
* console-stream.c (vars_of_console_stream):
* console-stream.c (init_console_stream):
* console-x.c (x_semi_canonicalize_console_connection):
* console-x.c (x_semi_canonicalize_device_connection):
* console-x.c (x_canonicalize_device_connection):
* console-x.h:
* data.c (eq_with_ebola_notice):
* data.c (Fsubr_interactive):
* data.c (Fnumber_to_string):
* data.c (digit_to_number):
* device-gtk.c (gtk_init_device):
* device-msw.c (print_devmode):
* device-x.c (x_event_name):
* dialog-msw.c (handle_directory_dialog_box):
* dialog-msw.c (handle_file_dialog_box):
* dialog-msw.c (vars_of_dialog_mswindows):
* doc.c (weird_doc):
* doc.c (Fsnarf_documentation):
* doc.c (vars_of_doc):
* dumper.c (pdump):
* dynarr.c:
* dynarr.c (Dynarr_realloc):
* editfns.c (Fuser_real_login_name):
* editfns.c (get_home_directory):
* elhash.c (print_hash_table_data):
* elhash.c (print_hash_table):
* emacs.c (main_1):
* emacs.c (vars_of_emacs):
* emodules.c:
* emodules.c (_emodules_list):
* emodules.c (Fload_module):
* emodules.c (Funload_module):
* emodules.c (Flist_modules):
* emodules.c (find_make_module):
* emodules.c (attempt_module_delete):
* emodules.c (emodules_load):
* emodules.c (emodules_doc_subr):
* emodules.c (emodules_doc_sym):
* emodules.c (syms_of_module):
* emodules.c (vars_of_module):
* emodules.h:
* eval.c (print_subr):
* eval.c (signal_call_debugger):
* eval.c (build_error_data):
* eval.c (signal_error):
* eval.c (maybe_signal_error):
* eval.c (signal_continuable_error):
* eval.c (maybe_signal_continuable_error):
* eval.c (signal_error_2):
* eval.c (maybe_signal_error_2):
* eval.c (signal_continuable_error_2):
* eval.c (maybe_signal_continuable_error_2):
* eval.c (signal_ferror):
* eval.c (maybe_signal_ferror):
* eval.c (signal_continuable_ferror):
* eval.c (maybe_signal_continuable_ferror):
* eval.c (signal_ferror_with_frob):
* eval.c (maybe_signal_ferror_with_frob):
* eval.c (signal_continuable_ferror_with_frob):
* eval.c (maybe_signal_continuable_ferror_with_frob):
* eval.c (syntax_error):
* eval.c (syntax_error_2):
* eval.c (maybe_syntax_error):
* eval.c (sferror):
* eval.c (sferror_2):
* eval.c (maybe_sferror):
* eval.c (invalid_argument):
* eval.c (invalid_argument_2):
* eval.c (maybe_invalid_argument):
* eval.c (invalid_constant):
* eval.c (invalid_constant_2):
* eval.c (maybe_invalid_constant):
* eval.c (invalid_operation):
* eval.c (invalid_operation_2):
* eval.c (maybe_invalid_operation):
* eval.c (invalid_change):
* eval.c (invalid_change_2):
* eval.c (maybe_invalid_change):
* eval.c (invalid_state):
* eval.c (invalid_state_2):
* eval.c (maybe_invalid_state):
* eval.c (wtaerror):
* eval.c (stack_overflow):
* eval.c (out_of_memory):
* eval.c (print_multiple_value):
* eval.c (issue_call_trapping_problems_warning):
* eval.c (backtrace_specials):
* eval.c (backtrace_unevalled_args):
* eval.c (Fbacktrace):
* eval.c (warn_when_safe):
* event-Xt.c (modwarn):
* event-Xt.c (modbarf):
* event-Xt.c (check_modifier):
* event-Xt.c (store_modifier):
* event-Xt.c (emacs_Xt_format_magic_event):
* event-Xt.c (describe_event):
* event-gtk.c (dragndrop_data_received):
* event-gtk.c (store_modifier):
* event-gtk.c (gtk_reset_modifier_mapping):
* event-msw.c (dde_eval_string):
* event-msw.c (Fdde_alloc_advise_item):
* event-msw.c (mswindows_dde_callback):
* event-msw.c (FROB):
* event-msw.c (emacs_mswindows_format_magic_event):
* event-stream.c (external_debugging_print_event):
* event-stream.c (execute_help_form):
* event-stream.c (vars_of_event_stream):
* events.c (print_event_1):
* events.c (print_event):
* events.c (event_equal):
* extents.c (print_extent_1):
* extents.c (print_extent):
* extents.c (vars_of_extents):
* faces.c (print_face):
* faces.c (complex_vars_of_faces):
* file-coding.c:
* file-coding.c (print_coding_system):
* file-coding.c (print_coding_system_in_print_method):
* file-coding.c (default_query_method):
* file-coding.c (find_coding_system):
* file-coding.c (make_coding_system_1):
* file-coding.c (chain_print):
* file-coding.c (undecided_print):
* file-coding.c (gzip_print):
* file-coding.c (vars_of_file_coding):
* file-coding.c (complex_vars_of_file_coding):
* fileio.c:
* fileio.c (report_file_type_error):
* fileio.c (report_error_with_errno):
* fileio.c (report_file_error):
* fileio.c (barf_or_query_if_file_exists):
* fileio.c (vars_of_fileio):
* floatfns.c (matherr):
* fns.c (print_bit_vector):
* fns.c (Fmapconcat):
* fns.c (add_suffix_to_symbol):
* fns.c (add_prefix_to_symbol):
* frame-gtk.c:
* frame-gtk.c (Fgtk_window_id):
* frame-x.c (def):
* frame-x.c (x_cde_transfer_callback):
* frame.c:
* frame.c (Fmake_frame):
* gc.c (show_gc_cursor_and_message):
* gc.c (vars_of_gc):
* glyphs-eimage.c (png_instantiate):
* glyphs-eimage.c (tiff_instantiate):
* glyphs-gtk.c (gtk_print_image_instance):
* glyphs-msw.c (mswindows_print_image_instance):
* glyphs-x.c (x_print_image_instance):
* glyphs-x.c (update_widget_face):
* glyphs.c (make_string_from_file):
* glyphs.c (print_image_instance):
* glyphs.c (signal_image_error):
* glyphs.c (signal_image_error_2):
* glyphs.c (signal_double_image_error):
* glyphs.c (signal_double_image_error_2):
* glyphs.c (xbm_mask_file_munging):
* glyphs.c (pixmap_to_lisp_data):
* glyphs.h:
* gui.c (gui_item_display_flush_left):
* hpplay.c (player_error_internal):
* hpplay.c (myHandler):
* intl-win32.c:
* intl-win32.c (langcode_to_lang):
* intl-win32.c (sublangcode_to_lang):
* intl-win32.c (Fmswindows_get_locale_info):
* intl-win32.c (lcid_to_locale_mule_or_no):
* intl-win32.c (mswindows_multibyte_to_unicode_print):
* intl-win32.c (complex_vars_of_intl_win32):
* keymap.c:
* keymap.c (print_keymap):
* keymap.c (ensure_meta_prefix_char_keymapp):
* keymap.c (Fkey_description):
* keymap.c (Ftext_char_description):
* lisp.h:
* lisp.h (struct):
* lisp.h (DECLARE_INLINE_HEADER):
* lread.c (Fload_internal):
* lread.c (locate_file):
* lread.c (read_escape):
* lread.c (read_raw_string):
* lread.c (read1):
* lread.c (read_list):
* lread.c (read_compiled_function):
* lread.c (init_lread):
* lrecord.h:
* marker.c (print_marker):
* marker.c (marker_equal):
* menubar-msw.c (displayable_menu_item):
* menubar-x.c (command_builder_operate_menu_accelerator):
* menubar.c (vars_of_menubar):
* minibuf.c (reinit_complex_vars_of_minibuf):
* minibuf.c (complex_vars_of_minibuf):
* mule-charset.c (Fmake_charset):
* mule-charset.c (complex_vars_of_mule_charset):
* mule-coding.c (iso2022_print):
* mule-coding.c (fixed_width_query):
* number.c (bignum_print):
* number.c (ratio_print):
* number.c (bigfloat_print):
* number.c (bigfloat_finalize):
* objects-msw.c:
* objects-msw.c (mswindows_color_to_string):
* objects-msw.c (mswindows_color_list):
* objects-tty.c:
* objects-tty.c (tty_font_list):
* objects-tty.c (tty_find_charset_font):
* objects-xlike-inc.c (xft_find_charset_font):
* objects-xlike-inc.c (endif):
* print.c:
* print.c (write_istring):
* print.c (write_ascstring):
* print.c (Fterpri):
* print.c (Fprint):
* print.c (print_error_message):
* print.c (print_vector_internal):
* print.c (print_cons):
* print.c (print_string):
* print.c (printing_unreadable_object):
* print.c (print_internal):
* print.c (print_float):
* print.c (print_symbol):
* process-nt.c (mswindows_report_winsock_error):
* process-nt.c (nt_canonicalize_host_name):
* process-unix.c (unix_canonicalize_host_name):
* process.c (print_process):
* process.c (report_process_error):
* process.c (report_network_error):
* process.c (make_process_internal):
* process.c (Fstart_process_internal):
* process.c (status_message):
* process.c (putenv_internal):
* process.c (vars_of_process):
* process.h:
* profile.c (vars_of_profile):
* rangetab.c (print_range_table):
* realpath.c (vars_of_realpath):
* redisplay.c (vars_of_redisplay):
* search.c (wordify):
* search.c (Freplace_match):
* sheap.c (sheap_adjust_h):
* sound.c (report_sound_error):
* sound.c (Fplay_sound_file):
* specifier.c (print_specifier):
* symbols.c (Fsubr_name):
* symbols.c (do_symval_forwarding):
* symbols.c (set_default_buffer_slot_variable):
* symbols.c (set_default_console_slot_variable):
* symbols.c (store_symval_forwarding):
* symbols.c (default_value):
* symbols.c (defsymbol_massage_name_1):
* symbols.c (defsymbol_massage_name_nodump):
* symbols.c (defsymbol_massage_name):
* symbols.c (defsymbol_massage_multiword_predicate_nodump):
* symbols.c (defsymbol_massage_multiword_predicate):
* symbols.c (defsymbol_nodump):
* symbols.c (defsymbol):
* symbols.c (defkeyword):
* symbols.c (defkeyword_massage_name):
* symbols.c (check_module_subr):
* symbols.c (deferror_1):
* symbols.c (deferror):
* symbols.c (deferror_massage_name):
* symbols.c (deferror_massage_name_and_message):
* symbols.c (defvar_magic):
* symeval.h:
* symeval.h (DEFVAR_SYMVAL_FWD):
* sysdep.c:
* sysdep.c (init_system_name):
* sysdll.c:
* sysdll.c (MAYBE_PREPEND_UNDERSCORE):
* sysdll.c (dll_function):
* sysdll.c (dll_variable):
* sysdll.c (dll_error):
* sysdll.c (dll_open):
* sysdll.c (dll_close):
* sysdll.c (image_for_address):
* sysdll.c (my_find_image):
* sysdll.c (search_linked_libs):
* sysdll.h:
* sysfile.h:
* sysfile.h (DEFAULT_DIRECTORY_FALLBACK):
* syswindows.h:
* tests.c (DFC_CHECK_LENGTH):
* tests.c (DFC_CHECK_CONTENT):
* tests.c (Ftest_hash_tables):
* text.c (vars_of_text):
* text.h:
* tooltalk.c (tt_opnum_string):
* tooltalk.c (tt_message_arg_ival_string):
* tooltalk.c (Ftooltalk_default_procid):
* tooltalk.c (Ftooltalk_default_session):
* tooltalk.c (init_tooltalk):
* tooltalk.c (vars_of_tooltalk):
* ui-gtk.c (Fdll_load):
* ui-gtk.c (type_to_marshaller_type):
* ui-gtk.c (Fgtk_import_function_internal):
* ui-gtk.c (emacs_gtk_object_printer):
* ui-gtk.c (emacs_gtk_boxed_printer):
* unicode.c (unicode_to_ichar):
* unicode.c (unicode_print):
* unicode.c (unicode_query):
* unicode.c (vars_of_unicode):
* unicode.c (complex_vars_of_unicode):
* win32.c:
* win32.c (mswindows_report_process_error):
* window.c (print_window):
* xemacs.def.in.in:
BASIC IDEA: Further fixing up uses of char * and CIbyte *
to reflect their actual semantics; Mule-izing some code;
redoing of the not-yet-working code to handle message translation.
Clean up code to handle message-translation (not yet working).
Create separate versions of build_msg_string() for working with
Ibyte *, CIbyte *, and Ascbyte * arguments. Assert that Ascbyte *
arguments are pure-ASCII. Make build_msg_string() be the same
as build_msg_ascstring(). Create same three versions of GETTEXT()
and DEFER_GETTEXT(). Also create build_defer_string() and
variants for the equivalent of DEFER_GETTEXT() when building a
string. Remove old CGETTEXT(). Clean up code where GETTEXT(),
DEFER_GETTEXT(), build_msg_string(), etc. was being called and
introduce some new calls to build_msg_string(), etc. Remove
GETTEXT() from calls to weird_doc() -- we assume that the
message snarfer knows about weird_doc(). Remove uses of
DEFER_GETTEXT() from error messages in sysdep.c and instead use
special comments /* @@@begin-snarf@@@ */ and /* @@@end-snarf@@@ */
that the message snarfer presumably knows about.
Create build_ascstring() and use it in many instances in place
of build_string(). The purpose of having Ascbyte * variants is
to make the code more self-documenting in terms of what sort of
semantics is expected for char * strings. In fact in the process
of looking for uses of build_string(), much improperly Mule-ized
was discovered.
Mule-ize a lot of code as described in previous paragraph,
e.g. in sysdep.c.
Make the error functions take Ascbyte * strings and fix up a
couple of places where non-pure-ASCII strings were being passed in
(file-coding.c, mule-coding.c, unicode.c). (It's debatable whether
we really need to make the error functions work this way. It
helps catch places where code is written in a way that message
translation won't work, but we may well never implement message
translation.)
Make staticpro() and friends take Ascbyte * strings instead of
raw char * strings. Create a const_Ascbyte_ptr dynarr type
to describe what's held by staticpro_names[] and friends,
create pdump descriptions for const_Ascbyte_ptr dynarrs, and
use them in place of specially-crafted staticpro descriptions.
Mule-ize certain other functions (e.g. x_event_name) by correcting
raw use of char * to Ascbyte *, Rawbyte * or another such type,
and raw use of char[] buffers to another type (usually Ascbyte[]).
Change many uses of write_c_string() to write_msg_string(),
write_ascstring(), etc.
Mule-ize emodules.c, emodules.h, sysdll.h.
Fix some un-Mule-ized code in intl-win32.c.
A comment in event-Xt.c and the limitations of the message
snarfer (make-msgfile or whatever) is presumably incorrect --
it should be smart enough to handle function calls spread over
more than one line. Clean up code in event-Xt.c that was
written awkwardly for this reason.
In config.h.in, instead of NEED_ERROR_CHECK_TYPES_INLINES,
create a more general XEMACS_DEFS_NEEDS_INLINE_DECLS to
indicate when inlined functions need to be declared in
xemacs.defs.in.in, and make use of it in xemacs.defs.in.in.
We need to do this because postgresql.c now calls qxestrdup(),
which is an inline function.
Make nconc2() and other such functions MODULE_API and put
them in xemacs.defs.in.in since postgresql.c now uses them.
Clean up indentation in lread.c and a few other places.
In text.h, document ASSERT_ASCTEXT_ASCII() and
ASSERT_ASCTEXT_ASCII_LEN(), group together the stand-in
encodings and add some more for DLL symbols, function and
variable names, etc.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Tue, 26 Jan 2010 23:22:30 -0600 |
parents | 902d5bd9b75c |
children | 304aebb79cd3 |
rev | line source |
---|---|
428 | 1 /* Asynchronous subprocess implementation for Win32 |
2 Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995 | |
3 Free Software Foundation, Inc. | |
4 Copyright (C) 1995 Sun Microsystems, Inc. | |
2367 | 5 Copyright (C) 1995, 1996, 2000, 2001, 2002, 2004 Ben Wing. |
428 | 6 |
7 This file is part of XEmacs. | |
8 | |
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 | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* Written by Kirill M. Katsnelson <kkm@kis.ru>, April 1998 */ | |
25 | |
771 | 26 /* Mule-ized as of 8-6-00 */ |
27 | |
2367 | 28 /* Major comment about parsing and/or constructing a command line taken |
29 from Windows, or suitable for giving to one of the library routines that | |
30 calls a subprocess is in win32-native.el */ | |
31 | |
428 | 32 #include <config.h> |
33 #include "lisp.h" | |
34 | |
442 | 35 #include "console-msw.h" |
2367 | 36 #include "events.h" |
428 | 37 #include "hash.h" |
38 #include "lstream.h" | |
39 #include "process.h" | |
40 #include "procimpl.h" | |
41 | |
558 | 42 #include "sysfile.h" |
43 #include "sysproc.h" | |
859 | 44 #include "syssignal.h" |
428 | 45 |
442 | 46 /* Bound by win32-native.el */ |
47 Lisp_Object Qmswindows_construct_process_command_line; | |
48 | |
428 | 49 /* Arbitrary size limit for code fragments passed to run_in_other_process */ |
50 #define FRAGMENT_CODE_SIZE 32 | |
51 | |
52 /* Implementation-specific data. Pointed to by Lisp_Process->process_data */ | |
53 struct nt_process_data | |
54 { | |
55 HANDLE h_process; | |
442 | 56 DWORD dwProcessId; |
57 HWND hwnd; /* console window */ | |
853 | 58 int selected_for_exit_notify; |
428 | 59 }; |
60 | |
442 | 61 /* Control whether create_child causes the process to inherit Emacs' |
62 console window, or be given a new one of its own. The default is | |
63 nil, to allow multiple DOS programs to run on Win95. Having separate | |
64 consoles also allows Emacs to cleanly terminate process groups. */ | |
65 Lisp_Object Vmswindows_start_process_share_console; | |
66 | |
67 /* Control whether create_child cause the process to inherit Emacs' | |
68 error mode setting. The default is t, to minimize the possibility of | |
69 subprocesses blocking when accessing unmounted drives. */ | |
70 Lisp_Object Vmswindows_start_process_inherit_error_mode; | |
71 | |
771 | 72 #define NT_DATA(p) ((struct nt_process_data *)((p)->process_data)) |
428 | 73 |
74 /*-----------------------------------------------------------------------*/ | |
75 /* Process helpers */ | |
76 /*-----------------------------------------------------------------------*/ | |
77 | |
853 | 78 /* These break process abstraction. Prototypes in console-msw.h, |
79 used by select_process method in event-msw.c. | |
80 | |
81 If called the first time on a process, return the process handle, so we | |
82 can select on it and receive exit notification. "First time only" so we | |
83 don't select the same process multiple times if someone turns off and on | |
84 the receipt of process data. */ | |
85 | |
86 HANDLE | |
87 get_nt_process_handle_only_first_time (Lisp_Process *p) | |
88 { | |
89 if (NT_DATA (p)->selected_for_exit_notify) | |
90 return INVALID_HANDLE_VALUE; | |
91 NT_DATA (p)->selected_for_exit_notify = 1; | |
92 return (NT_DATA (p)->h_process); | |
93 } | |
94 | |
428 | 95 HANDLE |
440 | 96 get_nt_process_handle (Lisp_Process *p) |
428 | 97 { |
98 return (NT_DATA (p)->h_process); | |
99 } | |
442 | 100 |
101 static struct Lisp_Process * | |
102 find_process_from_pid (DWORD pid) | |
103 { | |
104 Lisp_Object tail, proc; | |
105 | |
106 for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail)) | |
107 { | |
108 proc = XCAR (tail); | |
109 if (NT_DATA (XPROCESS (proc))->dwProcessId == pid) | |
110 return XPROCESS (proc); | |
111 } | |
112 return 0; | |
113 } | |
114 | |
428 | 115 |
116 /*-----------------------------------------------------------------------*/ | |
117 /* Running remote threads. See Microsoft Systems Journal 1994 Number 5 */ | |
118 /* Jeffrey Richter, Load Your 32-bit DLL into Another Process's Address..*/ | |
119 /*-----------------------------------------------------------------------*/ | |
120 | |
121 typedef struct | |
122 { | |
123 HANDLE h_process; | |
124 HANDLE h_thread; | |
125 LPVOID address; | |
126 } process_memory; | |
127 | |
2367 | 128 static void |
129 free_process_memory (process_memory *pmc) | |
130 { | |
131 ResumeThread (pmc->h_thread); | |
132 CloseHandle (pmc->h_thread); | |
133 } | |
134 | |
428 | 135 /* |
136 * Allocate SIZE bytes in H_PROCESS address space. Fill in PMC used | |
137 * further by other routines. Return nonzero if successful. | |
138 * | |
139 * The memory in other process is allocated by creating a suspended | |
140 * thread. Initial stack of that thread is used as the memory | |
141 * block. The thread entry point is the routine ExitThread in | |
854 | 142 * kernel32.dll, so the allocated memory is freed just by resuming the |
428 | 143 * thread, which immediately terminates after that. |
144 */ | |
145 | |
854 | 146 static int |
665 | 147 alloc_process_memory (HANDLE h_process, Bytecount size, |
771 | 148 process_memory *pmc) |
428 | 149 { |
150 LPTHREAD_START_ROUTINE adr_ExitThread = | |
151 (LPTHREAD_START_ROUTINE) | |
771 | 152 GetProcAddress (qxeGetModuleHandle (XETEXT ("kernel32")), "ExitThread"); |
428 | 153 DWORD dw_unused; |
154 CONTEXT context; | |
155 MEMORY_BASIC_INFORMATION mbi; | |
156 | |
157 pmc->h_process = h_process; | |
158 pmc->h_thread = CreateRemoteThread (h_process, NULL, size, | |
771 | 159 adr_ExitThread, NULL, |
160 CREATE_SUSPENDED, &dw_unused); | |
428 | 161 if (pmc->h_thread == NULL) |
162 return 0; | |
163 | |
164 /* Get context, for thread's stack pointer */ | |
165 context.ContextFlags = CONTEXT_CONTROL; | |
166 if (!GetThreadContext (pmc->h_thread, &context)) | |
167 goto failure; | |
168 | |
169 /* Determine base address of the committed range */ | |
170 if (sizeof(mbi) != VirtualQueryEx (h_process, | |
171 #if defined (_X86_) | |
172 (LPDWORD)context.Esp - 1, | |
173 #elif defined (_ALPHA_) | |
174 (LPDWORD)context.IntSp - 1, | |
175 #else | |
176 #error Unknown processor architecture | |
177 #endif | |
178 &mbi, sizeof(mbi))) | |
179 goto failure; | |
180 | |
181 /* Change the page protection of the allocated memory to executable, | |
182 read, and write. */ | |
183 if (!VirtualProtectEx (h_process, mbi.BaseAddress, size, | |
184 PAGE_EXECUTE_READWRITE, &dw_unused)) | |
185 goto failure; | |
186 | |
187 pmc->address = mbi.BaseAddress; | |
188 return 1; | |
189 | |
190 failure: | |
2367 | 191 free_process_memory (pmc); |
428 | 192 pmc->address = 0; |
193 return 0; | |
194 } | |
195 | |
196 /* | |
197 * Run ROUTINE in the context of process determined by H_PROCESS. The | |
198 * routine is passed the address of DATA as parameter. The ROUTINE must | |
199 * not be longer than ROUTINE_CODE_SIZE bytes. DATA_SIZE is the size of | |
200 * DATA structure. | |
201 * | |
202 * Note that the code must be positionally independent, and compiled | |
203 * without stack checks (they cause implicit calls into CRT so will | |
204 * fail). DATA should not refer any data in calling process, as both | |
205 * routine and its data are copied into remote process. Size of data | |
206 * and code together should not exceed one page (4K on x86 systems). | |
207 * | |
208 * Return the value returned by ROUTINE, or (DWORD)-1 if call failed. | |
209 */ | |
210 static DWORD | |
211 run_in_other_process (HANDLE h_process, | |
212 LPTHREAD_START_ROUTINE routine, | |
665 | 213 LPVOID data, Bytecount data_size) |
428 | 214 { |
215 process_memory pm; | |
665 | 216 const Bytecount code_size = FRAGMENT_CODE_SIZE; |
428 | 217 /* Need at most 3 extra bytes of memory, for data alignment */ |
665 | 218 Bytecount total_size = code_size + data_size + 3; |
428 | 219 LPVOID remote_data; |
220 HANDLE h_thread; | |
221 DWORD dw_unused; | |
222 | |
223 /* Allocate memory */ | |
224 if (!alloc_process_memory (h_process, total_size, &pm)) | |
225 return (DWORD)-1; | |
226 | |
227 /* Copy code */ | |
228 if (!WriteProcessMemory (h_process, pm.address, (LPVOID)routine, | |
229 code_size, NULL)) | |
230 goto failure; | |
231 | |
232 /* Copy data */ | |
233 if (data_size) | |
234 { | |
235 remote_data = (LPBYTE)pm.address + ((code_size + 4) & ~3); | |
236 if (!WriteProcessMemory (h_process, remote_data, data, data_size, NULL)) | |
237 goto failure; | |
238 } | |
239 else | |
240 remote_data = NULL; | |
241 | |
242 /* Execute the remote copy of code, passing it remote data */ | |
243 h_thread = CreateRemoteThread (h_process, NULL, 0, | |
244 (LPTHREAD_START_ROUTINE) pm.address, | |
245 remote_data, 0, &dw_unused); | |
246 if (h_thread == NULL) | |
247 goto failure; | |
248 | |
249 /* Wait till thread finishes */ | |
250 WaitForSingleObject (h_thread, INFINITE); | |
251 | |
252 /* Free remote memory */ | |
253 free_process_memory (&pm); | |
254 | |
255 /* Return thread's exit code */ | |
256 { | |
257 DWORD exit_code; | |
258 GetExitCodeThread (h_thread, &exit_code); | |
259 CloseHandle (h_thread); | |
260 return exit_code; | |
261 } | |
262 | |
263 failure: | |
264 free_process_memory (&pm); | |
2367 | 265 return (DWORD) -1; |
428 | 266 } |
267 | |
268 /*-----------------------------------------------------------------------*/ | |
269 /* Sending signals */ | |
270 /*-----------------------------------------------------------------------*/ | |
271 | |
442 | 272 /* ---------------------------- the NT way ------------------------------- */ |
273 | |
428 | 274 /* |
275 * We handle the following signals: | |
276 * | |
277 * SIGKILL, SIGTERM, SIGQUIT, SIGHUP - These four translate to ExitProcess | |
278 * executed by the remote process | |
279 * SIGINT - The remote process is sent CTRL_BREAK_EVENT | |
280 * | |
281 * The MSVC5.0 compiler feels free to re-order functions within a | |
282 * compilation unit, so we have no way of finding out the size of the | |
283 * following functions. Therefore these functions must not be larger than | |
284 * FRAGMENT_CODE_SIZE. | |
285 */ | |
286 | |
287 /* | |
288 * Sending SIGKILL | |
289 */ | |
290 typedef struct | |
291 { | |
292 void (WINAPI *adr_ExitProcess) (UINT); | |
293 } sigkill_data; | |
294 | |
295 static DWORD WINAPI | |
771 | 296 sigkill_proc (sigkill_data *data) |
428 | 297 { |
298 (*data->adr_ExitProcess)(255); | |
299 return 1; | |
300 } | |
301 | |
302 /* | |
303 * Sending break or control c | |
304 */ | |
305 typedef struct | |
306 { | |
307 BOOL (WINAPI *adr_GenerateConsoleCtrlEvent) (DWORD, DWORD); | |
308 DWORD event; | |
309 } sigint_data; | |
310 | |
311 static DWORD WINAPI | |
771 | 312 sigint_proc (sigint_data *data) |
428 | 313 { |
314 return (*data->adr_GenerateConsoleCtrlEvent) (data->event, 0); | |
315 } | |
316 | |
317 /* | |
318 * Enabling signals | |
319 */ | |
320 typedef struct | |
321 { | |
322 BOOL (WINAPI *adr_SetConsoleCtrlHandler) (LPVOID, BOOL); | |
323 } sig_enable_data; | |
324 | |
325 static DWORD WINAPI | |
771 | 326 sig_enable_proc (sig_enable_data *data) |
428 | 327 { |
328 (*data->adr_SetConsoleCtrlHandler) (NULL, FALSE); | |
329 return 1; | |
330 } | |
331 | |
332 /* | |
333 * Send signal SIGNO to process H_PROCESS. | |
334 * Return nonzero if successful. | |
335 */ | |
336 | |
337 static int | |
442 | 338 send_signal_the_nt_way (struct nt_process_data *cp, int pid, int signo) |
428 | 339 { |
442 | 340 HANDLE h_process; |
771 | 341 HMODULE h_kernel = qxeGetModuleHandle (XETEXT ("kernel32")); |
442 | 342 int close_process = 0; |
428 | 343 DWORD retval; |
854 | 344 |
428 | 345 assert (h_kernel != NULL); |
854 | 346 |
442 | 347 if (cp) |
348 { | |
349 pid = cp->dwProcessId; | |
350 h_process = cp->h_process; | |
351 } | |
352 else | |
353 { | |
354 close_process = 1; | |
355 /* Try to open the process with required privileges */ | |
356 h_process = OpenProcess (PROCESS_CREATE_THREAD | |
854 | 357 | PROCESS_QUERY_INFORMATION |
442 | 358 | PROCESS_VM_OPERATION |
359 | PROCESS_VM_WRITE, | |
360 FALSE, pid); | |
361 if (!h_process) | |
362 return 0; | |
363 } | |
364 | |
428 | 365 switch (signo) |
366 { | |
367 case SIGKILL: | |
368 case SIGTERM: | |
369 case SIGQUIT: | |
370 case SIGHUP: | |
371 { | |
372 sigkill_data d; | |
442 | 373 |
374 d.adr_ExitProcess = | |
375 (void (WINAPI *) (UINT)) GetProcAddress (h_kernel, "ExitProcess"); | |
428 | 376 assert (d.adr_ExitProcess); |
854 | 377 retval = run_in_other_process (h_process, |
771 | 378 (LPTHREAD_START_ROUTINE) sigkill_proc, |
428 | 379 &d, sizeof (d)); |
380 break; | |
381 } | |
382 case SIGINT: | |
383 { | |
384 sigint_data d; | |
385 d.adr_GenerateConsoleCtrlEvent = | |
442 | 386 (BOOL (WINAPI *) (DWORD, DWORD)) |
428 | 387 GetProcAddress (h_kernel, "GenerateConsoleCtrlEvent"); |
388 assert (d.adr_GenerateConsoleCtrlEvent); | |
389 d.event = CTRL_C_EVENT; | |
854 | 390 retval = run_in_other_process (h_process, |
2367 | 391 (LPTHREAD_START_ROUTINE) sigint_proc, |
428 | 392 &d, sizeof (d)); |
393 break; | |
394 } | |
395 default: | |
396 assert (0); | |
397 } | |
398 | |
442 | 399 if (close_process) |
400 CloseHandle (h_process); | |
2367 | 401 return (int) retval > 0 ? 1 : 0; |
428 | 402 } |
403 | |
404 /* | |
405 * Enable CTRL_C_EVENT handling in a new child process | |
406 */ | |
407 static void | |
408 enable_child_signals (HANDLE h_process) | |
409 { | |
771 | 410 HMODULE h_kernel = qxeGetModuleHandle (XETEXT ("kernel32")); |
428 | 411 sig_enable_data d; |
854 | 412 |
428 | 413 assert (h_kernel != NULL); |
414 d.adr_SetConsoleCtrlHandler = | |
442 | 415 (BOOL (WINAPI *) (LPVOID, BOOL)) |
428 | 416 GetProcAddress (h_kernel, "SetConsoleCtrlHandler"); |
417 assert (d.adr_SetConsoleCtrlHandler); | |
418 run_in_other_process (h_process, (LPTHREAD_START_ROUTINE)sig_enable_proc, | |
419 &d, sizeof (d)); | |
420 } | |
854 | 421 |
442 | 422 /* ---------------------------- the 95 way ------------------------------- */ |
423 | |
424 static BOOL CALLBACK | |
425 find_child_console (HWND hwnd, long putada) | |
426 { | |
427 DWORD thread_id; | |
428 DWORD process_id; | |
429 struct nt_process_data *cp = (struct nt_process_data *) putada; | |
430 | |
431 thread_id = GetWindowThreadProcessId (hwnd, &process_id); | |
432 if (process_id == cp->dwProcessId) | |
433 { | |
771 | 434 Extbyte window_class[32]; |
442 | 435 |
771 | 436 /* GetClassNameA to avoid problems with Unicode return values */ |
437 GetClassNameA (hwnd, window_class, sizeof (window_class)); | |
442 | 438 if (strcmp (window_class, |
771 | 439 mswindows_windows9x_p |
442 | 440 ? "tty" |
441 : "ConsoleWindowClass") == 0) | |
442 { | |
443 cp->hwnd = hwnd; | |
444 return FALSE; | |
445 } | |
446 } | |
447 /* keep looking */ | |
448 return TRUE; | |
449 } | |
450 | |
451 static int | |
452 send_signal_the_95_way (struct nt_process_data *cp, int pid, int signo) | |
453 { | |
454 HANDLE h_process; | |
455 int close_process = 0; | |
456 int rc = 1; | |
854 | 457 |
442 | 458 if (cp) |
459 { | |
460 pid = cp->dwProcessId; | |
461 h_process = cp->h_process; | |
462 | |
463 /* Try to locate console window for process. */ | |
464 EnumWindows (find_child_console, (LPARAM) cp); | |
465 } | |
466 else | |
467 { | |
468 close_process = 1; | |
469 /* Try to open the process with required privileges */ | |
470 h_process = OpenProcess (PROCESS_TERMINATE, FALSE, pid); | |
471 if (!h_process) | |
472 return 0; | |
473 } | |
854 | 474 |
442 | 475 if (signo == SIGINT) |
476 { | |
477 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
478 { | |
771 | 479 BYTE control_scan_code = (BYTE) MapVirtualKeyA (VK_CONTROL, 0); |
442 | 480 BYTE vk_break_code = VK_CANCEL; |
771 | 481 BYTE break_scan_code = (BYTE) MapVirtualKeyA (vk_break_code, 0); |
442 | 482 HWND foreground_window; |
483 | |
484 if (break_scan_code == 0) | |
485 { | |
486 /* Fake Ctrl-C if we can't manage Ctrl-Break. */ | |
487 vk_break_code = 'C'; | |
771 | 488 break_scan_code = (BYTE) MapVirtualKeyA (vk_break_code, 0); |
442 | 489 } |
490 | |
491 foreground_window = GetForegroundWindow (); | |
492 if (foreground_window) | |
493 { | |
494 /* NT 5.0, and apparently also Windows 98, will not allow | |
495 a Window to be set to foreground directly without the | |
496 user's involvement. The workaround is to attach | |
497 ourselves to the thread that owns the foreground | |
498 window, since that is the only thread that can set the | |
499 foreground window. */ | |
500 DWORD foreground_thread, child_thread; | |
501 foreground_thread = | |
502 GetWindowThreadProcessId (foreground_window, NULL); | |
503 if (foreground_thread == GetCurrentThreadId () | |
504 || !AttachThreadInput (GetCurrentThreadId (), | |
505 foreground_thread, TRUE)) | |
506 foreground_thread = 0; | |
507 | |
508 child_thread = GetWindowThreadProcessId (cp->hwnd, NULL); | |
509 if (child_thread == GetCurrentThreadId () | |
510 || !AttachThreadInput (GetCurrentThreadId (), | |
511 child_thread, TRUE)) | |
512 child_thread = 0; | |
513 | |
514 /* Set the foreground window to the child. */ | |
515 if (SetForegroundWindow (cp->hwnd)) | |
516 { | |
517 /* Generate keystrokes as if user had typed Ctrl-Break or | |
518 Ctrl-C. */ | |
519 keybd_event (VK_CONTROL, control_scan_code, 0, 0); | |
520 keybd_event (vk_break_code, break_scan_code, | |
521 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY), 0); | |
522 keybd_event (vk_break_code, break_scan_code, | |
523 (vk_break_code == 'C' ? 0 : KEYEVENTF_EXTENDEDKEY) | |
524 | KEYEVENTF_KEYUP, 0); | |
525 keybd_event (VK_CONTROL, control_scan_code, | |
526 KEYEVENTF_KEYUP, 0); | |
527 | |
528 /* Sleep for a bit to give time for Emacs frame to respond | |
529 to focus change events (if Emacs was active app). */ | |
530 Sleep (100); | |
531 | |
532 SetForegroundWindow (foreground_window); | |
533 } | |
534 /* Detach from the foreground and child threads now that | |
535 the foreground switching is over. */ | |
536 if (foreground_thread) | |
537 AttachThreadInput (GetCurrentThreadId (), | |
538 foreground_thread, FALSE); | |
539 if (child_thread) | |
540 AttachThreadInput (GetCurrentThreadId (), | |
541 child_thread, FALSE); | |
542 } | |
543 } | |
544 /* Ctrl-Break is NT equivalent of SIGINT. */ | |
545 else if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid)) | |
546 { | |
547 #if 0 /* FSF Emacs */ | |
548 DebPrint (("sys_kill.GenerateConsoleCtrlEvent return %d " | |
549 "for pid %lu\n", GetLastError (), pid)); | |
550 errno = EINVAL; | |
551 #endif | |
552 rc = 0; | |
553 } | |
554 } | |
555 else | |
556 { | |
557 if (NILP (Vmswindows_start_process_share_console) && cp && cp->hwnd) | |
558 { | |
559 #if 1 | |
771 | 560 if (mswindows_windows9x_p) |
442 | 561 { |
562 /* | |
563 Another possibility is to try terminating the VDM out-right by | |
564 calling the Shell VxD (id 0x17) V86 interface, function #4 | |
565 "SHELL_Destroy_VM", ie. | |
566 | |
567 mov edx,4 | |
568 mov ebx,vm_handle | |
569 call shellapi | |
570 | |
571 First need to determine the current VM handle, and then arrange for | |
572 the shellapi call to be made from the system vm (by using | |
573 Switch_VM_and_callback). | |
574 | |
575 Could try to invoke DestroyVM through CallVxD. | |
576 | |
577 */ | |
578 #if 0 | |
579 /* On Win95, posting WM_QUIT causes the 16-bit subsystem | |
580 to hang when cmdproxy is used in conjunction with | |
581 command.com for an interactive shell. Posting | |
582 WM_CLOSE pops up a dialog that, when Yes is selected, | |
583 does the same thing. TerminateProcess is also less | |
584 than ideal in that subprocesses tend to stick around | |
585 until the machine is shutdown, but at least it | |
586 doesn't freeze the 16-bit subsystem. */ | |
800 | 587 qxePostMessage (cp->hwnd, WM_QUIT, 0xff, 0); |
442 | 588 #endif |
589 if (!TerminateProcess (h_process, 0xff)) | |
590 { | |
591 #if 0 /* FSF Emacs */ | |
592 DebPrint (("sys_kill.TerminateProcess returned %d " | |
593 "for pid %lu\n", GetLastError (), pid)); | |
594 errno = EINVAL; | |
595 #endif | |
596 rc = 0; | |
597 } | |
598 } | |
599 else | |
600 #endif | |
800 | 601 qxePostMessage (cp->hwnd, WM_CLOSE, 0, 0); |
442 | 602 } |
603 /* Kill the process. On W32 this doesn't kill child processes | |
604 so it doesn't work very well for shells which is why it's not | |
605 used in every case. */ | |
606 else if (!TerminateProcess (h_process, 0xff)) | |
607 { | |
608 #if 0 /* FSF Emacs */ | |
609 DebPrint (("sys_kill.TerminateProcess returned %d " | |
610 "for pid %lu\n", GetLastError (), pid)); | |
611 errno = EINVAL; | |
612 #endif | |
613 rc = 0; | |
614 } | |
615 } | |
616 | |
617 if (close_process) | |
618 CloseHandle (h_process); | |
619 | |
620 return rc; | |
621 } | |
622 | |
623 /* -------------------------- all-OS functions ---------------------------- */ | |
624 | |
625 static int | |
626 send_signal (struct nt_process_data *cp, int pid, int signo) | |
627 { | |
771 | 628 return (!mswindows_windows9x_p && send_signal_the_nt_way (cp, pid, signo)) |
442 | 629 || send_signal_the_95_way (cp, pid, signo); |
630 } | |
631 | |
428 | 632 /* |
633 * Signal error if SIGNO is not supported | |
634 */ | |
635 static void | |
636 validate_signal_number (int signo) | |
637 { | |
638 if (signo != SIGKILL && signo != SIGTERM | |
639 && signo != SIGQUIT && signo != SIGINT | |
640 && signo != SIGHUP) | |
563 | 641 invalid_constant ("Signal number not supported", make_int (signo)); |
428 | 642 } |
854 | 643 |
428 | 644 /*-----------------------------------------------------------------------*/ |
645 /* Process methods */ | |
646 /*-----------------------------------------------------------------------*/ | |
647 | |
648 /* | |
649 * Allocate and initialize Lisp_Process->process_data | |
650 */ | |
651 | |
652 static void | |
440 | 653 nt_alloc_process_data (Lisp_Process *p) |
428 | 654 { |
655 p->process_data = xnew_and_zero (struct nt_process_data); | |
656 } | |
657 | |
658 static void | |
440 | 659 nt_finalize_process_data (Lisp_Process *p, int for_disksave) |
428 | 660 { |
661 assert (!for_disksave); | |
791 | 662 /* If it's still in the list of processes we are waiting on delete |
2367 | 663 it. This can happen if we forcibly delete a process and are unable |
664 to kill it. */ | |
791 | 665 mswindows_unwait_process (p); |
442 | 666 if (NT_DATA (p)->h_process) |
2367 | 667 { |
668 CloseHandle (NT_DATA (p)->h_process); | |
669 NT_DATA (p)->h_process = 0; | |
670 } | |
428 | 671 } |
672 | |
673 /* | |
674 * Initialize XEmacs process implementation once | |
675 */ | |
676 static void | |
677 nt_init_process (void) | |
678 { | |
679 /* Initialize winsock */ | |
680 WSADATA wsa_data; | |
681 /* Request Winsock v1.1 Note the order: (minor=1, major=1) */ | |
682 WSAStartup (MAKEWORD (1,1), &wsa_data); | |
683 } | |
684 | |
853 | 685 /* |
686 * Fork off a subprocess. P is a pointer to newly created subprocess | |
687 * object. If this function signals, the caller is responsible for | |
688 * deleting (and finalizing) the process object. | |
689 * | |
690 * The method must return PID of the new process, a (positive??? ####) number | |
691 * which fits into Lisp_Int. No return value indicates an error, the method | |
692 * must signal an error instead. | |
693 */ | |
694 | |
563 | 695 static DOESNT_RETURN |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
696 mswindows_report_winsock_error (const Ascbyte *reason, Lisp_Object data, |
563 | 697 int errnum) |
428 | 698 { |
563 | 699 report_file_type_error (Qnetwork_error, mswindows_lisp_error (errnum), |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
700 reason, data); |
442 | 701 } |
702 | |
703 static void | |
704 ensure_console_window_exists (void) | |
705 { | |
771 | 706 if (mswindows_windows9x_p) |
442 | 707 mswindows_hide_console (); |
708 } | |
709 | |
710 int | |
771 | 711 mswindows_compare_env (const void *strp1, const void *strp2) |
442 | 712 { |
2367 | 713 const Itext *str1 = * (const Itext **) strp1, |
714 *str2 = * (const Itext **) strp2; | |
442 | 715 |
716 while (*str1 && *str2 && *str1 != '=' && *str2 != '=') | |
717 { | |
718 if ((*str1) > (*str2)) | |
719 return 1; | |
720 else if ((*str1) < (*str2)) | |
721 return -1; | |
722 str1++, str2++; | |
723 } | |
724 | |
725 if (*str1 == '=' && *str2 == '=') | |
726 return 0; | |
727 else if (*str1 == '=') | |
728 return -1; | |
729 else | |
730 return 1; | |
428 | 731 } |
732 | |
563 | 733 /* |
734 * Fork off a subprocess. P is a pointer to newly created subprocess | |
735 * object. If this function signals, the caller is responsible for | |
736 * deleting (and finalizing) the process object. | |
737 * | |
738 * The method must return PID of the new process, a (positive??? ####) number | |
739 * which fits into Lisp_Int. No return value indicates an error, the method | |
740 * must signal an error instead. | |
741 */ | |
742 | |
428 | 743 static int |
440 | 744 nt_create_process (Lisp_Process *p, |
428 | 745 Lisp_Object *argv, int nargv, |
853 | 746 Lisp_Object program, Lisp_Object cur_dir, |
747 int separate_err) | |
428 | 748 { |
442 | 749 /* Synched up with sys_spawnve in FSF 20.6. Significantly different |
750 but still synchable. */ | |
853 | 751 HANDLE hmyshove, hmyslurp, hmyslurp_err, hprocin, hprocout, hprocerr; |
442 | 752 Extbyte *command_line; |
428 | 753 BOOL do_io, windowed; |
771 | 754 Extbyte *proc_env; |
428 | 755 |
442 | 756 /* No need to DOS-ize the filename; expand-file-name (called prior) |
757 already does this. */ | |
758 | |
428 | 759 /* Find out whether the application is windowed or not */ |
771 | 760 { |
761 /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most | |
762 errors. This leads to bogus error message. */ | |
763 DWORD image_type; | |
1204 | 764 if (mswindows_is_executable (XSTRING_DATA (program))) |
771 | 765 { |
766 Extbyte *progext; | |
2526 | 767 LISP_PATHNAME_CONVERT_OUT (program, progext); |
771 | 768 image_type = qxeSHGetFileInfo (progext, 0, NULL, 0, SHGFI_EXETYPE); |
769 } | |
770 else | |
771 { | |
772 DECLARE_EISTRING (progext); | |
2526 | 773 Ibyte *prog2; |
774 LISP_PATHNAME_RESOLVE_LINKS (program, prog2); | |
775 eicpy_rawz (progext, prog2); | |
2421 | 776 eicat_ascii (progext, ".exe"); |
771 | 777 eito_external (progext, Qmswindows_tstr); |
778 image_type = qxeSHGetFileInfo (eiextdata (progext), 0, NULL, 0, | |
779 SHGFI_EXETYPE); | |
780 } | |
781 if (image_type == 0) | |
782 mswindows_report_process_error | |
783 ("Determining executable file type", | |
784 program, | |
785 GetLastError () == ERROR_FILE_NOT_FOUND | |
786 ? ERROR_BAD_FORMAT : GetLastError ()); | |
787 windowed = HIWORD (image_type) != 0; | |
788 } | |
789 | |
428 | 790 |
791 /* Decide whether to do I/O on process handles, or just mark the | |
792 process exited immediately upon successful launching. We do I/O if the | |
793 process is a console one, or if it is windowed but windowed_process_io | |
794 is non-zero */ | |
795 do_io = !windowed || windowed_process_io ; | |
854 | 796 |
428 | 797 if (do_io) |
798 { | |
799 /* Create two unidirectional named pipes */ | |
800 HANDLE htmp; | |
801 SECURITY_ATTRIBUTES sa; | |
802 | |
826 | 803 sa.nLength = sizeof (sa); |
428 | 804 sa.bInheritHandle = TRUE; |
805 sa.lpSecurityDescriptor = NULL; | |
806 | |
807 CreatePipe (&hprocin, &hmyshove, &sa, 0); | |
808 CreatePipe (&hmyslurp, &hprocout, &sa, 0); | |
809 | |
853 | 810 if (separate_err) |
811 CreatePipe (&hmyslurp_err, &hprocerr, &sa, 0); | |
812 else | |
813 /* Duplicate the stdout handle for use as stderr */ | |
2367 | 814 DuplicateHandle (GetCurrentProcess(), hprocout, GetCurrentProcess(), |
815 &hprocerr, 0, TRUE, DUPLICATE_SAME_ACCESS); | |
430 | 816 |
428 | 817 /* Stupid Win32 allows to create a pipe with *both* ends either |
818 inheritable or not. We need process ends inheritable, and local | |
819 ends not inheritable. */ | |
442 | 820 DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), |
821 &htmp, 0, FALSE, | |
822 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
428 | 823 hmyshove = htmp; |
442 | 824 DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), |
825 &htmp, 0, FALSE, | |
826 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
428 | 827 hmyslurp = htmp; |
853 | 828 if (separate_err) |
829 { | |
830 DuplicateHandle (GetCurrentProcess(), hmyslurp_err, | |
831 GetCurrentProcess(), &htmp, 0, FALSE, | |
832 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); | |
833 hmyslurp_err = htmp; | |
834 } | |
428 | 835 } |
836 | |
837 /* Convert an argv vector into Win32 style command line by a call to | |
442 | 838 lisp function `mswindows-construct-process-command-line' |
839 (in win32-native.el) */ | |
428 | 840 { |
841 int i; | |
842 Lisp_Object args_or_ret = Qnil; | |
843 struct gcpro gcpro1; | |
844 | |
845 GCPRO1 (args_or_ret); | |
846 | |
847 for (i = 0; i < nargv; ++i) | |
848 args_or_ret = Fcons (*argv++, args_or_ret); | |
849 args_or_ret = Fnreverse (args_or_ret); | |
850 args_or_ret = Fcons (program, args_or_ret); | |
851 | |
2367 | 852 /* This Lisp function is in win32-native.el and has lots of comments |
853 about what exactly is going on. */ | |
442 | 854 args_or_ret = call1 (Qmswindows_construct_process_command_line, |
855 args_or_ret); | |
428 | 856 |
857 if (!STRINGP (args_or_ret)) | |
858 /* Luser wrote his/her own clever version */ | |
442 | 859 invalid_argument |
860 ("Bogus return value from `mswindows-construct-process-command-line'", | |
861 args_or_ret); | |
428 | 862 |
2526 | 863 /* #### What about path names, which may be links? */ |
771 | 864 LISP_STRING_TO_TSTR (args_or_ret, command_line); |
428 | 865 |
866 UNGCPRO; /* args_or_ret */ | |
867 } | |
868 | |
869 /* Set `proc_env' to a nul-separated array of the strings in | |
870 Vprocess_environment terminated by 2 nuls. */ | |
771 | 871 |
428 | 872 { |
867 | 873 Ibyte **env; |
428 | 874 REGISTER Lisp_Object tem; |
867 | 875 REGISTER Ibyte **new_env; |
771 | 876 REGISTER int new_length = 0, i; |
854 | 877 |
428 | 878 for (tem = Vprocess_environment; |
879 (CONSP (tem) | |
880 && STRINGP (XCAR (tem))); | |
881 tem = XCDR (tem)) | |
882 new_length++; | |
442 | 883 |
884 /* FSF adds an extra env var to hold the current process ID of the | |
885 Emacs process. Apparently this is used only by emacsserver.c, | |
771 | 886 which we have superseded by gnuserv.c. (#### Does it work under |
442 | 887 MS Windows?) |
888 | |
854 | 889 sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d", |
442 | 890 GetCurrentProcessId ()); |
891 arglen += strlen (ppid_env_var_buffer) + 1; | |
892 numenv++; | |
893 */ | |
854 | 894 |
428 | 895 /* new_length + 1 to include terminating 0. */ |
867 | 896 env = new_env = alloca_array (Ibyte *, new_length + 1); |
854 | 897 |
428 | 898 /* Copy the Vprocess_environment strings into new_env. */ |
899 for (tem = Vprocess_environment; | |
900 (CONSP (tem) | |
901 && STRINGP (XCAR (tem))); | |
902 tem = XCDR (tem)) | |
903 { | |
867 | 904 Ibyte **ep = env; |
905 Ibyte *string = XSTRING_DATA (XCAR (tem)); | |
428 | 906 /* See if this string duplicates any string already in the env. |
907 If so, don't put it in. | |
908 When an env var has multiple definitions, | |
909 we keep the definition that comes first in process-environment. */ | |
910 for (; ep != new_env; ep++) | |
911 { | |
867 | 912 Ibyte *p = *ep, *q = string; |
428 | 913 while (1) |
914 { | |
915 if (*q == 0) | |
916 /* The string is malformed; might as well drop it. */ | |
917 goto duplicate; | |
918 if (*q != *p) | |
919 break; | |
920 if (*q == '=') | |
921 goto duplicate; | |
922 p++, q++; | |
923 } | |
924 } | |
925 *new_env++ = string; | |
926 duplicate: ; | |
927 } | |
928 *new_env = 0; | |
854 | 929 |
428 | 930 /* Sort the environment variables */ |
931 new_length = new_env - env; | |
867 | 932 qsort (env, new_length, sizeof (Ibyte *), mswindows_compare_env); |
771 | 933 |
934 { | |
935 DECLARE_EISTRING (envout); | |
936 | |
937 for (i = 0; i < new_length; i++) | |
938 { | |
1204 | 939 eicat_raw (envout, env[i], qxestrlen (env[i])); |
940 eicat_raw (envout, (Ibyte *) "\0", 1); | |
771 | 941 } |
942 | |
1204 | 943 eicat_raw (envout, (Ibyte *) "\0", 1); |
771 | 944 eito_external (envout, Qmswindows_tstr); |
945 proc_env = eiextdata (envout); | |
946 } | |
428 | 947 } |
442 | 948 |
949 #if 0 | |
950 /* #### we need to port this. */ | |
951 /* On Windows 95, if cmdname is a DOS app, we invoke a helper | |
952 application to start it by specifying the helper app as cmdname, | |
953 while leaving the real app name as argv[0]. */ | |
954 if (is_dos_app) | |
955 { | |
2421 | 956 cmdname = alloca_ibytes (PATH_MAX_INTERNAL); |
442 | 957 if (egetenv ("CMDPROXY")) |
771 | 958 qxestrcpy (cmdname, egetenv ("CMDPROXY")); |
442 | 959 else |
960 { | |
771 | 961 qxestrcpy (cmdname, XSTRING_DATA (Vinvocation_directory)); |
867 | 962 qxestrcat (cmdname, (Ibyte *) "cmdproxy.exe"); |
442 | 963 } |
964 } | |
965 #endif | |
854 | 966 |
428 | 967 /* Create process */ |
968 { | |
771 | 969 STARTUPINFOW si; |
428 | 970 PROCESS_INFORMATION pi; |
971 DWORD err; | |
442 | 972 DWORD flags; |
428 | 973 |
974 xzero (si); | |
975 si.dwFlags = STARTF_USESHOWWINDOW; | |
976 si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE; | |
977 if (do_io) | |
978 { | |
979 si.hStdInput = hprocin; | |
980 si.hStdOutput = hprocout; | |
430 | 981 si.hStdError = hprocerr; |
428 | 982 si.dwFlags |= STARTF_USESTDHANDLES; |
983 } | |
984 | |
442 | 985 flags = CREATE_SUSPENDED; |
771 | 986 if (mswindows_windows9x_p) |
442 | 987 flags |= (!NILP (Vmswindows_start_process_share_console) |
988 ? CREATE_NEW_PROCESS_GROUP | |
989 : CREATE_NEW_CONSOLE); | |
990 else | |
991 flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; | |
992 if (NILP (Vmswindows_start_process_inherit_error_mode)) | |
993 flags |= CREATE_DEFAULT_ERROR_MODE; | |
994 | |
995 ensure_console_window_exists (); | |
996 | |
771 | 997 { |
998 Extbyte *curdirext; | |
999 | |
2526 | 1000 LISP_PATHNAME_CONVERT_OUT (cur_dir, curdirext); |
771 | 1001 |
1002 err = (qxeCreateProcess (NULL, command_line, NULL, NULL, TRUE, | |
1003 (XEUNICODE_P ? | |
1004 flags | CREATE_UNICODE_ENVIRONMENT : | |
1005 flags), proc_env, | |
1006 curdirext, &si, &pi) | |
1007 ? 0 : GetLastError ()); | |
1008 } | |
428 | 1009 |
1010 if (do_io) | |
1011 { | |
1012 /* These just have been inherited; we do not need a copy */ | |
1013 CloseHandle (hprocin); | |
1014 CloseHandle (hprocout); | |
430 | 1015 CloseHandle (hprocerr); |
428 | 1016 } |
854 | 1017 |
428 | 1018 /* Handle process creation failure */ |
1019 if (err) | |
1020 { | |
1021 if (do_io) | |
1022 { | |
1023 CloseHandle (hmyshove); | |
1024 CloseHandle (hmyslurp); | |
853 | 1025 if (separate_err) |
1026 CloseHandle (hmyslurp_err); | |
428 | 1027 } |
563 | 1028 mswindows_report_process_error |
1029 ("Error starting", | |
1030 program, GetLastError ()); | |
428 | 1031 } |
1032 | |
1033 /* The process started successfully */ | |
1034 if (do_io) | |
1035 { | |
1036 NT_DATA(p)->h_process = pi.hProcess; | |
442 | 1037 NT_DATA(p)->dwProcessId = pi.dwProcessId; |
853 | 1038 init_process_io_handles (p, (void *) hmyslurp, (void *) hmyshove, |
1039 separate_err ? (void *) hmyslurp_err | |
1040 : (void *) -1, 0); | |
428 | 1041 } |
1042 else | |
1043 { | |
1044 /* Indicate as if the process has exited immediately. */ | |
1045 p->status_symbol = Qexit; | |
1046 CloseHandle (pi.hProcess); | |
1047 } | |
1048 | |
442 | 1049 if (!windowed) |
1050 enable_child_signals (pi.hProcess); | |
1051 | |
428 | 1052 ResumeThread (pi.hThread); |
1053 CloseHandle (pi.hThread); | |
1054 | |
432 | 1055 return ((int)pi.dwProcessId); |
428 | 1056 } |
1057 } | |
1058 | |
854 | 1059 /* |
428 | 1060 * This method is called to update status fields of the process |
1061 * structure. If the process has not existed, this method is expected | |
1062 * to do nothing. | |
1063 * | |
854 | 1064 * The method is called only for real child processes. |
428 | 1065 */ |
1066 | |
1067 static void | |
771 | 1068 nt_update_status_if_terminated (Lisp_Process *p) |
428 | 1069 { |
1070 DWORD exit_code; | |
1071 if (GetExitCodeProcess (NT_DATA(p)->h_process, &exit_code) | |
1072 && exit_code != STILL_ACTIVE) | |
1073 { | |
1074 p->tick++; | |
1075 p->core_dumped = 0; | |
1076 /* The exit code can be a code returned by process, or an | |
1077 NTSTATUS value. We cannot accurately handle the latter since | |
1078 it is a full 32 bit integer */ | |
1079 if (exit_code & 0xC0000000) | |
1080 { | |
1081 p->status_symbol = Qsignal; | |
1082 p->exit_code = exit_code & 0x1FFFFFFF; | |
1083 } | |
1084 else | |
1085 { | |
1086 p->status_symbol = Qexit; | |
1087 p->exit_code = exit_code; | |
1088 } | |
1089 } | |
1090 } | |
1091 | |
1092 /* | |
1093 * Stuff the entire contents of LSTREAM to the process output pipe | |
1094 */ | |
1095 | |
1096 /* #### If only this function could be somehow merged with | |
1097 unix_send_process... */ | |
1098 | |
1099 static void | |
771 | 1100 nt_send_process (Lisp_Object proc, struct lstream *lstream) |
428 | 1101 { |
432 | 1102 volatile Lisp_Object vol_proc = proc; |
440 | 1103 Lisp_Process *volatile p = XPROCESS (proc); |
428 | 1104 |
1105 /* use a reasonable-sized buffer (somewhere around the size of the | |
1106 stream buffer) so as to avoid inundating the stream with blocked | |
1107 data. */ | |
867 | 1108 Ibyte chunkbuf[512]; |
428 | 1109 Bytecount chunklen; |
1110 | |
1111 while (1) | |
1112 { | |
771 | 1113 int writeret; |
428 | 1114 |
442 | 1115 chunklen = Lstream_read (lstream, chunkbuf, 512); |
428 | 1116 if (chunklen <= 0) |
2500 | 1117 break; /* perhaps should ABORT() if < 0? |
428 | 1118 This should never happen. */ |
1119 | |
1120 /* Lstream_write() will never successfully write less than the | |
1121 amount sent in. In the worst case, it just buffers the | |
1122 unwritten data. */ | |
771 | 1123 writeret = Lstream_write (XLSTREAM (DATA_OUTSTREAM (p)), chunkbuf, |
428 | 1124 chunklen); |
771 | 1125 Lstream_flush (XLSTREAM (DATA_OUTSTREAM (p))); |
428 | 1126 if (writeret < 0) |
1127 { | |
1128 p->status_symbol = Qexit; | |
1129 p->exit_code = ERROR_BROKEN_PIPE; | |
1130 p->core_dumped = 0; | |
1131 p->tick++; | |
1132 process_tick++; | |
432 | 1133 deactivate_process (*((Lisp_Object *) (&vol_proc))); |
442 | 1134 invalid_operation ("Broken pipe error sending to process; closed it", |
1135 p->name); | |
428 | 1136 } |
1137 | |
1138 { | |
1139 int wait_ms = 25; | |
1140 while (Lstream_was_blocked_p (XLSTREAM (p->pipe_outstream))) | |
1141 { | |
1142 /* Buffer is full. Wait, accepting input; that may allow | |
1143 the program to finish doing output and read more. */ | |
1144 Faccept_process_output (Qnil, Qzero, make_int (wait_ms)); | |
1145 Lstream_flush (XLSTREAM (p->pipe_outstream)); | |
1146 wait_ms = min (1000, 2 * wait_ms); | |
1147 } | |
1148 } | |
1149 } | |
1150 } | |
1151 | |
2367 | 1152 static void |
1153 nt_deactivate_process (Lisp_Process *p, | |
1154 USID *in_usid, | |
1155 USID *err_usid) | |
1156 { | |
1157 event_stream_delete_io_streams (p->pipe_instream, p->pipe_outstream, | |
1158 p->pipe_errstream, in_usid, err_usid); | |
1159 /* Go ahead and close the process handle now to prevent accumulation | |
1160 of handles when lots of processes are run. (The handle gets closed | |
1161 anyway upon GC, but that might be a ways away, esp. if | |
1162 deleted-exited-processes is set to nil.) */ | |
1163 nt_finalize_process_data (p, 0); | |
1164 } | |
1165 | |
428 | 1166 /* |
1167 * Send a signal number SIGNO to PROCESS. | |
1168 * CURRENT_GROUP means send to the process group that currently owns | |
1169 * the terminal being used to communicate with PROCESS. | |
1170 * This is used for various commands in shell mode. | |
1171 * If NOMSG is zero, insert signal-announcements into process's buffers | |
1172 * right away. | |
1173 * | |
1174 * If we can, we try to signal PROCESS by sending control characters | |
1175 * down the pty. This allows us to signal inferiors who have changed | |
1176 * their uid, for which killpg would return an EPERM error. | |
1177 * | |
1178 * The method signals an error if the given SIGNO is not valid | |
1179 */ | |
1180 | |
1181 static void | |
1182 nt_kill_child_process (Lisp_Object proc, int signo, | |
2286 | 1183 int UNUSED (current_group), int UNUSED (nomsg)) |
428 | 1184 { |
440 | 1185 Lisp_Process *p = XPROCESS (proc); |
428 | 1186 |
1187 /* Signal error if SIGNO cannot be sent */ | |
1188 validate_signal_number (signo); | |
1189 | |
1190 /* Send signal */ | |
442 | 1191 if (!send_signal (NT_DATA (p), 0, signo)) |
1192 invalid_operation ("Cannot send signal to process", proc); | |
428 | 1193 } |
1194 | |
1195 /* | |
442 | 1196 * Kill any process in the system given its PID |
428 | 1197 * |
1198 * Returns zero if a signal successfully sent, or | |
1199 * negative number upon failure | |
1200 */ | |
1201 static int | |
1202 nt_kill_process_by_pid (int pid, int signo) | |
1203 { | |
442 | 1204 struct Lisp_Process *p; |
1205 | |
428 | 1206 /* Signal error if SIGNO cannot be sent */ |
1207 validate_signal_number (signo); | |
1208 | |
442 | 1209 p = find_process_from_pid (pid); |
1210 return send_signal (p ? NT_DATA (p) : 0, pid, signo) ? 0 : -1; | |
428 | 1211 } |
1212 | |
1213 /*-----------------------------------------------------------------------*/ | |
1214 /* Sockets connections */ | |
1215 /*-----------------------------------------------------------------------*/ | |
1216 #ifdef HAVE_SOCKETS | |
1217 | |
1218 /* #### Hey MS, how long Winsock 2 for '95 will be in beta? */ | |
1219 | |
1220 #define SOCK_TIMER_ID 666 | |
1221 #define XM_SOCKREPLY (WM_USER + 666) | |
1222 | |
563 | 1223 /* Return 0 for success, or error code */ |
1224 | |
428 | 1225 static int |
563 | 1226 get_internet_address (Lisp_Object host, struct sockaddr_in *address) |
428 | 1227 { |
2367 | 1228 CBinbyte buf[MAXGETHOSTSTRUCT]; |
428 | 1229 HWND hwnd; |
1230 HANDLE hasync; | |
563 | 1231 int errcode = 0; |
428 | 1232 |
1233 address->sin_family = AF_INET; | |
1234 | |
1235 /* First check if HOST is already a numeric address */ | |
1236 { | |
1204 | 1237 Extbyte *hostext; |
1238 unsigned long inaddr; | |
1239 | |
1240 LISP_STRING_TO_EXTERNAL (host, hostext, Qmswindows_host_name_encoding); | |
1241 inaddr = inet_addr (hostext); | |
428 | 1242 if (inaddr != INADDR_NONE) |
1243 { | |
1244 address->sin_addr.s_addr = inaddr; | |
563 | 1245 return 0; |
428 | 1246 } |
1247 } | |
1248 | |
1249 /* Create a window which will receive completion messages */ | |
771 | 1250 hwnd = qxeCreateWindow (XETEXT ("STATIC"), NULL, WS_OVERLAPPED, 0, 0, 1, 1, |
1251 NULL, NULL, NULL, NULL); | |
428 | 1252 assert (hwnd); |
1253 | |
1254 /* Post name resolution request */ | |
771 | 1255 { |
1256 Extbyte *hostext; | |
1257 | |
1258 LISP_STRING_TO_EXTERNAL (host, hostext, Qmswindows_host_name_encoding); | |
1259 | |
1260 hasync = WSAAsyncGetHostByName (hwnd, XM_SOCKREPLY, hostext, | |
1261 buf, sizeof (buf)); | |
1262 if (hasync == NULL) | |
1263 { | |
1264 errcode = WSAGetLastError (); | |
1265 goto done; | |
1266 } | |
1267 } | |
428 | 1268 |
1269 /* Set a timer to poll for quit every 250 ms */ | |
1270 SetTimer (hwnd, SOCK_TIMER_ID, 250, NULL); | |
1271 | |
1272 while (1) | |
1273 { | |
1274 MSG msg; | |
800 | 1275 qxeGetMessage (&msg, hwnd, 0, 0); |
428 | 1276 if (msg.message == XM_SOCKREPLY) |
1277 { | |
1278 /* Ok, got an answer */ | |
563 | 1279 errcode = WSAGETASYNCERROR (msg.lParam); |
428 | 1280 goto done; |
1281 } | |
1282 else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID) | |
1283 { | |
1284 if (QUITP) | |
1285 { | |
1286 WSACancelAsyncRequest (hasync); | |
1287 KillTimer (hwnd, SOCK_TIMER_ID); | |
1288 DestroyWindow (hwnd); | |
853 | 1289 QUIT; |
428 | 1290 } |
1291 } | |
800 | 1292 qxeDispatchMessage (&msg); |
428 | 1293 } |
1294 | |
1295 done: | |
1296 KillTimer (hwnd, SOCK_TIMER_ID); | |
1297 DestroyWindow (hwnd); | |
563 | 1298 if (!errcode) |
428 | 1299 { |
1300 /* BUF starts with struct hostent */ | |
771 | 1301 struct hostent *he = (struct hostent *) buf; |
1302 address->sin_addr.s_addr = * (unsigned long *) he->h_addr_list[0]; | |
428 | 1303 } |
563 | 1304 return errcode; |
428 | 1305 } |
1306 | |
1307 static Lisp_Object | |
1308 nt_canonicalize_host_name (Lisp_Object host) | |
1309 { | |
1310 struct sockaddr_in address; | |
1311 | |
563 | 1312 if (get_internet_address (host, &address)) /* error */ |
428 | 1313 return host; |
1314 | |
1315 if (address.sin_family == AF_INET) | |
4952
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
1316 return build_ext_string (inet_ntoa (address.sin_addr), |
19a72041c5ed
Mule-izing, various fixes related to char * arguments
Ben Wing <ben@xemacs.org>
parents:
2526
diff
changeset
|
1317 Qunix_host_name_encoding); |
428 | 1318 else |
1319 return host; | |
1320 } | |
1321 | |
1322 /* open a TCP network connection to a given HOST/SERVICE. Treated | |
1323 exactly like a normal process when reading and writing. Only | |
1324 differences are in status display and process deletion. A network | |
1325 connection has no PID; you cannot signal it. All you can do is | |
1326 deactivate and close it via delete-process */ | |
1327 | |
1328 static void | |
442 | 1329 nt_open_network_stream (Lisp_Object name, Lisp_Object host, |
1330 Lisp_Object service, | |
771 | 1331 Lisp_Object protocol, void **vinfd, void **voutfd) |
428 | 1332 { |
1333 struct sockaddr_in address; | |
1334 SOCKET s; | |
1335 int port; | |
1336 int retval; | |
563 | 1337 int errnum; |
428 | 1338 |
1339 CHECK_STRING (host); | |
1340 | |
1341 if (!EQ (protocol, Qtcp)) | |
563 | 1342 invalid_constant ("Unsupported protocol", protocol); |
428 | 1343 |
1344 if (INTP (service)) | |
1345 port = htons ((unsigned short) XINT (service)); | |
1346 else | |
1347 { | |
1348 struct servent *svc_info; | |
771 | 1349 Extbyte *servext; |
1350 | |
428 | 1351 CHECK_STRING (service); |
771 | 1352 LISP_STRING_TO_EXTERNAL (service, servext, |
1353 Qmswindows_service_name_encoding); | |
1354 | |
1355 svc_info = getservbyname (servext, "tcp"); | |
428 | 1356 if (svc_info == 0) |
442 | 1357 invalid_argument ("Unknown service", service); |
428 | 1358 port = svc_info->s_port; |
1359 } | |
1360 | |
563 | 1361 retval = get_internet_address (host, &address); |
1362 if (retval) | |
1363 mswindows_report_winsock_error ("Getting IP address", host, | |
1364 retval); | |
428 | 1365 address.sin_port = port; |
1366 | |
1367 s = socket (address.sin_family, SOCK_STREAM, 0); | |
1368 if (s < 0) | |
563 | 1369 mswindows_report_winsock_error ("Creating socket", name, |
1370 WSAGetLastError ()); | |
428 | 1371 |
1372 /* We don't want to be blocked on connect */ | |
1373 { | |
1374 unsigned long nonblock = 1; | |
1375 ioctlsocket (s, FIONBIO, &nonblock); | |
1376 } | |
854 | 1377 |
428 | 1378 retval = connect (s, (struct sockaddr *) &address, sizeof (address)); |
1379 if (retval != NO_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) | |
563 | 1380 { |
1381 errnum = WSAGetLastError (); | |
1382 goto connect_failed; | |
1383 } | |
1384 | |
1385 #if 0 /* PUTA! I thought getsockopt() was failing, so I created the | |
1386 following based on the code in get_internet_address(), but | |
1387 it was my own fault down below. Both versions should work. */ | |
428 | 1388 /* Wait while connection is established */ |
563 | 1389 { |
1390 HWND hwnd; | |
1391 | |
1392 /* Create a window which will receive completion messages */ | |
771 | 1393 hwnd = qxeCreateWindow (XETEXT ("STATIC"), NULL, WS_OVERLAPPED, 0, 0, 1, 1, |
1394 NULL, NULL, NULL, NULL); | |
563 | 1395 assert (hwnd); |
1396 | |
1397 /* Post request */ | |
1398 if (WSAAsyncSelect (s, hwnd, XM_SOCKREPLY, FD_CONNECT)) | |
1399 { | |
1400 errnum = WSAGetLastError (); | |
1401 goto done; | |
1402 } | |
1403 | |
1404 /* Set a timer to poll for quit every 250 ms */ | |
1405 SetTimer (hwnd, SOCK_TIMER_ID, 250, NULL); | |
1406 | |
1407 while (1) | |
1408 { | |
1409 MSG msg; | |
1410 GetMessage (&msg, hwnd, 0, 0); | |
1411 if (msg.message == XM_SOCKREPLY) | |
1412 { | |
1413 /* Ok, got an answer */ | |
1414 errnum = WSAGETASYNCERROR (msg.lParam); | |
1415 goto done; | |
1416 } | |
1417 | |
1418 else if (msg.message == WM_TIMER && msg.wParam == SOCK_TIMER_ID) | |
1419 { | |
1420 if (QUITP) | |
1421 { | |
1422 WSAAsyncSelect (s, hwnd, XM_SOCKREPLY, 0); | |
1423 KillTimer (hwnd, SOCK_TIMER_ID); | |
1424 DestroyWindow (hwnd); | |
853 | 1425 QUIT; |
563 | 1426 } |
1427 } | |
1428 DispatchMessage (&msg); | |
1429 } | |
1430 | |
1431 done: | |
1432 WSAAsyncSelect (s, hwnd, XM_SOCKREPLY, 0); | |
1433 KillTimer (hwnd, SOCK_TIMER_ID); | |
1434 DestroyWindow (hwnd); | |
1435 if (errnum) | |
1436 goto connect_failed; | |
1437 } | |
1438 | |
1439 #else | |
428 | 1440 while (1) |
1441 { | |
563 | 1442 fd_set fdwriteset, fdexceptset; |
428 | 1443 struct timeval tv; |
1444 int nsel; | |
1445 | |
1446 if (QUITP) | |
1447 { | |
1448 closesocket (s); | |
853 | 1449 QUIT; |
428 | 1450 } |
1451 | |
1452 /* Poll for quit every 250 ms */ | |
1453 tv.tv_sec = 0; | |
1454 tv.tv_usec = 250 * 1000; | |
1455 | |
563 | 1456 FD_ZERO (&fdwriteset); |
1457 FD_SET (s, &fdwriteset); | |
1458 FD_ZERO (&fdexceptset); | |
1459 FD_SET (s, &fdexceptset); | |
1460 nsel = select (0, NULL, &fdwriteset, &fdexceptset, &tv); | |
1461 | |
1462 if (nsel == SOCKET_ERROR) | |
1463 { | |
1464 errnum = WSAGetLastError (); | |
1465 goto connect_failed; | |
1466 } | |
428 | 1467 |
1468 if (nsel > 0) | |
1469 { | |
1470 /* Check: was connection successful or not? */ | |
563 | 1471 if (FD_ISSET (s, &fdwriteset)) |
1472 break; | |
1473 else if (FD_ISSET (s, &fdexceptset)) | |
1474 { | |
1475 int store_me_harder = sizeof (errnum); | |
1476 /* OK, we finally can get the REAL error code. Any paths | |
1477 in this code that lead to a call of WSAGetLastError() | |
1478 indicate probable logic failure. */ | |
1479 if (getsockopt (s, SOL_SOCKET, SO_ERROR, (char *) &errnum, | |
1480 &store_me_harder)) | |
1481 errnum = WSAGetLastError (); | |
1482 goto connect_failed; | |
1483 } | |
428 | 1484 else |
563 | 1485 { |
1486 signal_error (Qinternal_error, | |
1487 "Porra, esse caralho de um sistema de operacao", | |
1488 Qunbound); | |
1489 break; | |
1490 } | |
428 | 1491 } |
1492 } | |
563 | 1493 #endif |
428 | 1494 |
1495 /* We are connected at this point */ | |
771 | 1496 *vinfd = (void *)s; |
428 | 1497 DuplicateHandle (GetCurrentProcess(), (HANDLE)s, |
1498 GetCurrentProcess(), (LPHANDLE)voutfd, | |
1499 0, FALSE, DUPLICATE_SAME_ACCESS); | |
1500 return; | |
1501 | |
563 | 1502 connect_failed: |
1503 { | |
1504 closesocket (s); | |
1505 mswindows_report_winsock_error ("Connection failed", | |
1506 list3 (Qunbound, host, service), | |
1507 errnum); | |
1508 } | |
428 | 1509 } |
1510 | |
1511 #endif | |
771 | 1512 |
1513 | |
1514 DEFUN ("mswindows-set-process-priority", Fmswindows_set_process_priority, 2, 2, "", /* | |
1515 Set the priority of PROCESS to PRIORITY. | |
1516 If PROCESS is nil, the priority of Emacs is changed, otherwise the | |
1517 priority of the process whose pid is PROCESS is changed. | |
1518 PRIORITY should be one of the symbols high, normal, or low; | |
1519 any other symbol will be interpreted as normal. | |
1520 | |
1521 If successful, the return value is t, otherwise nil. | |
1522 */ | |
1523 (process, priority)) | |
1524 { | |
1525 HANDLE proc_handle = GetCurrentProcess (); | |
1526 DWORD priority_class = NORMAL_PRIORITY_CLASS; | |
1527 Lisp_Object result = Qnil; | |
1528 | |
1529 CHECK_SYMBOL (priority); | |
1530 | |
1531 if (!NILP (process)) | |
1532 { | |
1533 DWORD pid; | |
1534 struct Lisp_Process *p = 0; | |
1535 | |
1536 if (PROCESSP (process)) | |
1537 { | |
1538 CHECK_LIVE_PROCESS (process); | |
1539 p = XPROCESS (process); | |
1540 pid = NT_DATA (p)->dwProcessId; | |
1541 } | |
1542 else | |
1543 { | |
1544 CHECK_INT (process); | |
1545 | |
1546 /* Allow pid to be an internally generated one, or one obtained | |
1547 externally. This is necessary because real pids on Win95 are | |
1548 negative. */ | |
1549 | |
1550 pid = XINT (process); | |
1551 p = find_process_from_pid (pid); | |
1552 if (p != NULL) | |
1553 pid = NT_DATA (p)->dwProcessId; | |
1554 } | |
1555 | |
1556 /* #### Should we be using the existing process handle from NT_DATA(p)? | |
1557 Will we fail if we open it a second time? */ | |
1558 proc_handle = OpenProcess (PROCESS_SET_INFORMATION, FALSE, pid); | |
1559 } | |
1560 | |
1561 if (EQ (priority, Qhigh)) | |
1562 priority_class = HIGH_PRIORITY_CLASS; | |
1563 else if (EQ (priority, Qlow)) | |
1564 priority_class = IDLE_PRIORITY_CLASS; | |
1565 | |
1566 if (proc_handle != NULL) | |
1567 { | |
1568 if (SetPriorityClass (proc_handle, priority_class)) | |
1569 result = Qt; | |
1570 if (!NILP (process)) | |
1571 CloseHandle (proc_handle); | |
1572 } | |
1573 | |
1574 return result; | |
1575 } | |
1576 | |
428 | 1577 |
1578 /*-----------------------------------------------------------------------*/ | |
1579 /* Initialization */ | |
1580 /*-----------------------------------------------------------------------*/ | |
1581 | |
1582 void | |
1583 process_type_create_nt (void) | |
1584 { | |
1585 PROCESS_HAS_METHOD (nt, alloc_process_data); | |
1586 PROCESS_HAS_METHOD (nt, finalize_process_data); | |
1587 PROCESS_HAS_METHOD (nt, init_process); | |
1588 PROCESS_HAS_METHOD (nt, create_process); | |
1589 PROCESS_HAS_METHOD (nt, update_status_if_terminated); | |
1590 PROCESS_HAS_METHOD (nt, send_process); | |
2367 | 1591 PROCESS_HAS_METHOD (nt, deactivate_process); |
428 | 1592 PROCESS_HAS_METHOD (nt, kill_child_process); |
1593 PROCESS_HAS_METHOD (nt, kill_process_by_pid); | |
1594 #ifdef HAVE_SOCKETS | |
1595 PROCESS_HAS_METHOD (nt, canonicalize_host_name); | |
1596 PROCESS_HAS_METHOD (nt, open_network_stream); | |
1597 #ifdef HAVE_MULTICAST | |
1598 #error I won't do this until '95 has winsock2 | |
1599 PROCESS_HAS_METHOD (nt, open_multicast_group); | |
1600 #endif | |
1601 #endif | |
1602 } | |
1603 | |
1604 void | |
1605 syms_of_process_nt (void) | |
1606 { | |
771 | 1607 DEFSUBR (Fmswindows_set_process_priority); |
442 | 1608 DEFSYMBOL (Qmswindows_construct_process_command_line); |
428 | 1609 } |
1610 | |
1611 void | |
1612 vars_of_process_nt (void) | |
1613 { | |
442 | 1614 DEFVAR_LISP ("mswindows-start-process-share-console", |
1615 &Vmswindows_start_process_share_console /* | |
1616 When nil, new child processes are given a new console. | |
1617 When non-nil, they share the Emacs console; this has the limitation of | |
638 | 1618 allowing only one DOS subprocess to run at a time (whether started directly |
442 | 1619 or indirectly by Emacs), and preventing Emacs from cleanly terminating the |
1620 subprocess group, but may allow Emacs to interrupt a subprocess that doesn't | |
1621 otherwise respond to interrupts from Emacs. | |
1622 */ ); | |
1623 Vmswindows_start_process_share_console = Qnil; | |
1624 | |
1625 DEFVAR_LISP ("mswindows-start-process-inherit-error-mode", | |
1626 &Vmswindows_start_process_inherit_error_mode /* | |
1627 "When nil, new child processes revert to the default error mode. | |
1628 When non-nil, they inherit their error mode setting from Emacs, which stops | |
1629 them blocking when trying to access unmounted drives etc. | |
1630 */ ); | |
1631 Vmswindows_start_process_inherit_error_mode = Qt; | |
428 | 1632 } |