diff src/process-nt.c @ 278:90d73dddcdc4 r21-0b37

Import from CVS: tag r21-0b37
author cvs
date Mon, 13 Aug 2007 10:31:29 +0200
parents 6330739388db
children 7df0dd720c89
line wrap: on
line diff
--- a/src/process-nt.c	Mon Aug 13 10:30:38 2007 +0200
+++ b/src/process-nt.c	Mon Aug 13 10:31:29 2007 +0200
@@ -30,8 +30,10 @@
 #include "lstream.h"
 #include "process.h"
 #include "procimpl.h"
+#include "sysdep.h"
 
 #include <windows.h>
+#include <shellapi.h>
 
 /* Implemenation-specific data. Pointed to by Lisp_Process->process_data */
 struct nt_process_data
@@ -124,36 +126,61 @@
 
 /* #### This function completely ignores Vprocess_environment */
 
+static void
+signal_cannot_launch (char* image_file, DWORD err)
+{
+  mswindows_set_errno (err);
+  error ("Starting \"%s\": %s", image_file, strerror (errno));
+}
+
 static int
 nt_create_process (struct Lisp_Process *p,
 		   char **argv, CONST char *current_dir)
 {
   HANDLE hmyshove, hmyslurp, hprocin, hprocout;
   LPTSTR command_line;
-  
-  /* Create two unidirectional named pipes */
+  BOOL do_io, windowed;
+
+  /* Find out whether the application is windowed or not */
   {
-    HANDLE htmp;
-    SECURITY_ATTRIBUTES sa;
-
-    sa.nLength = sizeof(sa);
-    sa.bInheritHandle = TRUE;
-    sa.lpSecurityDescriptor = NULL;
+    /* SHGetFileInfo tends to return ERROR_FILE_NOT_FOUND on most
+       errors. This leads to bogus error message. */
+    DWORD image_type = SHGetFileInfo (argv[0], 0, NULL, 0, SHGFI_EXETYPE);
+    if (image_type == 0)
+      signal_cannot_launch (argv[0], (GetLastError () == ERROR_FILE_NOT_FOUND
+				      ? ERROR_BAD_FORMAT : GetLastError ()));
+    windowed = HIWORD (image_type) != 0;
+  }
 
-    CreatePipe (&hprocin, &hmyshove, &sa, 0);
-    CreatePipe (&hmyslurp, &hprocout, &sa, 0);
+  /* Decide whether to do I/O on process handles, or just mark the
+     process exited immediately upon successful launching. We do I/O if the
+     process is a console one, or if it is windowed but windowed_process_io
+     is non-zero */
+  do_io = !windowed || windowed_process_io ;
+  
+  if (do_io)
+    {
+      /* Create two unidirectional named pipes */
+      HANDLE htmp;
+      SECURITY_ATTRIBUTES sa;
 
-    /* Stupid Win32 allows to create a pipe with *both* ends either
-       inheritable or not. We need process ends inheritable, and local
-       ends not inheritable. */
-    /* #### Perhaps even stupider me does not know how to do this better */
-    DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp,
-		     0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
-    hmyshove = htmp;
-    DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), &htmp,
-		     0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
-    hmyslurp = htmp;
-  }
+      sa.nLength = sizeof(sa);
+      sa.bInheritHandle = TRUE;
+      sa.lpSecurityDescriptor = NULL;
+
+      CreatePipe (&hprocin, &hmyshove, &sa, 0);
+      CreatePipe (&hmyslurp, &hprocout, &sa, 0);
+
+      /* Stupid Win32 allows to create a pipe with *both* ends either
+	 inheritable or not. We need process ends inheritable, and local
+	 ends not inheritable. */
+      DuplicateHandle (GetCurrentProcess(), hmyshove, GetCurrentProcess(), &htmp,
+		       0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+      hmyshove = htmp;
+      DuplicateHandle (GetCurrentProcess(), hmyslurp, GetCurrentProcess(), &htmp,
+		       0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+      hmyslurp = htmp;
+    }
 
   /* Convert an argv vector into Win32 style command line.
 
@@ -186,74 +213,57 @@
     STARTUPINFO si;
     PROCESS_INFORMATION pi;
     DWORD err;
-    BOOL windowed;
 
     xzero (si);
-    si.hStdInput = hprocin;
-    si.hStdOutput = hprocout;
-    si.hStdError = hprocout;
-    si.wShowWindow = SW_HIDE;
-    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-	
-    err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE,
-			  CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP |	CREATE_SUSPENDED,
-			  NULL, current_dir, &si, &pi)
-	   ? 0 : GetLastError ());
-      
-    CloseHandle (hprocin);
-    CloseHandle (hprocout);
-
-    /* See if we succeeded with process creation */
-    if (err)
+    si.dwFlags = STARTF_USESHOWWINDOW;
+    si.wShowWindow = windowed ? SW_SHOWNORMAL : SW_HIDE;
+    if (do_io)
       {
-      process_error__One_of_those_nasty_uses_for_goto_statement:
-	CloseHandle (hmyshove);
-	CloseHandle (hmyslurp);
-	error ("Cannot start \"%s\": error code was %lu", argv[0], err);
+	si.hStdInput = hprocin;
+	si.hStdOutput = hprocout;
+	si.hStdError = hprocout;
+	si.dwFlags |= STARTF_USESTDHANDLES;
       }
 
-    /* Determine if the new process is a windowed one */
-    windowed = WaitForInputIdle (pi.hProcess, 100) == WAIT_TIMEOUT;
-    if (windowed)
+    err = (CreateProcess (NULL, command_line, NULL, NULL, TRUE,
+			  CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
+			  NULL, current_dir, &si, &pi)
+	   ? 0 : GetLastError ());
+
+    if (do_io)
       {
-	/* We restart windowed process fire-and forget style, and
-	   indicate successful process creation, just as if the
-	   process ended instantly upon launching */
-	CloseHandle (hmyshove);
-	CloseHandle (hmyslurp);
-	/* TerminateProcess is safe becuase the process is not yet
-	   running */
-	TerminateProcess (pi.hProcess, 0);
-	si.dwFlags = STARTF_USESHOWWINDOW;
-	si.wShowWindow = SW_SHOWNORMAL;
-	if (!CreateProcess (NULL, command_line, NULL, NULL, FALSE,
-			    DETACHED_PROCESS , NULL, current_dir, &si, &pi))
+	/* These just have been inherited; we do not need a copy */
+	CloseHandle (hprocin);
+	CloseHandle (hprocout);
+      }
+    
+    /* Handle process creation failure */
+    if (err)
+      {
+	if (do_io)
 	  {
-	    err = GetLastError ();
-	    goto process_error__One_of_those_nasty_uses_for_goto_statement;
+	    CloseHandle (hmyshove);
+	    CloseHandle (hmyslurp);
 	  }
+	signal_cannot_launch (argv[0], GetLastError ());
+      }
 
-	/* We just launched a windowed process. Fake it as if a
-	   process launched has already ended */
-	p->status_symbol = Qexit;
-
-	/* Get rid of process and thread handles */
-	CloseHandle (pi.hThread);
-	CloseHandle (pi.hProcess);
+    /* The process started successfully */
+    if (do_io)
+      {
+	NT_DATA(p)->h_process = pi.hProcess;
+	init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0);
       }
     else
       {
-	/* Just started a console subprocess */
-
-	NT_DATA(p)->h_process = pi.hProcess;
-
-	init_process_io_handles (p, (void*)hmyslurp, (void*)hmyshove, 0);
-	
-	/* We created it suspended. Resume the only thread */
-	ResumeThread (pi.hThread);
-	CloseHandle (pi.hThread);
+	/* Indicate as if the process has exited immediately. */
+	p->status_symbol = Qexit;
+	CloseHandle (pi.hProcess);
       }
 
+    CloseHandle (pi.hThread);
+
+    /* Hack to support Windows 95 negative pids */
     return ((int)pi.dwProcessId < 0
 	    ? -(int)pi.dwProcessId : (int)pi.dwProcessId);
   }