(displayed_window_lines): Take empty lines at
[bpt/emacs.git] / src / w32.c
index 71ba574..a7fd593 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -57,6 +57,8 @@ Boston, MA 02111-1307, USA.
 #undef read
 #undef write
 
+#undef strerror
+
 #include "lisp.h"
 
 #include <pwd.h>
@@ -89,6 +91,7 @@ Boston, MA 02111-1307, USA.
 extern Lisp_Object Vw32_downcase_file_names;
 extern Lisp_Object Vw32_generate_fake_inodes;
 extern Lisp_Object Vw32_get_true_file_attributes;
+extern Lisp_Object Vw32_num_mouse_buttons;
 
 static char startup_dir[MAXPATHLEN];
 
@@ -465,7 +468,7 @@ get_long_basename (char * name, char * buf, int size)
   HANDLE dir_handle;
   int len = 0;
 
-  /* must be valid filename, no wild cards or other illegal characters */
+  /* must be valid filename, no wild cards or other invalid characters */
   if (strpbrk (name, "*?|<>\""))
     return 0;
 
@@ -503,9 +506,10 @@ w32_get_long_filename (char * name, char * buf, int size)
   len = parse_root (full, &p);
   memcpy (o, full, len);
   o += len;
+  *o = '\0';
   size -= len;
 
-  do
+  while (p != NULL && *p)
     {
       q = p;
       p = strchr (q, '\\');
@@ -528,11 +532,23 @@ w32_get_long_filename (char * name, char * buf, int size)
       else
        return FALSE;
     }
-  while (p != NULL && *p);
 
   return TRUE;
 }
 
+int
+is_unc_volume (const char *filename)
+{
+  const char *ptr = filename;
+
+  if (!IS_DIRECTORY_SEP (ptr[0]) || !IS_DIRECTORY_SEP (ptr[1]) || !ptr[2])
+    return 0;
+
+  if (strpbrk (ptr + 2, "*?|<>\"\\/"))
+    return 0;
+
+  return 1;
+}
 
 /* Routines that are no-ops on NT but are defined to get Emacs to compile.  */
 
@@ -542,12 +558,24 @@ sigsetmask (int signal_mask)
   return 0;
 }
 
+int 
+sigmask (int sig) 
+{ 
+  return 0;
+}
+
 int 
 sigblock (int sig) 
 { 
   return 0;
 }
 
+int 
+sigunblock (int sig) 
+{ 
+  return 0;
+}
+
 int 
 setpgrp (int pid, int gid) 
 { 
@@ -626,7 +654,7 @@ char *get_emacs_configuration (void);
 extern Lisp_Object Vsystem_configuration;
 
 void
-init_environment ()
+init_environment (char ** argv)
 {
   int len;
   static const char * const tempdirs[] = {
@@ -745,7 +773,7 @@ init_environment ()
 
   {
     char *p;
-    char modname[MAX_PATH];
+    static char modname[MAX_PATH];
 
     if (!GetModuleFileName (NULL, modname, MAX_PATH))
       abort ();
@@ -754,8 +782,17 @@ init_environment ()
     *p = 0;
 
     SetCurrentDirectory (modname);
+
+    /* Ensure argv[0] has the full path to Emacs.  */
+    *p = '\\';
+    argv[0] = modname;
   }
 
+  /* Determine if there is a middle mouse button, to allow parse_button
+     to decide whether right mouse events should be mouse-2 or
+     mouse-3. */
+  XSETINT (Vw32_num_mouse_buttons, GetSystemMetrics (SM_CMOUSEBUTTONS));
+
   init_user_info ();
 }
 
@@ -770,6 +807,7 @@ char *
 get_emacs_configuration (void)
 {
   char *arch, *oem, *os;
+  int build_num;
 
   /* Determine the processor type.  */
   switch (get_processor_type ()) 
@@ -811,10 +849,37 @@ get_emacs_configuration (void)
   /* Let oem be "*" until we figure out how to decode the OEM field.  */
   oem = "*";
 
-  os = (GetVersion () & OS_WIN95) ? "windows95" : "nt";
+  switch (osinfo_cache.dwPlatformId) {
+  case VER_PLATFORM_WIN32_NT:
+    os = "nt";
+    build_num = osinfo_cache.dwBuildNumber;
+    break;
+  case VER_PLATFORM_WIN32_WINDOWS:
+    if (osinfo_cache.dwMinorVersion == 0) {
+      os = "windows95";
+    } else {
+      os = "windows98";
+    }
+    build_num = LOWORD (osinfo_cache.dwBuildNumber);
+    break;
+  case VER_PLATFORM_WIN32s:
+    /* Not supported, should not happen. */
+    os = "windows32s";
+    build_num = LOWORD (osinfo_cache.dwBuildNumber);
+    break;
+  default:
+    os = "unknown";
+    build_num = 0;
+    break;
+  }
+
+  if (osinfo_cache.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+    sprintf (configuration_buffer, "%s-%s-%s%d.%d.%d", arch, oem, os,
+            get_w32_major_version (), get_w32_minor_version (), build_num);
+  } else {
+    sprintf (configuration_buffer, "%s-%s-%s.%d", arch, oem, os, build_num);
+  }
 
-  sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
-          get_w32_major_version (), get_w32_minor_version ());
   return configuration_buffer;
 }
 
@@ -1194,6 +1259,13 @@ static int    dir_is_fat;
 static char   dir_pathname[MAXPATHLEN+1];
 static WIN32_FIND_DATA dir_find_data;
 
+/* Support shares on a network resource as subdirectories of a read-only
+   root directory. */
+static HANDLE wnet_enum_handle = INVALID_HANDLE_VALUE;
+HANDLE open_unc_volume (char *);
+char  *read_unc_volume (HANDLE, char *, int);
+void   close_unc_volume (HANDLE);
+
 DIR *
 opendir (char *filename)
 {
@@ -1202,10 +1274,20 @@ opendir (char *filename)
   /* Opening is done by FindFirstFile.  However, a read is inherent to
      this operation, so we defer the open until read time.  */
 
-  if (!(dirp = (DIR *) malloc (sizeof (DIR))))
-    return NULL;
   if (dir_find_handle != INVALID_HANDLE_VALUE)
     return NULL;
+  if (wnet_enum_handle != INVALID_HANDLE_VALUE)
+    return NULL;
+
+  if (is_unc_volume (filename))
+    {
+      wnet_enum_handle = open_unc_volume (filename);
+      if (wnet_enum_handle == INVALID_HANDLE_VALUE)
+       return NULL;
+    }
+
+  if (!(dirp = (DIR *) malloc (sizeof (DIR))))
+    return NULL;
 
   dirp->dd_fd = 0;
   dirp->dd_loc = 0;
@@ -1227,14 +1309,26 @@ closedir (DIR *dirp)
       FindClose (dir_find_handle);
       dir_find_handle = INVALID_HANDLE_VALUE;
     }
+  else if (wnet_enum_handle != INVALID_HANDLE_VALUE)
+    {
+      close_unc_volume (wnet_enum_handle);
+      wnet_enum_handle = INVALID_HANDLE_VALUE;
+    }
   xfree ((char *) dirp);
 }
 
 struct direct *
 readdir (DIR *dirp)
 {
+  if (wnet_enum_handle != INVALID_HANDLE_VALUE)
+    {
+      if (!read_unc_volume (wnet_enum_handle, 
+                             dir_find_data.cFileName, 
+                             MAX_PATH))
+       return NULL;
+    }
   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
-  if (dir_find_handle == INVALID_HANDLE_VALUE)
+  else if (dir_find_handle == INVALID_HANDLE_VALUE)
     {
       char filename[MAXNAMLEN + 3];
       int ln;
@@ -1280,6 +1374,80 @@ readdir (DIR *dirp)
   return &dir_static;
 }
 
+HANDLE
+open_unc_volume (char *path)
+{
+  NETRESOURCE nr; 
+  HANDLE henum;
+  int result;
+
+  nr.dwScope = RESOURCE_GLOBALNET; 
+  nr.dwType = RESOURCETYPE_DISK; 
+  nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER; 
+  nr.dwUsage = RESOURCEUSAGE_CONTAINER; 
+  nr.lpLocalName = NULL; 
+  nr.lpRemoteName = map_w32_filename (path, NULL);
+  nr.lpComment = NULL; 
+  nr.lpProvider = NULL;   
+
+  result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,  
+                       RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
+
+  if (result == NO_ERROR)
+    return henum;
+  else
+    return INVALID_HANDLE_VALUE;
+}
+
+char *
+read_unc_volume (HANDLE henum, char *readbuf, int size)
+{
+  int count;
+  int result;
+  int bufsize = 512;
+  char *buffer;
+  char *ptr;
+
+  count = 1;
+  buffer = alloca (bufsize);
+  result = WNetEnumResource (wnet_enum_handle, &count, buffer, &bufsize);
+  if (result != NO_ERROR)
+    return NULL;
+
+  /* WNetEnumResource returns \\resource\share...skip forward to "share". */
+  ptr = ((LPNETRESOURCE) buffer)->lpRemoteName;
+  ptr += 2;
+  while (*ptr && !IS_DIRECTORY_SEP (*ptr)) ptr++;
+  ptr++;
+
+  strncpy (readbuf, ptr, size);
+  return readbuf;
+}
+
+void
+close_unc_volume (HANDLE henum)
+{
+  if (henum != INVALID_HANDLE_VALUE)
+    WNetCloseEnum (henum);
+}
+
+DWORD
+unc_volume_file_attributes (char *path)
+{
+  HANDLE henum;
+  DWORD attrs;
+
+  henum = open_unc_volume (path);
+  if (henum == INVALID_HANDLE_VALUE)
+    return -1;
+
+  attrs = FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY;
+
+  close_unc_volume (henum);
+
+  return attrs;
+}
+
 
 /* Shadow some MSVC runtime functions to map requests for long filenames
    to reasonable short names if necessary.  This was originally added to
@@ -1293,7 +1461,15 @@ sys_access (const char * path, int mode)
 
   /* MSVC implementation doesn't recognize D_OK.  */
   path = map_w32_filename (path, NULL);
-  if ((attributes = GetFileAttributes (path)) == -1)
+  if (is_unc_volume (path))
+    {
+      attributes = unc_volume_file_attributes (path);
+      if (attributes == -1) {
+       errno = EACCES;
+       return -1;
+      }
+    }
+  else if ((attributes = GetFileAttributes (path)) == -1)
     {
       /* Should try mapping GetLastError to errno; for now just indicate
         that path doesn't exist.  */
@@ -1558,12 +1734,13 @@ sys_rename (const char * oldname, const char * newname)
        {
          /* Force temp name to require a manufactured 8.3 alias - this
             seems to make the second rename work properly.  */
-         sprintf (p, ".%s.%u", o, i);
+         sprintf (p, "_.%s.%u", o, i);
          i++;
+         result = rename (oldname, temp);
        }
       /* This loop must surely terminate!  */
-      while (rename (oldname, temp) < 0 && errno == EEXIST);
-      if (errno != EEXIST)
+      while (result < 0 && (errno == EEXIST || errno == EACCES));
+      if (result < 0)
        return -1;
     }
 
@@ -1582,7 +1759,7 @@ sys_rename (const char * oldname, const char * newname)
   result = rename (temp, newname);
 
   if (result < 0
-      && errno == EEXIST
+      && (errno == EEXIST || errno == EACCES)
       && _chmod (newname, 0666) == 0
       && _unlink (newname) == 0)
     result = rename (temp, newname);
@@ -1736,7 +1913,7 @@ stat (const char * path, struct stat * buf)
     }
 
   name = (char *) map_w32_filename (path, &path);
-  /* must be valid filename, no wild cards or other illegal characters */
+  /* must be valid filename, no wild cards or other invalid characters */
   if (strpbrk (name, "*?|<>\""))
     {
       errno = ENOENT;
@@ -1758,7 +1935,21 @@ stat (const char * path, struct stat * buf)
             && (IS_DIRECTORY_SEP (*path) || *path == 0));
   name = strcpy (alloca (len + 2), name);
 
-  if (rootdir)
+  if (is_unc_volume (name))
+    {
+      DWORD attrs = unc_volume_file_attributes (name);
+
+      if (attrs == -1)
+       return -1;
+
+      memset (&wfd, 0, sizeof (wfd));
+      wfd.dwFileAttributes = attrs;
+      wfd.ftCreationTime = utc_base_ft;
+      wfd.ftLastAccessTime = utc_base_ft;
+      wfd.ftLastWriteTime = utc_base_ft;
+      strcpy (wfd.cFileName, name);
+    }
+  else if (rootdir)
     {
       if (!IS_DIRECTORY_SEP (name[len-1]))
        strcat (name, "\\");
@@ -1782,9 +1973,11 @@ stat (const char * path, struct stat * buf)
       /* (This is hacky, but helps when doing file completions on
         network drives.)  Optimize by using information available from
         active readdir if possible.  */
+      len = strlen (dir_pathname);
+      if (IS_DIRECTORY_SEP (dir_pathname[len-1]))
+       len--;
       if (dir_find_handle != INVALID_HANDLE_VALUE
-         && (len = strlen (dir_pathname)),
-         strnicmp (name, dir_pathname, len) == 0
+         && strnicmp (name, dir_pathname, len) == 0
          && IS_DIRECTORY_SEP (name[len])
          && stricmp (name + len + 1, dir_static.d_name) == 0)
        {
@@ -1809,31 +2002,18 @@ stat (const char * path, struct stat * buf)
       buf->st_nlink = 2;       /* doesn't really matter */
       fake_inode = 0;          /* this doesn't either I think */
     }
-  else if (!NILP (Vw32_get_true_file_attributes))
+  else if (!NILP (Vw32_get_true_file_attributes)
+          /* No access rights required to get info.  */
+          && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL))
+             != INVALID_HANDLE_VALUE)
     {
       /* This is more accurate in terms of gettting the correct number
         of links, but is quite slow (it is noticable when Emacs is
         making a list of file name completions). */
       BY_HANDLE_FILE_INFORMATION info;
 
-      /* No access rights required to get info.  */
-      fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
-
       if (GetFileInformationByHandle (fh, &info))
        {
-         switch (GetFileType (fh))
-           {
-           case FILE_TYPE_DISK:
-             buf->st_mode = _S_IFREG;
-             break;
-           case FILE_TYPE_PIPE:
-             buf->st_mode = _S_IFIFO;
-             break;
-           case FILE_TYPE_CHAR:
-           case FILE_TYPE_UNKNOWN:
-           default:
-             buf->st_mode = _S_IFCHR;
-           }
          buf->st_nlink = info.nNumberOfLinks;
          /* Might as well use file index to fake inode values, but this
             is not guaranteed to be unique unless we keep a handle open
@@ -1841,13 +2021,27 @@ stat (const char * path, struct stat * buf)
             not unique).  Reputedly, there are at most 48 bits of info
             (on NTFS, presumably less on FAT). */
          fake_inode = info.nFileIndexLow ^ info.nFileIndexHigh;
-         CloseHandle (fh);
        }
       else
        {
-         errno = EACCES;
-         return -1;
+         buf->st_nlink = 1;
+         fake_inode = 0;
        }
+
+      switch (GetFileType (fh))
+       {
+       case FILE_TYPE_DISK:
+         buf->st_mode = _S_IFREG;
+         break;
+       case FILE_TYPE_PIPE:
+         buf->st_mode = _S_IFIFO;
+         break;
+       case FILE_TYPE_CHAR:
+       case FILE_TYPE_UNKNOWN:
+       default:
+         buf->st_mode = _S_IFCHR;
+       }
+      CloseHandle (fh);
     }
   else
     {
@@ -2212,6 +2406,99 @@ static void check_errno ()
     pfn_WSASetLastError (0);
 }
 
+/* Extend strerror to handle the winsock-specific error codes.  */
+struct {
+  int errnum;
+  char * msg;
+} _wsa_errlist[] = {
+  WSAEINTR                , "Interrupted function call",
+  WSAEBADF                , "Bad file descriptor",
+  WSAEACCES               , "Permission denied",
+  WSAEFAULT               , "Bad address",
+  WSAEINVAL               , "Invalid argument",
+  WSAEMFILE               , "Too many open files",
+                       
+  WSAEWOULDBLOCK          , "Resource temporarily unavailable",
+  WSAEINPROGRESS          , "Operation now in progress",
+  WSAEALREADY             , "Operation already in progress",
+  WSAENOTSOCK             , "Socket operation on non-socket",
+  WSAEDESTADDRREQ         , "Destination address required",
+  WSAEMSGSIZE             , "Message too long",
+  WSAEPROTOTYPE           , "Protocol wrong type for socket",
+  WSAENOPROTOOPT          , "Bad protocol option",
+  WSAEPROTONOSUPPORT      , "Protocol not supported",
+  WSAESOCKTNOSUPPORT      , "Socket type not supported",
+  WSAEOPNOTSUPP           , "Operation not supported",
+  WSAEPFNOSUPPORT         , "Protocol family not supported",
+  WSAEAFNOSUPPORT         , "Address family not supported by protocol family",
+  WSAEADDRINUSE           , "Address already in use",
+  WSAEADDRNOTAVAIL        , "Cannot assign requested address",
+  WSAENETDOWN             , "Network is down",
+  WSAENETUNREACH          , "Network is unreachable",
+  WSAENETRESET            , "Network dropped connection on reset",
+  WSAECONNABORTED         , "Software caused connection abort",
+  WSAECONNRESET           , "Connection reset by peer",
+  WSAENOBUFS              , "No buffer space available",
+  WSAEISCONN              , "Socket is already connected",
+  WSAENOTCONN             , "Socket is not connected",
+  WSAESHUTDOWN            , "Cannot send after socket shutdown",
+  WSAETOOMANYREFS         , "Too many references",         /* not sure */
+  WSAETIMEDOUT            , "Connection timed out",
+  WSAECONNREFUSED         , "Connection refused",
+  WSAELOOP                , "Network loop",                /* not sure */
+  WSAENAMETOOLONG         , "Name is too long",
+  WSAEHOSTDOWN            , "Host is down",
+  WSAEHOSTUNREACH         , "No route to host",
+  WSAENOTEMPTY            , "Buffer not empty",                    /* not sure */
+  WSAEPROCLIM             , "Too many processes",
+  WSAEUSERS               , "Too many users",              /* not sure */
+  WSAEDQUOT               , "Double quote in host name",    /* really not sure */
+  WSAESTALE               , "Data is stale",               /* not sure */
+  WSAEREMOTE              , "Remote error",                /* not sure */
+                       
+  WSASYSNOTREADY          , "Network subsystem is unavailable",
+  WSAVERNOTSUPPORTED      , "WINSOCK.DLL version out of range",
+  WSANOTINITIALISED       , "Winsock not initialized successfully",
+  WSAEDISCON              , "Graceful shutdown in progress",
+#ifdef WSAENOMORE
+  WSAENOMORE              , "No more operations allowed",   /* not sure */
+  WSAECANCELLED           , "Operation cancelled",         /* not sure */
+  WSAEINVALIDPROCTABLE    , "Invalid procedure table from service provider",
+  WSAEINVALIDPROVIDER     , "Invalid service provider version number",
+  WSAEPROVIDERFAILEDINIT  , "Unable to initialize a service provider",
+  WSASYSCALLFAILURE       , "System call failured",
+  WSASERVICE_NOT_FOUND    , "Service not found",           /* not sure */
+  WSATYPE_NOT_FOUND       , "Class type not found",
+  WSA_E_NO_MORE           , "No more resources available",  /* really not sure */
+  WSA_E_CANCELLED         , "Operation already cancelled",  /* really not sure */
+  WSAEREFUSED             , "Operation refused",           /* not sure */
+#endif
+                       
+  WSAHOST_NOT_FOUND       , "Host not found",
+  WSATRY_AGAIN            , "Authoritative host not found during name lookup",
+  WSANO_RECOVERY          , "Non-recoverable error during name lookup",
+  WSANO_DATA              , "Valid name, no data record of requested type",
+
+  -1, NULL
+};
+
+char *
+sys_strerror(int error_no)
+{
+  int i;
+  static char unknown_msg[40];
+
+  if (error_no >= 0 && error_no < _sys_nerr)
+    return _sys_errlist[error_no];
+
+  for (i = 0; _wsa_errlist[i].errnum >= 0; i++)
+    if (_wsa_errlist[i].errnum == error_no)
+      return _wsa_errlist[i].msg;
+
+  sprintf(unknown_msg, "Unidentified error: %d", error_no);
+  return unknown_msg;
+}
+
 /* [andrewi 3-May-96] I've had conflicting results using both methods,
    but I believe the method of keeping the socket handle separate (and
    insuring it is not inheritable) is the correct one. */
@@ -2885,40 +3172,49 @@ check_windows_init_file ()
      it cannot find the Windows installation file.  If this file does
      not exist in the expected place, tell the user.  */
 
-  if (!noninteractive && !inhibit_window_system) {
-    extern Lisp_Object Vwindow_system, Vload_path;
-    Lisp_Object init_file;
-    int fd;
-
-    init_file = build_string ("term/w32-win");
-    fd = openp (Vload_path, init_file, ".el:.elc", NULL, 0);
-    if (fd < 0) {
-      Lisp_Object load_path_print = Fprin1_to_string (Vload_path, Qnil);
-      char *init_file_name = XSTRING (init_file)->data;
-      char *load_path = XSTRING (load_path_print)->data;
-      char *buffer = alloca (1024);
-
-      sprintf (buffer, 
-              "The Emacs Windows initialization file \"%s.el\" "
-              "could not be found in your Emacs installation.  "
-              "Emacs checked the following directories for this file:\n"
-              "\n%s\n\n"
-              "When Emacs cannot find this file, it usually means that it "
-              "was not installed properly, or its distribution file was "
-              "not unpacked properly.\nSee the README.W32 file in the "
-              "top-level Emacs directory for more information.",
-              init_file_name, load_path);
-      MessageBox (NULL,
-                 buffer,
-                 "Emacs Abort Dialog",
-                 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
-      close (fd);
+  if (!noninteractive && !inhibit_window_system) 
+    {
+      extern Lisp_Object Vwindow_system, Vload_path, Qfile_exists_p;
+      Lisp_Object objs[2];
+      Lisp_Object full_load_path;
+      Lisp_Object init_file;
+      int fd;
 
+      objs[0] = Vload_path;
+      objs[1] = decode_env_path (0, (getenv ("EMACSLOADPATH")));
+      full_load_path = Fappend (2, objs);
+      init_file = build_string ("term/w32-win");
+      fd = openp (full_load_path, init_file, ".el:.elc", NULL, 0);
+      if (fd < 0) 
+       {
+         Lisp_Object load_path_print = Fprin1_to_string (full_load_path, Qnil);
+         char *init_file_name = XSTRING (init_file)->data;
+         char *load_path = XSTRING (load_path_print)->data;
+         char *buffer = alloca (1024);
+
+         sprintf (buffer, 
+                  "The Emacs Windows initialization file \"%s.el\" "
+                  "could not be found in your Emacs installation.  "
+                  "Emacs checked the following directories for this file:\n"
+                  "\n%s\n\n"
+                  "When Emacs cannot find this file, it usually means that it "
+                  "was not installed properly, or its distribution file was "
+                  "not unpacked properly.\nSee the README.W32 file in the "
+                  "top-level Emacs directory for more information.",
+                  init_file_name, load_path);
+         MessageBox (NULL,
+                     buffer,
+                     "Emacs Abort Dialog",
+                     MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
       /* Use the low-level Emacs abort. */
 #undef abort
-      abort ();
+         abort ();
+       }
+      else
+       {
+         close (fd);
+       }
     }
-  }
 }
 
 void
@@ -2928,12 +3224,6 @@ term_ntproc ()
   /* shutdown the socket interface if necessary */
   term_winsock ();
 #endif
-
-  /* Check whether we are shutting down because we cannot find the
-     Windows initialization file.  Do this during shutdown so that
-     Emacs is initialized as possible, and so that it is out of the 
-     critical startup path.  */
-  check_windows_init_file ();
 }
 
 void
@@ -3033,6 +3323,9 @@ init_ntproc ()
       (*drive)++;
     }
   }
+  
+  /* Check to see if Emacs has been installed correctly.  */
+  check_windows_init_file ();
 }
 
 /* end of nt.c */