diff -c pretest/lib-src/etags.c.orig pretest/lib-src/etags.c
*** pretest/lib-src/etags.c.orig	Tue Jul 23 17:32:10 1996
--- pretest/lib-src/etags.c	Mon Jul 21 10:54:31 1997
***************
*** 52,57 ****
--- 52,58 ----
  # include <string.h>
  # include <io.h>
  # define MAXPATHLEN _MAX_PATH
+ # include "ntlib.h"
  #endif
  
  #ifdef HAVE_CONFIG_H
***************
*** 4332,4338 ****
  char *
  etags_getcwd ()
  {
! #ifdef MSDOS
    char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
  
    getwd (path);
--- 4333,4339 ----
  char *
  etags_getcwd ()
  {
! #ifdef DOS_NT
    char *p, path[MAXPATHLEN + 1]; /* Fixed size is safe on MSDOS.  */
  
    getwd (path);
***************
*** 4343,4349 ****
        *p = lowcase (*p);
  
    return strdup (path);
! #else /* not MSDOS */
  #if HAVE_GETCWD
    int bufsize = 200;
    char *path = xnew (bufsize, char);
--- 4344,4350 ----
        *p = lowcase (*p);
  
    return strdup (path);
! #else /* not DOS_NT */
  #if HAVE_GETCWD
    int bufsize = 200;
    char *path = xnew (bufsize, char);
diff -c pretest/lib-src/getopt.c.orig pretest/lib-src/getopt.c
*** pretest/lib-src/getopt.c.orig	Mon Jun 24 22:40:30 1996
--- pretest/lib-src/getopt.c	Mon Jul 14 14:11:38 1997
***************
*** 68,77 ****
  #endif
  #endif
  
! #if defined (WIN32) && !defined (__CYGWIN32__)
! /* It's not Unix, really.  See?  Capital letters.  */
! #include <windows.h>
! #define getpid() GetCurrentProcessId()
  #endif
  
  #ifndef _
--- 68,75 ----
  #endif
  #endif
  
! #if defined (WINDOWSNT) && !defined (__CYGWIN32__)
! #include "ntlib.h"
  #endif
  
  #ifndef _
diff -c pretest/lib-src/makefile.nt.orig pretest/lib-src/makefile.nt
*** pretest/lib-src/makefile.nt.orig	Sat Jul 20 19:08:55 1996
--- pretest/lib-src/makefile.nt	Mon Jul 14 14:11:38 1997
***************
*** 231,236 ****
--- 231,245 ----
  	$(EMACS_ROOT)\src\m\intel386.h \
  	$(EMACS_ROOT)\lib-src\..\src\config.h
  
+ $(BLD)\ctags.obj : \
+ 	$(SRC)\ctags.c \
+ 	$(EMACS_ROOT)\nt\inc\sys\param.h \
+ 	$(EMACS_ROOT)\src\s\windowsnt.h \
+ 	$(EMACS_ROOT)\src\m\intel386.h \
+ 	$(EMACS_ROOT)\lib-src\..\src\config.h \
+ 	$(SRC)\ntlib.h \
+ 	$(SRC)\getopt.h
+ 
  $(BLD)\cvtmail.obj : \
  	$(SRC)\cvtmail.c
  
***************
*** 260,265 ****
--- 269,275 ----
  	$(EMACS_ROOT)\src\s\windowsnt.h \
  	$(EMACS_ROOT)\src\m\intel386.h \
  	$(EMACS_ROOT)\lib-src\..\src\config.h \
+ 	$(SRC)\ntlib.h \
  	$(SRC)\getopt.h
  
  $(BLD)\fakemail.obj : \
***************
*** 282,287 ****
--- 292,298 ----
  	$(EMACS_ROOT)\src\s\windowsnt.h \
  	$(EMACS_ROOT)\src\m\intel386.h \
  	$(EMACS_ROOT)\src\config.h \
+ 	$(SRC)\ntlib.h \
  	$(SRC)\getopt.h
  
  $(BLD)\getopt1.obj : \
***************
*** 312,318 ****
  	$(EMACS_ROOT)\nt\inc\sys\file.h \
  	$(EMACS_ROOT)\src\vmsproc.h \
  	$(EMACS_ROOT)\lib-src\..\src\syswait.h \
! 	$(EMACS_ROOT)\nt\inc\pwd.h
  		$(CC) $(CFLAGS) -DUSG -Fo$@ movemail.c
  
  $(BLD)\ntlib.obj : \
--- 323,330 ----
  	$(EMACS_ROOT)\nt\inc\sys\file.h \
  	$(EMACS_ROOT)\src\vmsproc.h \
  	$(EMACS_ROOT)\lib-src\..\src\syswait.h \
! 	$(EMACS_ROOT)\nt\inc\pwd.h \
! 	$(SRC)\ntlib.h
  		$(CC) $(CFLAGS) -DUSG -Fo$@ movemail.c
  
  $(BLD)\ntlib.obj : \
diff -c pretest/lib-src/movemail.c.orig pretest/lib-src/movemail.c
*** pretest/lib-src/movemail.c.orig	Mon Apr 29 00:36:20 1996
--- pretest/lib-src/movemail.c	Mon Jul 14 14:11:40 1997
***************
*** 78,93 ****
  #endif
  
  #ifdef WINDOWSNT
! #undef access
! #undef unlink
  #define fork() 0
  #define sys_wait(var) (*(var) = 0)
  /* Unfortunately, Samba doesn't seem to properly lock Unix files even
     though the locking call succeeds (and indeed blocks local access from
     other NT programs).  If you have direct file access using an NFS
     client or something other than Samba, the locking call might work
!    properly - make sure it does before you enable this! */
! #define DISABLE_DIRECT_ACCESS
  #endif /* WINDOWSNT */
  
  #ifdef USG
--- 78,101 ----
  #endif
  
  #ifdef WINDOWSNT
! /* Changes some substitutions made by config.h for Emacs.  */
! #include "ntlib.h"
  #define fork() 0
  #define sys_wait(var) (*(var) = 0)
  /* Unfortunately, Samba doesn't seem to properly lock Unix files even
     though the locking call succeeds (and indeed blocks local access from
     other NT programs).  If you have direct file access using an NFS
     client or something other than Samba, the locking call might work
!    properly - make sure it does before you enable this!
! 
!    [18-Feb-97 andrewi] I now believe my comment above to be incorrect,
!    since it was based on a misunderstanding of how locking calls are
!    implemented and used on Unix.  */
! //#define DISABLE_DIRECT_ACCESS
! 
! /* Ensure all file i/o is in binary mode. */
! #include <fcntl.h>
! int _fmode = _O_BINARY;
  #endif /* WINDOWSNT */
  
  #ifdef USG
***************
*** 122,131 ****
--- 130,141 ----
  #endif
  
  /* Cancel substitutions made by config.h for Emacs.  */
+ #ifndef WINDOWSNT
  #undef open
  #undef read
  #undef write
  #undef close
+ #endif
  
  #ifndef errno
  extern int errno;
***************
*** 484,504 ****
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <netdb.h>
! #else
  #undef _WINSOCKAPI_
  #include <winsock.h>
! #endif
  #include <stdio.h>
  #include <pwd.h>
- 
- #ifdef USG
- #include <fcntl.h>
- /* Cancel substitutions made by config.h for Emacs.  */
- #undef open
- #undef read
- #undef write
- #undef close
- #endif /* USG */
  
  #define NOTOK (-1)
  #define OK 0
--- 494,505 ----
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <netdb.h>
! #else /* WINDOWSNT */
  #undef _WINSOCKAPI_
  #include <winsock.h>
! #endif /* WINDOWSNT */
  #include <stdio.h>
  #include <pwd.h>
  
  #define NOTOK (-1)
  #define OK 0
diff -c pretest/lib-src/ntlib.h.orig pretest/lib-src/ntlib.h
*** pretest/lib-src/ntlib.h.orig	Sat Jul 20 19:06:53 1996
--- pretest/lib-src/ntlib.h	Mon Jul 14 14:11:40 1997
***************
*** 20,28 ****
--- 20,36 ----
  
  */
  
+ #define WIN32
+ 
  #include <pwd.h>
  #include <malloc.h>
  
+ /* Include these headers now so we don't have to worry about include
+    order dependencies in common source files.  */
+ #include <direct.h>
+ #include <io.h>
+ #include <stdio.h>
+ 
  void sleep(int seconds);
  char *getwd (char *dir);
  int getppid(void);
***************
*** 38,46 ****
  #define bzero(b, l) memset(b, 0, l)
  #define bcopy(s, d, l) memcpy(d, s, l)
  #define bcmp(a, b, l) memcmp(a, b, l)
- 
- #define index   strchr
- #define rindex  strrchr
  #endif
  
  /* end of ntlib.h */
--- 46,111 ----
  #define bzero(b, l) memset(b, 0, l)
  #define bcopy(s, d, l) memcpy(d, s, l)
  #define bcmp(a, b, l) memcmp(a, b, l)
  #endif
+ 
+ /* redirect or undo interceptions by config.h */
+ #undef access
+ #define access  _access
+ #undef chdir
+ #define chdir   _chdir
+ #undef chmod
+ #define chmod   _chmod
+ #undef close
+ #define close   _close
+ #undef creat
+ #define creat   _creat
+ #undef ctime
+ #undef dup
+ #define dup     _dup
+ #undef dup2
+ #define dup2    _dup2
+ #undef fopen
+ #undef mkdir
+ #define mkdir   _mkdir
+ #undef mktemp
+ #define mktemp  _mktemp
+ #undef open
+ #define open    _open
+ #undef pipe
+ #define pipe    _pipe
+ #undef read
+ #define read    _read
+ #undef rename
+ #undef rmdir
+ #define rmdir   _rmdir
+ #undef unlink
+ #define unlink  _unlink
+ #undef write
+ #define write   _write
+ 
+ /* map to MSVC names */
+ #define execlp    _execlp
+ #define execvp    _execvp
+ #define fcloseall _fcloseall
+ #define fdopen	  _fdopen
+ #define fgetchar  _fgetchar
+ #define fileno	  _fileno
+ #define flushall  _flushall
+ #define fputchar  _fputchar
+ #define getcwd	  _getcwd
+ #define getw	  _getw
+ #define getpid    _getpid
+ #define isatty    _isatty
+ #define locking   _locking
+ #define logb      _logb
+ #define _longjmp  longjmp
+ #define lseek     _lseek
+ #define popen     _popen
+ #define pclose    _pclose
+ #define putw	  _putw
+ #define umask	  _umask
+ #define utime	  _utime
+ #define index     strchr
+ #define rindex    strrchr
  
  /* end of ntlib.h */
diff -c pretest/lisp/ChangeLog.orig pretest/lisp/ChangeLog
*** pretest/lisp/ChangeLog.orig	Wed Aug 21 08:52:22 1996
--- pretest/lisp/ChangeLog	Mon Jul 14 14:11:40 1997
***************
*** 1,3 ****
--- 1,12 ----
+ Tue May 06 15:20:43 1997  Michael Welsh Duggan  <md5i@schenley.com>
+ 
+ 	* winnt.el: Delete popupmenu-based global-unsets.
+ 
+ Tue Apr 15 13:43:39 1997  Andrew Innes  <andrewi@harlequin.co.uk>
+ 
+ 	* hilit19.el (hilit-rehighlight-message): respect mail-mode
+ 	header/body separation line.
+ 
  Wed Aug 21 03:51:42 1996  Richard Stallman  <rms@psilocin.gnu.ai.mit.edu>
  
  	* Version 19.34 released.
diff -c pretest/lisp/comint.el.orig pretest/lisp/comint.el
*** pretest/lisp/comint.el.orig	Thu Aug  1 23:30:38 1996
--- pretest/lisp/comint.el	Tue Jul 15 18:34:14 1997
***************
*** 1828,1836 ****
  directory tracking functions.")
  
  (defvar comint-file-name-chars
!   (if (memq system-type '(ms-dos windows-nt))
!       "~/A-Za-z0-9_^$!#%&{}@`'.()-"
!     "~/A-Za-z0-9+@:_.$#%,={}-")
    "String of characters valid in a file name.
  
  This is a good thing to set in mode hooks.")
--- 1828,1840 ----
  directory tracking functions.")
  
  (defvar comint-file-name-chars
!   (cond
!    ((eq system-type 'ms-dos)
!     "~/A-Za-z0-9_^$!#%&{}@`'.()-")
!    ((eq system-type 'windows-nt)
!     "~/\\A-Za-z0-9_^$!#%&{}@`'.,:()-")
!    (t   
!     "~/A-Za-z0-9+@:_.$#%,={}-"))
    "String of characters valid in a file name.
  
  This is a good thing to set in mode hooks.")
diff -c pretest/lisp/disp-table.el.orig pretest/lisp/disp-table.el
*** pretest/lisp/disp-table.el.orig	Sun Jan 14 07:34:30 1996
--- pretest/lisp/disp-table.el	Mon Jul 14 14:11:42 1997
***************
*** 191,197 ****
      (standard-display-8bit 160 255)
      ;; Make non-line-break space display as a plain space.
      ;; Most X fonts do the wrong thing for code 160.
!     (aset standard-display-table 160 [32])))
  
  (provide 'disp-table)
  
--- 191,202 ----
      (standard-display-8bit 160 255)
      ;; Make non-line-break space display as a plain space.
      ;; Most X fonts do the wrong thing for code 160.
!     (aset standard-display-table 160 [32])
!     ;; Most Windows programs send out apostrophe's as \222.  Most X fonts
!     ;; don't contain a character at that position.  Map it to the ASCII
!     ;; apostrophe.
!     (aset standard-display-table 146 [39])
!     ))
  
  (provide 'disp-table)
  
diff -c pretest/lisp/files.el.orig pretest/lisp/files.el
*** pretest/lisp/files.el.orig	Sun Jul 28 07:50:58 1996
--- pretest/lisp/files.el	Fri Jul 18 18:28:46 1997
***************
*** 397,402 ****
--- 397,426 ----
  	   (let ((tem (copy-sequence file-name-handler-alist)))
  	     (delq (rassq 'ange-ftp-completion-hook-function tem) tem)))))
      (or prev-dirs (setq prev-dirs (list nil)))
+ 
+     ;; andrewi@harlequin.co.uk - none of the following code (except for
+     ;; invoking the file-name handler) currently applies on Windows
+     ;; (ie. there are no native symlinks), but there is an issue with
+     ;; case differences being ignored by the OS, and short "8.3 DOS"
+     ;; name aliases existing for all files.  (The short names are not
+     ;; reported by directory-files, but can be used to refer to files.)
+     ;; It seems appropriate for file-truename to resolve these issues in
+     ;; the most natural way, which on Windows is to call the function
+     ;; `win32-long-file-name' - this returns the exact name of a file as
+     ;; it is stored on disk (expanding short name aliases with the full
+     ;; name in the process).
+     (if (eq system-type 'windows-nt)
+       (let ((handler (find-file-name-handler filename 'file-truename))
+ 	    newname)
+ 	;; For file name that has a special handler, call handler.
+ 	;; This is so that ange-ftp can save time by doing a no-op.
+ 	(if handler
+ 	    (setq filename (funcall handler 'file-truename filename))
+ 	  ;; if filename doesn't exist, newname will be nil
+ 	  (setq newname (win32-long-file-name filename))
+ 	  (setq filename (or newname filename)))
+ 	(setq done t)))
+ 
      ;; If this file directly leads to a link, process that iteratively
      ;; so that we don't use lots of stack.
      (while (not done)
***************
*** 990,997 ****
      ("\\.awk\\'" . awk-mode)
      ("\\.prolog\\'" . prolog-mode)
      ("\\.tar\\'" . tar-mode)
!     ("\\.\\(arc\\|zip\\|lzh\\|zoo\\)\\'" . archive-mode)
!     ("\\.\\(ARC\\|ZIP\\|LZH\\|ZOO\\)\\'" . archive-mode)
      ;; Mailer puts message to be edited in
      ;; /tmp/Re.... or Message
      ("\\`/tmp/Re" . text-mode)
--- 1014,1021 ----
      ("\\.awk\\'" . awk-mode)
      ("\\.prolog\\'" . prolog-mode)
      ("\\.tar\\'" . tar-mode)
!     ("\\.\\(arc\\|zip\\|lzh\\|zoo\\|jar\\)\\'" . archive-mode)
!     ("\\.\\(ARC\\|ZIP\\|LZH\\|ZOO\\|JAR\\)\\'" . archive-mode)
      ;; Mailer puts message to be edited in
      ;; /tmp/Re.... or Message
      ("\\`/tmp/Re" . text-mode)
***************
*** 2272,2278 ****
  	     (not (file-exists-p file-name)))
  	   (error "Auto-save file %s not current" file-name))
  	  ((save-window-excursion
! 	     (if (not (eq system-type 'vax-vms))
  		 (with-output-to-temp-buffer "*Directory*"
  		   (buffer-disable-undo standard-output)
  		   (call-process "ls" nil standard-output nil
--- 2296,2302 ----
  	     (not (file-exists-p file-name)))
  	   (error "Auto-save file %s not current" file-name))
  	  ((save-window-excursion
! 	     (if (not (memq system-type '(vax-vms windows-nt)))
  		 (with-output-to-temp-buffer "*Directory*"
  		   (buffer-disable-undo standard-output)
  		   (call-process "ls" nil standard-output nil
diff -c pretest/lisp/gud.el.orig pretest/lisp/gud.el
*** pretest/lisp/gud.el.orig	Thu Aug  1 23:36:10 1996
--- pretest/lisp/gud.el	Mon Jul 14 14:11:42 1997
***************
*** 171,180 ****
  (defun gud-gdb-massage-args (file args)
    (cons "-fullname" args))
  
- (defvar gud-gdb-marker-regexp
-   (concat "\032\032\\([^" path-separator "\n]*\\)" path-separator
- 	  "\\([0-9]*\\)" path-separator ".*\n"))
- 
  ;; There's no guarantee that Emacs will hand the filter the entire
  ;; marker at once; it could be broken up across several strings.  We
  ;; might even receive a big chunk with several markers in it.  If we
--- 171,176 ----
***************
*** 188,195 ****
    (setq gud-marker-acc (concat gud-marker-acc string))
    (let ((output ""))
  
!     ;; Process all the complete markers in this chunk.
!     (while (string-match gud-gdb-marker-regexp gud-marker-acc)
        (setq
  
         ;; Extract the frame position from the marker.
--- 184,193 ----
    (setq gud-marker-acc (concat gud-marker-acc string))
    (let ((output ""))
  
!     ;; Process all the complete markers in this chunk.  Allow first field
!     ;; (filename) to include drive letter and colon (for Windows).
!     (while (string-match "\032\032\\(.:?[^:\n]*\\):\\([0-9]*\\):.*\n"
! 			 gud-marker-acc)
        (setq
  
         ;; Extract the frame position from the marker.
***************
*** 930,949 ****
  (defun gud-perldb-massage-args (file args)
    (cons "-d" (cons (car args) (cons "-emacs" (cdr args)))))
  
- ;; There's no guarantee that Emacs will hand the filter the entire
- ;; marker at once; it could be broken up across several strings.  We
- ;; might even receive a big chunk with several markers in it.  If we
- ;; receive a chunk of text which looks like it might contain the
- ;; beginning of a marker, we save it here between calls to the
- ;; filter.
- (defvar gud-perldb-marker-acc "")
- 
  (defun gud-perldb-marker-filter (string)
    (setq gud-marker-acc (concat gud-marker-acc string))
    (let ((output ""))
  
!     ;; Process all the complete markers in this chunk.
!     (while (string-match "\032\032\\([^:\n]*\\):\\([0-9]*\\):.*\n"
  			 gud-marker-acc)
        (setq
  
--- 928,940 ----
  (defun gud-perldb-massage-args (file args)
    (cons "-d" (cons (car args) (cons "-emacs" (cdr args)))))
  
  (defun gud-perldb-marker-filter (string)
    (setq gud-marker-acc (concat gud-marker-acc string))
    (let ((output ""))
  
!     ;; Process all the complete markers in this chunk.  Allow first field
!     ;; (filename) to include drive letter and colon (for Windows).
!     (while (string-match "\032\032\\(.:?[^:\n]*\\):\\([0-9]*\\):.*\n"
  			 gud-marker-acc)
        (setq
  
diff -c pretest/lisp/hilit19.el.orig pretest/lisp/hilit19.el
*** pretest/lisp/hilit19.el.orig	Fri Jun 21 06:16:05 1996
--- pretest/lisp/hilit19.el	Mon Jul 14 14:11:44 1997
***************
*** 786,792 ****
    "Highlight a buffer containing a news article or mail message."
    (save-excursion
      (goto-char (point-min))
!     (re-search-forward "^$" nil 'noerr)
      (hilit-unhighlight-region (point-min) (point-max) quietly)
      (hilit-highlight-region (point-min) (point) 'msg-header quietly)
      (hilit-highlight-region (point) (point-max) 'msg-body quietly)))
--- 786,794 ----
    "Highlight a buffer containing a news article or mail message."
    (save-excursion
      (goto-char (point-min))
!     ;; find separation between headers and body (either a blank line or
!     ;; the message separator line in mail-mode)
!     (re-search-forward "^\\(\\|--text follows this line--\\)$" nil 'noerr)
      (hilit-unhighlight-region (point-min) (point-max) quietly)
      (hilit-highlight-region (point-min) (point) 'msg-header quietly)
      (hilit-highlight-region (point) (point-max) 'msg-body quietly)))
diff -c pretest/lisp/info.el.orig pretest/lisp/info.el
*** pretest/lisp/info.el.orig	Fri Aug  9 03:08:30 1996
--- pretest/lisp/info.el	Mon Jul 14 14:11:44 1997
***************
*** 1615,1621 ****
    (make-local-variable 'Info-tag-table-marker)
    (make-local-variable 'Info-history)
    (make-local-variable 'Info-index-alternatives)
!   (if (memq (framep (selected-frame)) '(x pc))
        (progn
  	(make-face 'info-node)
  	(make-face 'info-menu-5)
--- 1615,1621 ----
    (make-local-variable 'Info-tag-table-marker)
    (make-local-variable 'Info-history)
    (make-local-variable 'Info-index-alternatives)
!   (if (memq (framep (selected-frame)) '(x pc win32))
        (progn
  	(make-face 'info-node)
  	(make-face 'info-menu-5)
diff -c pretest/lisp/loadup.el.orig pretest/lisp/loadup.el
*** pretest/lisp/loadup.el.orig	Mon Jun 10 22:18:03 1996
--- pretest/lisp/loadup.el	Thu Jul 17 21:49:43 1997
***************
*** 162,168 ****
  				  emacs-version
  				  (if versions
  				      (1+ (apply 'max versions))
! 				    1)))))
  
  ;; Note: all compiled Lisp files loaded above this point
  ;; must be among the ones parsed by make-docfile
--- 162,169 ----
  				  emacs-version
  				  (if versions
  				      (1+ (apply 'max versions))
! 				    ;; crude hack to differentiate Windows sub-releases
! 				    4)))))
  
  ;; Note: all compiled Lisp files loaded above this point
  ;; must be among the ones parsed by make-docfile
diff -c pretest/lisp/scroll-bar.el.orig pretest/lisp/scroll-bar.el
*** pretest/lisp/scroll-bar.el.orig	Tue May 21 15:38:52 1996
--- pretest/lisp/scroll-bar.el	Mon Jul 14 14:11:44 1997
***************
*** 142,148 ****
        (setq next-portion-start (max
  				(scroll-bar-drag-position next-portion-whole)
  				(1+ portion-start)))
!       (if (or (> current-start next-portion-start)
  	      (< current-start portion-start))
  	  (set-window-start window portion-start)
  	;; Always set window start, to ensure scroll bar position is updated.
--- 142,148 ----
        (setq next-portion-start (max
  				(scroll-bar-drag-position next-portion-whole)
  				(1+ portion-start)))
!       (if (or (>= current-start next-portion-start)
  	      (< current-start portion-start))
  	  (set-window-start window portion-start)
  	;; Always set window start, to ensure scroll bar position is updated.
diff -c pretest/lisp/winnt.el.orig pretest/lisp/winnt.el
*** pretest/lisp/winnt.el.orig	Tue Jul 23 17:16:40 1996
--- pretest/lisp/winnt.el	Thu Jul 17 17:44:02 1997
***************
*** 61,67 ****
  
  ;; The cmd.exe shell uses the "/c" switch instead of the "-c" switch
  ;; for executing its command line argument (from simple.el).
! (setq shell-command-switch "/c")
  
  ;; For appending suffixes to directories and files in shell completions.
  (add-hook 'shell-mode-hook 
--- 61,69 ----
  
  ;; The cmd.exe shell uses the "/c" switch instead of the "-c" switch
  ;; for executing its command line argument (from simple.el).
! ;; However, Emacs now includes cmdproxy which is used as the shell by
! ;; default; cmdproxy accepts "-c" and interprets as Unix shells do.
! ;(setq shell-command-switch "/c")
  
  ;; For appending suffixes to directories and files in shell completions.
  (add-hook 'shell-mode-hook 
***************
*** 84,94 ****
    '(
      ("[:/].*config.sys$" . nil)		; config.sys text
      ("\\.elc$" . t)			; emacs stuff
!     ("\\.\\(obj\\|exe\\|com\\|lib\\|sys\\|chk\\|out\\|bin\\|ico\\|pif\\)$" . t)
  					; MS-Dos stuff
      ("\\.\\(arc\\|zip\\|pak\\|lzh\\|zoo\\)$" . t)
  					; Packers
!     ("\\.\\(a\\|o\\|tar\\|z\\|gz\\|taz\\)$" . t)
  					; Unix stuff
      ("\\.tp[ulpw]$" . t)
  					; Borland Pascal stuff
--- 86,100 ----
    '(
      ("[:/].*config.sys$" . nil)		; config.sys text
      ("\\.elc$" . t)			; emacs stuff
!     ("\\.\\(obj\\|exe\\|com\\|lib\\|sym\\|sys\\|chk\\|out\\|bin\\|ico\\|pif\\|dos\\)$" . t)
  					; MS-Dos stuff
+     ("\\.\\(dll\\|drv\\|cpl\\|scr\\vbx\\|386\\|vxd\\|fon\\|fnt\\|fot\\|ttf\\|grp\\)$" . t)
+ 					; Windows stuff
+     ("\\.\\(hlp\\|bmp\\|wav\\|avi\\|mpg\\|jpg\\|tif\\mov\\au\\)" . t)
+ 					; known binary data files
      ("\\.\\(arc\\|zip\\|pak\\|lzh\\|zoo\\)$" . t)
  					; Packers
!     ("\\.\\(a\\|o\\|tar\\|z\\|gz\\|taz\\|jar\\)$" . t)
  					; Unix stuff
      ("\\.tp[ulpw]$" . t)
  					; Borland Pascal stuff
***************
*** 171,179 ****
  See also `auto-save-file-name-p'."
    (let ((name (original-make-auto-save-file-name))
  	(start 0))
!     ;; destructively replace occurences of * or ? with $
      (while (string-match "[?*]" name start)
!       (aset name (match-beginning 0) ?$)
        (setq start (1+ (match-end 0))))
      name))
  
--- 177,185 ----
  See also `auto-save-file-name-p'."
    (let ((name (original-make-auto-save-file-name))
  	(start 0))
!     ;; destructively replace occurences of * or ? with !
      (while (string-match "[?*]" name start)
!       (aset name (match-beginning 0) ?!)
        (setq start (1+ (match-end 0))))
      name))
  
***************
*** 186,195 ****
    (or type (setq type 'PRIMARY))
    (get 'x-selections type))
  
! (fmakunbound 'font-menu-add-default)
! (global-unset-key [C-down-mouse-1])
! (global-unset-key [C-down-mouse-2])
! (global-unset-key [C-down-mouse-3])
  
  ;;; Set to a system sound if you want a fancy bell.
  (set-message-beep nil)
--- 192,201 ----
    (or type (setq type 'PRIMARY))
    (get 'x-selections type))
  
! ;(fmakunbound 'font-menu-add-default)
! ;(global-unset-key [C-down-mouse-1])
! ;(global-unset-key [C-down-mouse-2])
! ;(global-unset-key [C-down-mouse-3])
  
  ;;; Set to a system sound if you want a fancy bell.
  (set-message-beep nil)
diff -c pretest/lisp/term/win32-win.el.orig pretest/lisp/term/win32-win.el
*** pretest/lisp/term/win32-win.el.orig	Tue May 21 15:34:35 1996
--- pretest/lisp/term/win32-win.el	Mon Jul 21 15:19:06 1997
***************
*** 94,99 ****
--- 94,100 ----
  	    (select-window window)
  	    (cond
  	     ((eq bar-part 'up)
+ 	      (goto-char (window-start window))
  	      (scroll-down 1))
  	     ((eq bar-part 'above-handle)
  	      (scroll-down))
***************
*** 102,107 ****
--- 103,109 ----
  	     ((eq bar-part 'below-handle)
  	      (scroll-up))
  	     ((eq bar-part 'down)
+ 	      (goto-char (window-start window))
  	      (scroll-up 1))
  	     )))
        (select-window old-window))))
diff -c pretest/nt/ChangeLog.orig pretest/nt/ChangeLog
*** pretest/nt/ChangeLog.orig	Wed Aug 21 08:52:39 1996
--- pretest/nt/ChangeLog	Mon Jul 14 14:11:46 1997
***************
*** 1,3 ****
--- 1,11 ----
+ Thu Jul 03 11:37:46 1997  Geoff Voelker  <voelker@cs.washington.edu>
+ 
+ 	* makefile.nt (real_install): Create site-lisp directory.
+ 	* emacs.bat.in: Extend EMACS_LOADPATH to include site-lisp.
+ 	* addpm.c (env_vars): Extend EMACS_LOADPATH to include site-lisp.
+ 
+ 	* makefile.def (SYS_LDFLAGS): Allow pdb's to be created.
+ 	
  Wed Aug 21 03:51:42 1996  Richard Stallman  <rms@psilocin.gnu.ai.mit.edu>
  
  	* Version 19.34 released.
diff -c pretest/nt/FTIME.BAT.null pretest/nt/FTIME.BAT
*** pretest/nt/FTIME.BAT.null	Tue Jul 22 15:14:34 1997
--- pretest/nt/FTIME.BAT	Mon Jul 14 14:11:46 1997
***************
*** 0 ****
--- 1,10 ----
+ @echo off
+ set emacs_dir=d:\andrewi\work\pretest
+ prep /om /ft %emacs_dir%\src\obj\i386\emacs
+ if errorlevel 1 goto done
+ profile %emacs_dir%\src\obj\i386\emacs %1 %2 %3 %4 %5 %6 %7 %8 %9
+ if errorlevel 1 goto done
+ prep /m  %emacs_dir%\src\obj\i386\emacs
+ if errorlevel 1 goto done
+ plist  %emacs_dir%\src\obj\i386\emacs > info/emacs.prof
+ :done
diff -c pretest/nt/FTIME2.BAT.null pretest/nt/FTIME2.BAT
*** pretest/nt/FTIME2.BAT.null	Tue Jul 22 15:14:34 1997
--- pretest/nt/FTIME2.BAT	Mon Jul 14 14:11:46 1997
***************
*** 0 ****
--- 1,11 ----
+ @echo off
+ set emacs_dir=d:\andrewi\work\pretest
+ rem prep /om /ft %emacs_dir%\src\obj\i386\emacs
+ prep /sf _command_loop_1 /om /ft %emacs_dir%\src\obj\i386\emacs
+ if errorlevel 1 goto done
+ profile %emacs_dir%\src\obj\i386\emacs %1 %2 %3 %4 %5 %6 %7 %8 %9
+ if errorlevel 1 goto done
+ prep /m  %emacs_dir%\src\obj\i386\emacs
+ if errorlevel 1 goto done
+ plist  %emacs_dir%\src\obj\i386\emacs > info/emacs.prof
+ :done
diff -c pretest/nt/addpm.c.orig pretest/nt/addpm.c
*** pretest/nt/addpm.c.orig	Mon Jun  3 16:40:08 1996
--- pretest/nt/addpm.c	Fri Jul 18 19:13:00 1997
***************
*** 54,61 ****
  env_vars[] = 
  {
    {"emacs_dir", NULL},
!   {"EMACSLOADPATH", "%emacs_dir%/lisp"},
!   {"SHELL", "%COMSPEC%"},
    {"EMACSDATA", "%emacs_dir%/etc"},
    {"EMACSPATH", "%emacs_dir%/bin"},
    {"EMACSLOCKDIR", "%emacs_dir%/lock"},
--- 54,61 ----
  env_vars[] = 
  {
    {"emacs_dir", NULL},
!   {"EMACSLOADPATH", "%emacs_dir%/lisp;%emacs_dir%/site-lisp"},
!   {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
    {"EMACSDATA", "%emacs_dir%/etc"},
    {"EMACSPATH", "%emacs_dir%/bin"},
    {"EMACSLOCKDIR", "%emacs_dir%/lock"},
***************
*** 109,124 ****
    DWORD idDde;
    HCONV HConversation;
    HSZ ProgMan;
    char additem[MAX_PATH*2 + 100];
    char *lpext;
  
    if (argc < 2 || argc > 3)
      {
        fprintf (stderr, "usage: addpm emacs_path [icon_path]\n");
        exit (1);
      }
  
!   lpext = add_registry (argv[1]) ? "exe" : "bat";
  
    DdeInitialize (&idDde, (PFNCALLBACK)DdeCallback, APPCMD_CLIENTONLY, 0);
  
--- 109,166 ----
    DWORD idDde;
    HCONV HConversation;
    HSZ ProgMan;
+   char modname[MAX_PATH];
    char additem[MAX_PATH*2 + 100];
    char *lpext;
+   char *emacs_path;
+   char *p;
  
+   /* If no args specified, use our location to set emacs_path.  */
+ #if 0
    if (argc < 2 || argc > 3)
      {
        fprintf (stderr, "usage: addpm emacs_path [icon_path]\n");
        exit (1);
      }
+ #endif
  
!   if (argc > 1)
!     emacs_path = argv[1];
!   else
!     {
!       if (!GetModuleFileName (NULL, modname, MAX_PATH) ||
! 	  (p = strrchr (modname, '\\')) == NULL)
! 	{
! 	  fprintf (stderr, "fatal error");
! 	  exit (1);
! 	}
!       *p = 0;
! 
!       /* Set emacs_path to emacs_dir if we are in "%emacs_dir%\bin".  */
!       if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
! 	{
! 	  *p = 0;
! 	  emacs_path = modname;
! 	}
!       else
! 	{
! 	  fprintf (stderr, "usage: addpm emacs_path [icon_path]\n");
! 	  exit (1);
! 	}
! 
!       /* Tell user what we are going to do.  */
!       {
! 	char msg[ MAX_PATH ];
! 	sprintf (msg, "Install Emacs at %s?\n", emacs_path);
! 	if (!MessageBox (NULL, msg, "Install Emacs", MB_OKCANCEL | MB_ICONQUESTION))
! 	  {
! 	    fprintf (stderr, "Install cancelled\n");
! 	    exit (1);
! 	  }
!       }
!     }
! 
!   lpext = add_registry (emacs_path) ? "exe" : "bat";
  
    DdeInitialize (&idDde, (PFNCALLBACK)DdeCallback, APPCMD_CLIENTONLY, 0);
  
***************
*** 129,135 ****
        DdeCommand ("[CreateGroup (Gnu Emacs)]");
        DdeCommand ("[ReplaceItem (Emacs)]");
        sprintf (additem, "[AddItem (%s\\bin\\runemacs.%s, Emacs%c%s)]",
! 	       argv[1], lpext, (argc>2 ? ',' : ' '),
  	       (argc>2 ? argv[2] : ""));
        DdeCommand (additem);
  
--- 171,177 ----
        DdeCommand ("[CreateGroup (Gnu Emacs)]");
        DdeCommand ("[ReplaceItem (Emacs)]");
        sprintf (additem, "[AddItem (%s\\bin\\runemacs.%s, Emacs%c%s)]",
! 	       emacs_path, lpext, (argc>2 ? ',' : ' '),
  	       (argc>2 ? argv[2] : ""));
        DdeCommand (additem);
  
diff -c pretest/nt/cmdproxy.c.null pretest/nt/cmdproxy.c
*** pretest/nt/cmdproxy.c.null	Tue Jul 22 15:14:35 1997
--- pretest/nt/cmdproxy.c	Thu Jul 17 15:25:22 1997
***************
*** 0 ****
--- 1,580 ----
+ /* Proxy shell designed for use with Emacs on Windows 95 and NT.
+    Copyright (C) 1997 Free Software Foundation, Inc.
+ 
+    Accepts subset of Unix sh(1) command-line options, for compatability
+    with elisp code written for Unix.  When possible, executes external
+    programs directly (a common use of /bin/sh by Emacs), otherwise
+    invokes the user-specified command processor to handle built-in shell
+    commands, batch files and interactive mode.
+ 
+    The main function is simply to process the "-c string" option in the
+    way /bin/sh does, since the standard Windows command shells use the
+    convention that everything after "/c" (the Windows equivalent of
+    "-c") is the input string.
+ 
+ This file is part of GNU Emacs.
+ 
+ GNU Emacs is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GNU Emacs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GNU Emacs; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ #include <windows.h>
+ 
+ #include <stdarg.h>  /* va_args */
+ #include <malloc.h>  /* alloca */
+ #include <stdlib.h>  /* getenv */
+ #include <string.h>  /* strlen */
+ 
+ 
+ /*******  Mock C library routines  *********************************/
+ 
+ /* These routines are used primarily to minimize the executable size.  */
+ 
+ #define stdin  GetStdHandle (STD_INPUT_HANDLE)
+ #define stdout GetStdHandle (STD_OUTPUT_HANDLE)
+ #define stderr GetStdHandle (STD_ERROR_HANDLE)
+ 
+ int
+ vfprintf(HANDLE hnd, char * msg, va_list args)
+ {
+   DWORD bytes_written;
+   char buf[1024];
+ 
+   wvsprintf (buf, msg, args);
+   return WriteFile (hnd, buf, strlen (buf), &bytes_written, NULL);
+ }
+ 
+ int
+ fprintf(HANDLE hnd, char * msg, ...)
+ {
+   va_list args;
+   int rc;
+ 
+   va_start (args, msg);
+   rc = vfprintf (hnd, msg, args);
+   va_end (args);
+ 
+   return rc;
+ }
+ 
+ int
+ printf(char * msg, ...)
+ {
+   va_list args;
+   int rc;
+ 
+   va_start (args, msg);
+   rc = vfprintf (stdout, msg, args);
+   va_end (args);
+ 
+   return rc;
+ }
+ 
+ void
+ fail (char * msg, ...)
+ {
+   va_list args;
+ 
+   va_start (args, msg);
+   vfprintf (stderr, msg, args);
+   va_end (args);
+ 
+   exit (1);
+ }
+ 
+ void
+ warn (char * msg, ...)
+ {
+   va_list args;
+ 
+   va_start (args, msg);
+   vfprintf (stderr, msg, args);
+   va_end (args);
+ }
+ 
+ /******************************************************************/
+ 
+ char *
+ canon_filename (char *fname)
+ {
+   char *p = fname;
+ 
+   while (*p)
+     {
+       if (*p == '/')
+ 	*p = '\\';
+       p++;
+     }
+ 
+   return fname;
+ }
+ 
+ char *
+ skip_space (char *str)
+ {
+   while (isspace (*str)) str++;
+   return str;
+ }
+ 
+ char *
+ skip_nonspace (char *str)
+ {
+   while (*str && !isspace (*str)) str++;
+   return str;
+ }
+ 
+ int escape_char = '\\';
+ 
+ /* Get next token from input, advancing pointer.  */
+ int
+ get_next_token (char * buf, char ** pSrc)
+ {
+   char * p = *pSrc;
+   char * o = buf;
+ 
+   p = skip_space (p);
+   if (*p == '"')
+     {
+       int escape_char_run = 0;
+ 
+       /* Go through src until an ending quote is found, unescaping
+ 	 quotes along the way.  If the escape char is not quote, then do
+ 	 special handling of multiple escape chars preceding a quote
+ 	 char (ie. the reverse of what Emacs does to escape quotes).  */
+       p++;
+       while (1)
+ 	{
+ 	  if (p[0] == escape_char && escape_char != '"')
+ 	    {
+ 	      escape_char_run++;
+ 	      continue;
+ 	    }
+ 	  else if (p[0] == '"')
+ 	    {
+ 	      while (escape_char_run > 1)
+ 		{
+ 		  *o++ = escape_char;
+ 		  escape_char_run -= 2;
+ 		}
+ 
+ 	      if (escape_char_run > 0)
+ 		{
+ 		  /* escaped quote */
+ 		  *o++ = *p++;
+ 		  escape_char_run = 0;
+ 		}
+ 	      else if (p[1] == escape_char && escape_char == '"')
+ 		{
+ 		  /* quote escaped by doubling */
+ 		  *o++ = *p;
+ 		  p += 2;
+ 		}
+ 	      else
+ 		{
+ 		  /* The ending quote.  */
+ 		  *o = '\0';
+ 		  /* Leave input pointer after token.  */
+ 		  p++;
+ 		  break;
+ 		}
+ 	    }
+ 	  else if (p[0] == '\0')
+ 	    {
+ 	      /* End of string, but no ending quote found.  We might want to
+ 		 flag this as an error, but for now will consider the end as
+ 		 the end of the token.  */
+ 	      *o = '\0';
+ 	      break;
+ 	    }
+ 	  else
+ 	    {
+ 	      *o++ = *p++;
+ 	    }
+ 	}
+     }
+   else
+     {
+       /* Next token is delimited by whitespace.  */
+       char * p1 = skip_nonspace (p);
+       memcpy (o, p, p1 - p);
+       o += (p1 - p);
+       p = p1;
+     }
+ 
+   *pSrc = p;
+ 
+   return o - buf;
+ }
+ 
+ /* Search for EXEC file in DIR.  If EXEC does not have an extension,
+    DIR is searched for EXEC with the standard extensions appended.  */
+ int
+ search_dir (char *dir, char *exec, int bufsize, char *buffer)
+ {
+   char *exts[] = {".bat", ".cmd", ".exe", ".com"};
+   int n_exts = sizeof (exts) / sizeof (char *);
+   char *dummy;
+   int i, rc;
+ 
+   /* Search the directory for the program.  */
+   for (i = 0; i < n_exts; i++) 
+     {
+       rc = SearchPath (dir, exec, exts[i], bufsize, buffer, &dummy);
+       if (rc > 0)
+ 	return rc;
+     }
+ 
+   return 0;
+ }
+ 
+ /* Return the absolute name of executable file PROG, including 
+    any file extensions.  If an absolute name for PROG cannot be found,
+    return NULL.  */
+ char *
+ make_absolute (char *prog)
+ {
+   char absname[MAX_PATH];
+   char dir[MAX_PATH];
+   char curdir[MAX_PATH];
+   char *p, *fname;
+   char *path;
+   int i;
+ 
+   /* At least partial absolute path specified; search there.  */
+   if ((isalpha (prog[0]) && prog[1] == ':') ||
+       (prog[0] == '\\'))
+     {
+       /* Split the directory from the filename.  */
+       fname = strrchr (prog, '\\');
+       if (!fname)
+ 	/* Only a drive specifier is given.  */
+ 	fname = prog + 2;
+       strncpy (dir, prog, fname - prog);
+       dir[fname - prog] = '\0';
+ 
+       /* Search the directory for the program.  */
+       if (search_dir (dir, prog, MAX_PATH, absname) > 0)
+ 	return strdup (absname);
+       else
+ 	return NULL;
+     }
+ 
+   if (GetCurrentDirectory (MAX_PATH, curdir) <= 0) 
+     return NULL;
+ 
+   /* Relative path; search in current dir. */
+   if (strpbrk (prog, "\\")) 
+     {
+       if (search_dir (curdir, prog, MAX_PATH, absname) > 0)
+ 	return strdup (absname);
+       else 
+ 	return NULL;
+     }
+   
+   /* Just filename; search current directory then PATH.  */
+   path = alloca (strlen (getenv ("PATH")) + strlen (curdir) + 2);
+   strcpy (path, curdir);
+   strcat (path, ";");
+   strcat (path, getenv ("PATH"));
+ 
+   while (*path)
+     {
+       /* Get next directory from path.  */
+       p = path;
+       while (*p && *p != ';') p++;
+       strncpy (dir, path, p - path);
+       dir[p - path] = '\0';
+ 
+       /* Search the directory for the program.  */
+       if (search_dir (dir, prog, MAX_PATH, absname) > 0)
+ 	return strdup (absname);
+ 
+       /* Move to the next directory.  */
+       path = p + 1;
+     } 
+ 
+   return NULL;
+ }
+ 
+ /*****************************************************************/
+ 
+ #if 0
+ char ** _argv;
+ int     _argc;
+ 
+ /* Parse commandline into argv array, allowing proper quoting of args.  */
+ void
+ setup_argv (void)
+ {
+   char * cmdline = GetCommandLine ();
+   int arg_bytes = 0;
+ 
+   
+ }
+ #endif
+ 
+ /* Information about child proc is global, to allow for automatic
+    termination when interrupted.  At the moment, only one child process
+    can be running at any one time.  */
+ 
+ PROCESS_INFORMATION child;
+ int interactive = TRUE;
+ 
+ BOOL
+ console_event_handler (DWORD event)
+ {
+   switch (event)
+     {
+     case CTRL_C_EVENT:
+     case CTRL_BREAK_EVENT:
+       if (!interactive)
+ 	{
+ 	  /* Both command.com and cmd.exe have the annoying behaviour of
+ 	     prompting "Terminate batch job (y/n)?" when interrupted
+ 	     while running a batch file, even if running in
+ 	     non-interactive (-c) mode.  Try to make up for this
+ 	     deficiency by forcibly terminating the subprocess if
+ 	     running non-interactively.  */
+ 	  if (child.hProcess &&
+ 	      WaitForSingleObject (child.hProcess, 500) != WAIT_OBJECT_0)
+ 	    TerminateProcess (child.hProcess, 0);
+ 	  exit (STATUS_CONTROL_C_EXIT);
+ 	}
+       break;
+ 
+ #if 0
+     default:
+       /* CLOSE, LOGOFF and SHUTDOWN events - actually we don't get these
+          under Windows 95.  */
+       fail ("cmdproxy: received %d event\n", event);
+       if (child.hProcess)
+ 	TerminateProcess (child.hProcess, 0);
+ #endif
+     }
+   return TRUE;
+ }
+ 
+ int
+ spawn (char * progname, char * cmdline)
+ {
+   DWORD rc = 0xff;
+   SECURITY_ATTRIBUTES sec_attrs;
+   STARTUPINFO start;
+ 
+   sec_attrs.nLength = sizeof (sec_attrs);
+   sec_attrs.lpSecurityDescriptor = NULL;
+   sec_attrs.bInheritHandle = FALSE;
+   
+   memset (&start, 0, sizeof (start));
+   start.cb = sizeof (start);
+ 
+   if (CreateProcess (progname, cmdline, &sec_attrs, NULL, TRUE,
+ 		     0, NULL, NULL, &start, &child))
+   {
+     /* wait for completion and pass on return code */
+     WaitForSingleObject (child.hProcess, INFINITE);
+     GetExitCodeProcess (child.hProcess, &rc);
+     CloseHandle (child.hThread);
+     CloseHandle (child.hProcess);
+     child.hProcess = NULL;
+   }
+ 
+   return (int) rc;
+ }
+ 
+ /*******  Main program  ********************************************/
+ 
+ int
+ main (int argc, char ** argv)
+ {
+   int rc;
+   int need_shell;
+   char * cmdline;
+   char * progname;
+   int envsize;
+   char modname[MAX_PATH];
+   char path[MAX_PATH];
+ 
+ 
+   interactive = TRUE;
+ 
+   SetConsoleCtrlHandler ((PHANDLER_ROUTINE) console_event_handler, TRUE);
+ 
+   /* We serve double duty: we can be called either as a proxy for the
+      real shell (that is, because we are defined to be the user shell),
+      or in our role as a helper application for running DOS programs.
+      In the former case, we interpret the command line options as if we
+      were a Unix shell, but in the latter case we simply pass our
+      command line to CreateProcess.  We know which case we are dealing
+      with by whether argv[0] refers to ourself or to some other program.
+      (This relies on an arcane feature of CreateProcess, where we can
+      specify cmdproxy as the module to run, but specify a different
+      program in the command line - the MSVC startup code sets argv[0]
+      from the command line.)  */
+ 
+   if (!GetModuleFileName (NULL, modname, sizeof (modname)))
+     fail ("GetModuleFileName failed");
+ 
+   /* Although Emacs always sets argv[0] to an absolute pathname, we
+      might get run in other ways as well, so convert argv[0] to an
+      absolute name before comparing to the module name.  */
+   if (!SearchPath (NULL, argv[0], ".exe", sizeof (path), path, &progname)
+       || stricmp (modname, path) != 0)
+     {
+       /* We are being used as a helper to run a DOS app; just pass
+ 	 command line to DOS app without change.  */
+       /* TODO: fill in progname.  */
+       return spawn (NULL, GetCommandLine ());
+     }
+ 
+   /* Process command line.  If running interactively (-c or /c not
+      specified) then spawn a real command shell, passing it the command
+      line arguments.
+ 
+      If not running interactively, then attempt to execute the specified
+      command directly.  If necessary, spawn a real shell to execute the
+      command.
+ 
+   */
+ 
+   progname = NULL;
+   cmdline = NULL;
+   /* If no args, spawn real shell for interactive use.  */
+   need_shell = TRUE;
+   interactive = TRUE;
+   /* Ask for a reasonable size environment for command.com.  */
+   envsize = 1024;
+ 
+   while (--argc > 0)
+     {
+       ++argv;
+       /* Only support single letter switches (except for -e); allow / as
+ 	 switch char for compatability with cmd.exe.  */
+       if ( ((*argv)[0] == '-' || (*argv)[0] == '/')
+ 	   && (*argv)[1] != '\0' && (*argv)[2] == '\0' )
+ 	{
+ 	  if ( ((*argv)[1] == 'c') && ((*argv)[2] == '\0')  )
+ 	    {
+ 	      if (--argc == 0)
+ 		fail ("error: expecting arg for %s", *argv);
+ 	      cmdline = *(++argv);
+ 	      interactive = FALSE;
+ 	    }
+ 	  else if ( ((*argv)[1] == 'i') && ((*argv)[2] == '\0')  )
+ 	    {
+ 	      if (cmdline)
+ 		warn ("warning: %s ignored because of -c", *argv);
+ 	    }
+ 	  else if ( ((*argv)[1] == 'e') && ((*argv)[2] == ':')  )
+ 	    {
+ 	      envsize = atoi (*argv + 3);
+ 	      /* Enforce a reasonable minimum size.  */
+ 	      if (envsize < 256)
+ 		envsize = 256;
+ 	    }
+ 	  else
+ 	    {
+ 	      warn ("warning: unknown option %s ignored", *argv);
+ 	    }
+ 	}
+       else
+ 	break;
+     }
+ 
+   /* If -c option, determine if we must spawn a real shell, or if we can
+      execute the command directly ourself.  */
+   if (cmdline)
+     {
+       /* If no redirection or piping, and if program can be found, then
+ 	 run program directly.  Otherwise invoke a real shell. */
+ 
+       static char copout_chars[] = "|<>&";
+ 
+       if (strpbrk (cmdline, copout_chars) == NULL)
+ 	{
+  	  char *args;
+ 
+ 	  /* The program name is the first token of cmdline.  Since
+ 	     filenames cannot legally contain embedded quotes, the value
+ 	     of escape_char doesn't matter.  */
+ 	  args = cmdline;
+ 	  if (!get_next_token (path, &args))
+ 	    fail ("error: no program name specified.\n");
+ 
+ 	  canon_filename (path);
+ 	  progname = make_absolute (path);
+ 
+ 	  /* If we found the program, run it directly (if not found it
+              might be an internal shell command, so don't fail).  */
+ 	  if (progname != NULL)
+ 	    need_shell = FALSE;
+ 	}
+     }
+ 
+   if (need_shell)
+     {
+       char * p;
+ 
+       progname = getenv ("COMSPEC");
+       if (!progname)
+ 	fail ("error: COMSPEC is not set");
+ 
+       canon_filename (progname);
+       progname = make_absolute (progname);
+ 
+       if (progname == NULL || strchr (progname, '\\') == NULL)
+ 	fail ("make_absolute failed");
+ 
+       if (cmdline)
+ 	{
+ 	  /* Convert to syntax expected by cmd.exe/command.com for
+ 	     running non-interactively.  Always quote program name in
+ 	     case path contains spaces (fortunately it can't contain
+ 	     quotes, since they are illegal in path names).  */
+ 	  wsprintf (p = alloca (strlen (cmdline) + strlen (progname) + 7),
+ 		    "\"%s\" /c %s", progname, cmdline);
+ 	  cmdline = p;
+ 	}
+       else
+ 	{
+ 	  /* Provide dir arg expected by command.com when first started
+ 	     interactively (the "command search path").  cmd.exe does
+ 	     not require it, but accepts it silently - presumably other
+ 	     DOS compatible shells do the same.  To avoid potential
+ 	     problems with spaces in command dir (which cannot be quoted
+ 	     - command.com doesn't like it), we always use the 8.3 form.  */
+ 	  GetShortPathName (progname, path, sizeof (path));
+ 	  p = strrchr (path, '\\');
+ 	  /* Trailing slash is acceptable.  */
+ 	  p++;
+ 
+ 	  /* Set environment size - again cmd.exe ignores this silently.  */
+ 	  wsprintf (p, " /e:%d", envsize);
+ 
+ 	  /* Quote progname in case it contains spaces.  */
+ 	  wsprintf (cmdline = alloca (strlen (progname) + strlen (path) + 4),
+ 		    "\"%s\" %s", progname, path);
+ 	}
+     }
+ 
+   if (!progname)
+     fail ("Internal error: program name not defined\n");
+ 
+   if (!cmdline)
+     cmdline = progname;
+ 
+   rc = spawn (progname, cmdline);
+ 
+   return rc;
+ }
diff -c pretest/nt/debug.bat.null pretest/nt/debug.bat
*** pretest/nt/debug.bat.null	Tue Jul 22 15:14:35 1997
--- pretest/nt/debug.bat	Mon Jul 14 14:11:48 1997
***************
*** 0 ****
--- 1,41 ----
+ @echo off 
+ REM !!! Warning: This file automatically generated !!! 
+ set emacs_dir=D:\AndrewI\work\pretest
+ 
+ REM Here begins emacs.bat.in
+ 
+ REM Set OS specific values.
+ set ARCH_SAVE=%PROCESSOR_ARCHITECTURE%
+ set PROCESSOR_ARCHITECTURE=
+ if "%ARCH_SAVE%" == "%PROCESSOR_ARCHITECTURE%" goto win95
+ set PROCESSOR_ARCHITECTURE=%ARCH_SAVE%
+ set SHELL=cmd
+ goto next
+ 
+ :win95
+ set SHELL=command
+ 
+ :next
+ 
+ set EMACSLOADPATH=%emacs_dir%\lisp
+ set EMACSDATA=%emacs_dir%\etc
+ set EMACSPATH=%emacs_dir%\bin
+ set EMACSLOCKDIR=%emacs_dir%\lock
+ set INFOPATH=%emacs_dir%\info
+ set EMACSDOC=%emacs_dir%\etc
+ set TERM=CMD
+ 
+ REM The variable HOME is used to find the startup file, ~\_emacs.  Ideally,
+ REM this will not be set in this file but should already be set before
+ REM this file is invoked.  If HOME is not set, use some generic default.
+ 
+ set HOME_SAVE=%HOME%
+ set HOME_EXISTS=yes
+ set HOME_DEFAULT=C:\
+ set HOME=
+ if "%HOME%" == "%HOME_SAVE%" set HOME_EXISTS=no
+ if "%HOME_EXISTS%" == "yes" set HOME=%HOME_SAVE%
+ if "%HOME_EXISTS%" == "no" set HOME=%HOME_DEFAULT%
+ if "%HOME_EXISTS%" == "no" echo HOME is not set!  Using %HOME% as a default...
+ 
+ start c:\msdev\bin\msdev -nologo %emacs_dir%\bin\emacs.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
diff -c pretest/nt/emacs.bat.null pretest/nt/emacs.bat
*** pretest/nt/emacs.bat.null	Tue Jul 22 15:14:35 1997
--- pretest/nt/emacs.bat	Mon Jul 14 14:11:50 1997
***************
*** 0 ****
--- 1,41 ----
+ @echo off 
+ REM !!! Warning: This file automatically generated !!! 
+ set emacs_dir=D:\ANDREWI\work\pretest
+ 
+ REM Here begins emacs.bat.in
+ 
+ REM Set OS specific values.
+ set ARCH_SAVE=%PROCESSOR_ARCHITECTURE%
+ set PROCESSOR_ARCHITECTURE=
+ if "%ARCH_SAVE%" == "%PROCESSOR_ARCHITECTURE%" goto win95
+ set PROCESSOR_ARCHITECTURE=%ARCH_SAVE%
+ set SHELL=cmd
+ goto next
+ 
+ :win95
+ set SHELL=command
+ 
+ :next
+ 
+ set EMACSLOADPATH=%emacs_dir%\lisp;%emacs_dir%\site-lisp
+ set EMACSDATA=%emacs_dir%\etc
+ set EMACSPATH=%emacs_dir%\bin
+ set EMACSLOCKDIR=%emacs_dir%\lock
+ set INFOPATH=%emacs_dir%\info
+ set EMACSDOC=%emacs_dir%\etc
+ set TERM=CMD
+ 
+ REM The variable HOME is used to find the startup file, ~\_emacs.  Ideally,
+ REM this will not be set in this file but should already be set before
+ REM this file is invoked.  If HOME is not set, use some generic default.
+ 
+ set HOME_SAVE=%HOME%
+ set HOME_EXISTS=yes
+ set HOME_DEFAULT=C:\
+ set HOME=
+ if "%HOME%" == "%HOME_SAVE%" set HOME_EXISTS=no
+ if "%HOME_EXISTS%" == "yes" set HOME=%HOME_SAVE%
+ if "%HOME_EXISTS%" == "no" set HOME=%HOME_DEFAULT%
+ if "%HOME_EXISTS%" == "no" echo HOME is not set!  Using %HOME% as a default...
+ 
+ %emacs_dir%\bin\emacs.exe %1 %2 %3 %4 %5 %6 %7 %8 %9
diff -c pretest/nt/emacs.bat.in.orig pretest/nt/emacs.bat.in
*** pretest/nt/emacs.bat.in.orig	Fri Jun 30 22:18:58 1995
--- pretest/nt/emacs.bat.in	Mon Jul 14 14:11:50 1997
***************
*** 14,20 ****
  
  :next
  
! set EMACSLOADPATH=%emacs_dir%\lisp
  set EMACSDATA=%emacs_dir%\etc
  set EMACSPATH=%emacs_dir%\bin
  set EMACSLOCKDIR=%emacs_dir%\lock
--- 14,20 ----
  
  :next
  
! set EMACSLOADPATH=%emacs_dir%\lisp;%emacs_dir%\site-lisp
  set EMACSDATA=%emacs_dir%\etc
  set EMACSPATH=%emacs_dir%\bin
  set EMACSLOCKDIR=%emacs_dir%\lock
diff -c pretest/nt/makefile.def.orig pretest/nt/makefile.def
*** pretest/nt/makefile.def.orig	Fri May  3 20:00:15 1996
--- pretest/nt/makefile.def	Tue Jul 22 12:26:52 1997
***************
*** 34,40 ****
--- 34,42 ----
  
  # Define MSVCNT11 to be nonzero if you are using the MSVCNT 1.1 environment.
  # MSVCNT11	= 1
+ !ifndef MSVCNT11
  MSVCNT11        = 0
+ !endif
  
  #
  # END CONFIGURATION
***************
*** 119,136 ****
  !if $(MSVCNT11)
  BASE_LIBS	= $(libc) $(baselibs) oldnames.lib
  !else
! BASE_LIBS	= $(libc) $(baselibs)
  !endif
  
  # We want any debugging info in the executable.
  !if "$(LINK)" == "link32"
  SYS_LDFLAGS	= 
  !else
! SYS_LDFLAGS	= -pdb:none -release -incremental:no -version:3.10
  !endif
  
  INC             = -I.
  CFLAGS_COMMON	= -nologo $(INC) $(ARCH_CFLAGS) $(LOCAL_FLAGS) -DWIN32_LEAN_AND_MEAN -D$(ARCH)
  !if $(MSVCNT11)
  CFLAGS          = $(CFLAGS_COMMON) -D_CRTAPI1=_cdecl
  !else
--- 121,142 ----
  !if $(MSVCNT11)
  BASE_LIBS	= $(libc) $(baselibs) oldnames.lib
  !else
! BASE_LIBS	= $(libc) $(baselibs) -nodefaultlib:oldnames.lib
  !endif
  
  # We want any debugging info in the executable.
  !if "$(LINK)" == "link32"
  SYS_LDFLAGS	= 
  !else
! SYS_LDFLAGS	= -release -incremental:no -version:3.10
  !endif
  
  INC             = -I.
+ !if "$(BUILD_TYPE)" == "spd"
  CFLAGS_COMMON	= -nologo $(INC) $(ARCH_CFLAGS) $(LOCAL_FLAGS) -DWIN32_LEAN_AND_MEAN -D$(ARCH)
+ !else
+ CFLAGS_COMMON	= -nologo $(INC) $(ARCH_CFLAGS) $(LOCAL_FLAGS) -DWIN32_LEAN_AND_MEAN -D$(ARCH) -DEMACSDEBUG
+ !endif
  !if $(MSVCNT11)
  CFLAGS          = $(CFLAGS_COMMON) -D_CRTAPI1=_cdecl
  !else
***************
*** 170,176 ****
  
  !if "$(ARCH)" == "i386"
  !if "$(BUILD_TYPE)" == "spd"
! ARCH_CFLAGS     = -nologo -D_X86_=1 -c -Zel -W2 -H63 -O2b2 -G5d -Zi
  !else
  ARCH_CFLAGS     = -nologo -D_X86_=1 -c -Zel -W2 -H63 -G3d -Zi -Od
  !endif
--- 176,182 ----
  
  !if "$(ARCH)" == "i386"
  !if "$(BUILD_TYPE)" == "spd"
! ARCH_CFLAGS     = -nologo -D_X86_=1 -c -Zel -W2 -H63 -Oxsb2 -G5dF -Zi
  !else
  ARCH_CFLAGS     = -nologo -D_X86_=1 -c -Zel -W2 -H63 -G3d -Zi -Od
  !endif
***************
*** 183,189 ****
  
  !else
  !if "$(ARCH)" == "alpha"
! ARCH_CFLAGS     = -D_ALPHA_=1 -c -Ze -Zi -W2 -D__stdcall= -D__cdecl=
  ARCH_LDFLAGS	= -align:0x2000 $(SYS_LDFLAGS)
  
  !else
--- 189,199 ----
  
  !else
  !if "$(ARCH)" == "alpha"
! !if "$(BUILD_TYPE)" == "spd"
! ARCH_CFLAGS     = -D_ALPHA_=1 -c -Ze -Zi -W2 -Od -D__stdcall= -D__cdecl=
! !else
! ARCH_CFLAGS     = -D_ALPHA_=1 -c -Ze -Zi -W2 -O1 -D__stdcall= -D__cdecl=
! !endif
  ARCH_LDFLAGS	= -align:0x2000 $(SYS_LDFLAGS)
  
  !else
diff -c pretest/nt/makefile.nt.orig pretest/nt/makefile.nt
*** pretest/nt/makefile.nt.orig	Wed Jul 17 00:19:28 1996
--- pretest/nt/makefile.nt	Mon Jul 14 14:11:50 1997
***************
*** 22,28 ****
  #						  9-6-94
  !include makefile.def
  
! ALL		= $(BLD)\addpm.exe $(BLD)\runemacs.exe
  !if $(MSVCNT11)
  TRES		= $(BLD)\emacs.res
  !else
--- 22,28 ----
  #						  9-6-94
  !include makefile.def
  
! ALL		= $(BLD)\addpm.exe $(BLD)\runemacs.exe $(BLD)\cmdproxy.exe
  !if $(MSVCNT11)
  TRES		= $(BLD)\emacs.res
  !else
***************
*** 38,43 ****
--- 38,49 ----
  		  $(LINK) -out:$@ -subsystem:console -entry:mainCRTStartup \
  		  $(SYS_LDFLAGS) $** $(BASE_LIBS) $(ADVAPI32) user32.lib
  
+ cmdproxy:	  $(BLD) $(BLD)\cmdproxy.exe
+ $(BLD)\cmdproxy.obj: cmdproxy.c
+ $(BLD)\cmdproxy.exe: $(BLD)\cmdproxy.obj
+ 		  $(LINK) -out:$@ -subsystem:console -entry:mainCRTStartup \
+ 		  $(SYS_LDFLAGS) $** $(BASE_LIBS) user32.lib
+ 
  #
  # The resource file.  NT 3.10 requires the use of cvtres; even though
  # it is not necessary on later versions, it is still ok to use it.
***************
*** 93,98 ****
--- 99,105 ----
  		cd ..\nt		
  		- $(CP) emacs.bat $(INSTALL_DIR)\bin
  		- $(CP) $(BLD)\addpm.exe $(INSTALL_DIR)\bin
+ 		- $(CP) $(BLD)\cmdproxy.exe $(INSTALL_DIR)\bin
  		- $(CP) $(BLD)\runemacs.exe $(INSTALL_DIR)\bin
  		- $(ADDPM) $(INSTALL_DIR)
  		- $(DEL) ..\same-dir.tst
***************
*** 112,117 ****
--- 119,125 ----
  		- mkdir $(INSTALL_DIR)\bin
  		- $(CP) emacs.bat $(INSTALL_DIR)\bin
  		- $(CP) $(BLD)\addpm.exe $(INSTALL_DIR)\bin
+ 		- $(CP) $(BLD)\cmdproxy.exe $(INSTALL_DIR)\bin
  		- $(CP) $(BLD)\runemacs.exe $(INSTALL_DIR)\bin
  		- $(DEL) ..\same-dir.tst
  		- $(DEL) $(INSTALL_DIR)\same-dir.tst
***************
*** 131,136 ****
--- 139,145 ----
  		- mkdir $(INSTALL_DIR)\info
  		- mkdir $(INSTALL_DIR)\lock
  		- mkdir $(INSTALL_DIR)\data
+ 		- mkdir $(INSTALL_DIR)\site-lisp
  		if not exist ..\same-dir.tst $(CP_DIR) ..\etc $(INSTALL_DIR)\etc
  		if not exist ..\same-dir.tst $(CP_DIR) ..\info $(INSTALL_DIR)\info
  		- $(DEL) ..\same-dir.tst
diff -c pretest/src/ChangeLog.orig pretest/src/ChangeLog
*** pretest/src/ChangeLog.orig	Wed Aug 21 21:30:17 1996
--- pretest/src/ChangeLog	Mon Jul 14 14:11:52 1997
***************
*** 1,3 ****
--- 1,133 ----
+ Thu Jul 03 11:37:46 1997  Geoff Voelker  <voelker@cs.washington.edu>
+ 
+ 	* w32term.c (w32_read_socket): For WM_MOVE, use the top and left
+ 	positions of the window manager window, not the client window.
+ 	(x_set_offset) [HAVE_NTGUI]: Do not add border widths.
+ 
+ 	* w32fns.c (win32_wnd_proc): Pass on WM_DISPLAYCHANGE messages.
+ 	* w32term.c (w32_read_socket): Handle WM_DISPLAYCHANGE messages.
+ 
+ 	* ntinevt.c (key_event): New parameter isdead. Set isdead if the
+  	key press was done using a dead key.
+ 	(win32_read_socket): Pass in new parameter to key_event.
+ 	* w32term.c: New extern declaration for key_event.
+ 	(w32_read_socket): Let key_event determine whether the key is dead.
+ 
+ 	* ntheap.c (_heap_init, _heap_term): New functions.
+ 	
+ Wed Jun 04 20:42:37 1997  Michael Welsh Duggan  <md5i@schenley.com>
+ 
+       * w32term.h (WM_MOUSEWHEEL): Define if not already defined.
+       Necessary for pre VC5.0 distribution.
+ 
+       * w32term.c (construct_mouse_wheel): New function.  Constructs an
+       input event from a WM_MOUSEWHEEL message.
+       (w32_read_socket): Handle WM_MOUSEWHEEL.
+ 
+       * w32fns.c (win32_wnd_proc): Capture and handle WM_MOUSEWHEEL
+       events.
+ 
+       * termhooks.h (event_kind) [WINDOWSNT]: New event type: mouse_wheel.
+ 
+       * keyboard.c (Qmouse_wheel) [WINDOWSNT]: New variable.
+       (eat_mouse_events) [WINDOWSNT]: Eat mouse-wheel events as well.
+       (mouse_wheel_syms) [WINDOWSNT]: New variable.
+       (lispy_mouse_wheel_names) [WINDOWSNT]: New variable.
+       (make_lispy_event) [WINDOWSNT]: Make mouse-wheel events.
+       (syms_of_keyboard) [WINDOWSNT]: Define Qmouse_wheel and
+       mouse_wheel_syms.
+ 
+ Thu May 08 20:35:58 1997  Michael Welsh Duggan  <md5i@schenley.com>
+ 
+ 	* w32fns.c (x_to_win32_color): Added support for X Windows RGB
+ 	string specifications.
+ 
+ Fri May 23 13:25:40 1997  Nico Francois  <nico.francois@scala.nl>
+ 
+ 	* w32menu.c (single_keymap_panes): Fixed problem with 'descrip' lisp
+ 	object not being protected properly (GCPRO).
+ 	(get_single_keymap_event): Fixed problem with 'descrip' lisp object
+ 	not being protected properly (GCPRO).
+ 
+ Fri May 16 19:08:34 1997  Nico Francois  <nico.francois@scala.nl>
+ 
+ 	* w32menu.c (name_is_separator): New function.  Will check if
+ 	a menu item name is a separator.  An empty name or a name consting
+ 	only of dashes ('-') is considered a separator.  Previously only
+ 	names with exactly two dashes ("--") where considered separators,
+ 	but some packages use more than two dashes when they want to add a
+ 	separator to a menu (vc-hooks.el for example).
+ 
+ Mon May 12 16:57:32 1997  Nico Francois  <nico.francois@scala.nl>
+ 
+ 	* w32menu.c (list_of_panes): If a pane's name is empty ("") items
+ 	are now placed in the main popup instead of a blank-named submenu.
+ 	This seems to be an undocumented feature of x-popup-menu.
+ 	(list_of_items): New argument HMENU.  If NULL the function will
+ 	work as before.  If non-NULL the function will add items to the
+ 	specified menu.
+ 
+ Wed May 07 23:52:59 1997  Michael Welsh Duggan  <md5i@schenley.com>
+ 
+ 	* w32menu.c (get_frame_menubar_event): Check for the possibility
+ 	of a menu-bar button.  A menu-bar button is a caption on the menu
+ 	bar with no submenu.
+ 	(set_frame_menubar): Correctly handle menu-bar buttons.
+ 
+ Wed May 07 14:37:29 1997  Nico Francois  <nico.francois@scala.nl>
+ 
+ 	* w32menu.c (list_of_items): Use 1 and 0 instead of Qt and Qnil
+ 	for enable in add_menu_item
+ 
+ Tue May 06 14:57:55 1997  Michael Welsh Duggan  <md5i@schenley.com>
+ 
+ 	* w32menu.c (win32menu_show): Call eat_mouse_events in order to
+ 	get rid of any extraneous mouse events.
+ 
+ 	* lisp.h (eat_mouse_events): Declare here.
+ 
+ 	* keyboard.c (eat_mouse_events): New function.  Changes kind of
+ 	mouse events in the keayboard buffer to no_event.
+ 
+ Thu Apr 24 19:44:13 1997  Michael Welsh Duggan  <md5i@schenley.com>
+ 
+ 	* w32fns.c (win32_wnd_proc): Allow a dragged selection from a
+ 	popup menu started up by a mouse down event.
+ 
+ 	* w32menu.c (list_of_panes): Only bring up one pane if the length
+ 	of the list of panes is one.
+ 
+ Tue Apr 22 14:01:10 1997  Michael Welsh Duggan  <md5i@schenley.com>
+ 
+ 	* w32fns.c (win32_wnd_proc): Capture and handle
+ 	WM_EMACS_TRACKPOPUPMENU events.
+ 
+ 	* w32term.h (WM_EMACS_TRACKPOPUPMENU): New Macro.
+ 
+ 	* w32menu.c (add_menu_item): equiv parameter send and paid
+ 	attention to.
+ 	(keymap_panes): Use CreatePopupMenu.
+ 	(single_keymap_panes): Use CreatePopupMenu.  Send key descriptions
+ 	to add_menu_item.
+ 	(list_of_panes): Use CreatePopupMenu.
+ 	(list_of_items): Use CreatePopupMenu.  Send nil description to
+ 	add_menu_item.
+ 	(get_menu_event): Send keymap instead of menu to
+ 	get_keymap_event.
+ 	(Fx_popup_menu): Extra parameter to mouse_position_hook.  Don't
+ 	send address of menu to win32menu_show.
+ 	(win32menu_show): Send message to call popup menu rather than
+ 	trying directly.  get_menu_event should take an address.
+ 
+ Thu Apr 17 13:09:04 1997  Andrew Innes  <andrewi@harlequin.co.uk>
+ 
+ 	* fileio.c (Fexpand_file_name): Fix expansion of "/foo/../".
+ 
+ Tue Dec 10 18:26:38 1996  Andrew Innes  <andrewi@harlequin.co.uk>
+ 
+ 	* fileio.c (Fwrite_region): Be careful not to destroy contents of
+ 	existing file when appending.
+ 
  Wed Aug 21 03:51:42 1996  Richard Stallman  <rms@psilocin.gnu.ai.mit.edu>
  
  	* Version 19.34 released.
diff -c pretest/src/alloc.c.orig pretest/src/alloc.c
*** pretest/src/alloc.c.orig	Mon Jun 10 19:01:01 1996
--- pretest/src/alloc.c	Fri Jul 18 14:37:52 1997
***************
*** 294,299 ****
--- 294,309 ----
    UNBLOCK_INPUT;
  }
  
+ char *
+ xstrdup (s)
+      char * s;
+ {
+   int size = strlen (s) + 1;
+   char * p = (char *) xmalloc (size);
+   memcpy (p, s, size);
+   return p;
+ }
+ 
  
  /* Arranging to disable input signals while we're in malloc.
  
diff -c pretest/src/fileio.c.orig pretest/src/fileio.c
*** pretest/src/fileio.c.orig	Sat Jul 20 08:00:27 1996
--- pretest/src/fileio.c	Mon Jul 21 10:55:10 1997
***************
*** 894,899 ****
--- 894,906 ----
  	      goto look_again;
  	}
    }
+ #ifdef WINDOWSNT
+   /* If we see "c://somedir", we want to strip the first slash after the
+      colon when stripping the drive letter.  Otherwise, this expands to
+      "//somedir".  */
+   if (drive && IS_DIRECTORY_SEP (nm[0]) && IS_DIRECTORY_SEP (nm[1]))
+     nm++;
+ #endif /* WINDOWSNT */
  #endif /* DOS_NT */
  
    /* Handle // and /~ in middle of file name
***************
*** 1387,1393 ****
  	{
  	  while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
  	    ;
! 	  if (o == target && IS_ANY_SEP (*o))
  	    ++o;
  	  p += 3;
  	}
--- 1394,1401 ----
  	{
  	  while (o != target && (--o) && !IS_DIRECTORY_SEP (*o))
  	    ;
! 	  /* Keep initial / only if this is the whole name. */
! 	  if (o == target && IS_ANY_SEP (*o) && p[3] == 0)
  	    ++o;
  	  p += 3;
  	}
***************
*** 2354,2363 ****
        || INTEGERP (ok_if_already_exists))
      barf_or_query_if_file_exists (newname, "make it a new name",
  				  INTEGERP (ok_if_already_exists), 0);
- #ifdef WINDOWSNT
-   /* Windows does not support this operation.  */
-   report_file_error ("Adding new name", Flist (2, &file));
- #else /* not WINDOWSNT */
  
    unlink (XSTRING (newname)->data);
    if (0 > link (XSTRING (file)->data, XSTRING (newname)->data))
--- 2362,2367 ----
***************
*** 2370,2376 ****
        report_file_error ("Adding new name", Flist (2, &file));
  #endif
      }
- #endif /* not WINDOWSNT */
  
    UNGCPRO;
    return Qnil;
--- 2374,2379 ----
***************
*** 2987,2992 ****
--- 2990,2996 ----
    Lisp_Object p;
    int total;
    int not_regular = 0;
+   int crlf_conversion_required = 0;
  
    if (current_buffer->base_buffer && ! NILP (visit))
      error ("Cannot do file visiting in an indirect buffer");
***************
*** 3078,3123 ****
  	error ("maximum buffer size exceeded");
      }
  
    /* If requested, replace the accessible part of the buffer
       with the file contents.  Avoid replacing text at the
       beginning or end of the buffer that matches the file contents;
       that preserves markers pointing to the unchanged parts.  */
- #ifdef DOS_NT
-   /* On MSDOS, replace mode doesn't really work, except for binary files,
-      and it's not worth supporting just for them.  */
-   if (!NILP (replace))
-     {
-       replace = Qnil;
-       XSETFASTINT (beg, 0);
-       XSETFASTINT (end, st.st_size);
-       del_range_1 (BEGV, ZV, 0);
-     }
- #else /* not DOS_NT */
    if (!NILP (replace))
      {
        unsigned char buffer[1 << 14];
        int same_at_start = BEGV;
        int same_at_end = ZV;
        int overlap;
  
        immediate_quit = 1;
-       QUIT;
        /* Count how many chars at the start of the file
  	 match the text at the beginning of the buffer.  */
        while (1)
  	{
  	  int nread, bufpos;
  
! 	  nread = read (fd, buffer, sizeof buffer);
  	  if (nread < 0)
  	    error ("IO error reading %s: %s",
  		   XSTRING (filename)->data, strerror (errno));
  	  else if (nread == 0)
  	    break;
  	  bufpos = 0;
! 	  while (bufpos < nread && same_at_start < ZV
! 		 && FETCH_CHAR (same_at_start) == buffer[bufpos])
! 	    same_at_start++, bufpos++;
  	  /* If we found a discrepancy, stop the scan.
  	     Otherwise loop around and scan the next bufferful.  */
  	  if (bufpos != nread)
--- 3082,3175 ----
  	error ("maximum buffer size exceeded");
      }
  
+ #ifdef DOS_NT
+   /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
+   /* Determine file type (text/binary) from its name.
+      Note that the buffer_file_type changes here when the file
+      being inserted is not of the same type as the original buffer.  */
+   current_buffer->buffer_file_type = call1 (Qfind_buffer_file_type, filename);
+   if (NILP (current_buffer->buffer_file_type))
+     crlf_conversion_required = 1;
+ #endif /* DOS_NT */
+ 
    /* If requested, replace the accessible part of the buffer
       with the file contents.  Avoid replacing text at the
       beginning or end of the buffer that matches the file contents;
       that preserves markers pointing to the unchanged parts.  */
    if (!NILP (replace))
      {
        unsigned char buffer[1 << 14];
        int same_at_start = BEGV;
        int same_at_end = ZV;
        int overlap;
+       /* Offset into the file where discrepancy begins.  */
+       int same_at_start_in_file = 0;
+       /* Offset into the file where discrepancy ends.  */
+       int same_at_end_in_file = st.st_size;
+       /* DOS_NT only: is there a `\r' character left in the buffer? */
+       int cr_left_in_buffer = 0;
+       /* DOS_NT only: was `\n' the first character in previous bufferful?  */
+       int last_was_lf = 0;
  
        immediate_quit = 1;
        /* Count how many chars at the start of the file
  	 match the text at the beginning of the buffer.  */
        while (1)
  	{
  	  int nread, bufpos;
  
! 	  QUIT;
! 
! 	  if (cr_left_in_buffer)
! 	    {
! 	      nread = read (fd, buffer + 1, sizeof(buffer) - 1);
! 	      cr_left_in_buffer = 0;
! 	      if (nread >= 0)
! 		nread++;
! 	    }
! 	  else
! 	    nread = read (fd, buffer, sizeof buffer);
  	  if (nread < 0)
  	    error ("IO error reading %s: %s",
  		   XSTRING (filename)->data, strerror (errno));
  	  else if (nread == 0)
  	    break;
  	  bufpos = 0;
! 
! 	  /* DOS_NT text files require that we ignore a `\r' before a `\n'.  */
! 	  if (crlf_conversion_required)
! 	    while (bufpos < nread && same_at_start < ZV)
! 	      {
! 		int filec = buffer[bufpos];
! 		int bufc  = FETCH_CHAR (same_at_start);
! 
! 		if (filec == bufc)
! 		  same_at_start++, bufpos++, same_at_start_in_file++;
! 		else if (filec == '\r' && bufc == '\n')
! 		  {
! 		    bufpos++;
! 		    /* If the `\r' is the last character in this buffer,
! 		       it will be examined with the next bufferful.  */
! 		    if (bufpos == nread)
! 		      {
! 			buffer[0] = filec;
! 			cr_left_in_buffer = 1;
! 		      }
! 		    else if (buffer[bufpos] == bufc)
! 		      {
! 			same_at_start_in_file += 2;
! 			same_at_start++;
! 		      }
! 		    else
! 		      break;
! 		  }
! 		else
! 		  break;
! 	      }
! 	  else
! 	    while (bufpos < nread && same_at_start < ZV
! 		   && FETCH_CHAR (same_at_start) == buffer[bufpos])
! 	      same_at_start++, same_at_start_in_file++, bufpos++;
  	  /* If we found a discrepancy, stop the scan.
  	     Otherwise loop around and scan the next bufferful.  */
  	  if (bufpos != nread)
***************
*** 3126,3132 ****
        immediate_quit = 0;
        /* If the file matches the buffer completely,
  	 there's no need to replace anything.  */
!       if (same_at_start - BEGV == st.st_size)
  	{
  	  close (fd);
  	  specpdl_ptr--;
--- 3178,3184 ----
        immediate_quit = 0;
        /* If the file matches the buffer completely,
  	 there's no need to replace anything.  */
!       if (same_at_start_in_file == st.st_size)
  	{
  	  close (fd);
  	  specpdl_ptr--;
***************
*** 3135,3149 ****
  	  goto handled;
  	}
        immediate_quit = 1;
-       QUIT;
        /* Count how many chars at the end of the file
  	 match the text at the end of the buffer.  */
        while (1)
  	{
  	  int total_read, nread, bufpos, curpos, trial;
  
  	  /* At what file position are we now scanning?  */
! 	  curpos = st.st_size - (ZV - same_at_end);
  	  /* If the entire file matches the buffer tail, stop the scan.  */
  	  if (curpos == 0)
  	    break;
--- 3187,3202 ----
  	  goto handled;
  	}
        immediate_quit = 1;
        /* Count how many chars at the end of the file
  	 match the text at the end of the buffer.  */
        while (1)
  	{
  	  int total_read, nread, bufpos, curpos, trial;
  
+ 	  QUIT;
+ 
  	  /* At what file position are we now scanning?  */
! 	  curpos = same_at_end_in_file;
  	  /* If the entire file matches the buffer tail, stop the scan.  */
  	  if (curpos == 0)
  	    break;
***************
*** 3165,3200 ****
  	  /* Scan this bufferful from the end, comparing with
  	     the Emacs buffer.  */
  	  bufpos = total_read;
! 	  /* Compare with same_at_start to avoid counting some buffer text
! 	     as matching both at the file's beginning and at the end.  */
! 	  while (bufpos > 0 && same_at_end > same_at_start
! 		 && FETCH_CHAR (same_at_end - 1) == buffer[bufpos - 1])
! 	    same_at_end--, bufpos--;
  	  /* If we found a discrepancy, stop the scan.
  	     Otherwise loop around and scan the preceding bufferful.  */
  	  if (bufpos != 0)
  	    break;
! 	  /* If display current starts at beginning of line,
  	     keep it that way.  */
  	  if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
  	    XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
  	}
        immediate_quit = 0;
  
-       /* Don't try to reuse the same piece of text twice.  */
-       overlap = same_at_start - BEGV - (same_at_end + st.st_size - ZV);
-       if (overlap > 0)
- 	same_at_end += overlap;
- 
        /* Arrange to read only the nonmatching middle part of the file.  */
!       XSETFASTINT (beg, same_at_start - BEGV);
!       XSETFASTINT (end, st.st_size - (ZV - same_at_end));
  
        del_range_1 (same_at_start, same_at_end, 0);
        /* Insert from the file at the proper position.  */
        SET_PT (same_at_start);
      }
- #endif /* not DOS_NT */
  
    total = XINT (end) - XINT (beg);
  
--- 3218,3283 ----
  	  /* Scan this bufferful from the end, comparing with
  	     the Emacs buffer.  */
  	  bufpos = total_read;
! 	  /* DOS_NT text files require that we ignore a `\r' before a `\n'.  */
! 	  if (crlf_conversion_required)
! 	    /* Compare with same_at_start to avoid counting some buffer text
! 	       as matching both at the file's beginning and at the end.  */
! 	    while (bufpos > 0 && same_at_end > same_at_start
! 		   && same_at_end_in_file > same_at_start_in_file)
! 	      {
! 		int filec = buffer[bufpos - 1];
! 		int bufc  = FETCH_CHAR (same_at_end - 1);
! 
! 		/* Account for `\n' in previous bufferful.  */
! 		if (last_was_lf && filec == '\r')
! 		  {
! 		    same_at_end_in_file--, bufpos--;
! 		    last_was_lf = 0;
! 		  }
! 		else if (filec == bufc)
! 		  {
! 		    last_was_lf = 0;
! 		    same_at_end--, same_at_end_in_file--, bufpos--;
! 		    if (bufc == '\n')
! 		      {
! 			if (bufpos <= 0)
! 			  last_was_lf = 1;
! 			else if (same_at_end_in_file <= same_at_start_in_file)
! 			  break;
! 			else if (buffer[bufpos - 1] == '\r')
! 			  same_at_end_in_file--, bufpos--;
! 		      }
! 		  }
! 		else
! 		  {
! 		    last_was_lf = 0;
! 		    break;
! 		  }
! 	      }
! 	  else
! 	    while (bufpos > 0 && same_at_end > same_at_start
! 		   && same_at_end_in_file > same_at_start_in_file
! 		   && FETCH_CHAR (same_at_end - 1) == buffer[bufpos - 1])
! 	      same_at_end--, same_at_end_in_file--, bufpos--;
  	  /* If we found a discrepancy, stop the scan.
  	     Otherwise loop around and scan the preceding bufferful.  */
  	  if (bufpos != 0)
  	    break;
! 	  /* If display currently starts at beginning of line,
  	     keep it that way.  */
  	  if (XBUFFER (XWINDOW (selected_window)->buffer) == current_buffer)
  	    XWINDOW (selected_window)->start_at_line_beg = Fbolp ();
  	}
        immediate_quit = 0;
  
        /* Arrange to read only the nonmatching middle part of the file.  */
!       XSETFASTINT (beg, same_at_start_in_file);
!       XSETFASTINT (end, same_at_end_in_file);
  
        del_range_1 (same_at_start, same_at_end, 0);
        /* Insert from the file at the proper position.  */
        SET_PT (same_at_start);
      }
  
    total = XINT (end) - XINT (beg);
  
***************
*** 3248,3269 ****
  
  #ifdef DOS_NT
    /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
!   /* Determine file type from name and remove LFs from CR-LFs if the file
!      is deemed to be a text file.  */
!   {
!     current_buffer->buffer_file_type
!       = call1 (Qfind_buffer_file_type, filename);
!     if (NILP (current_buffer->buffer_file_type))
!       {
! 	int reduced_size
! 	  = inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
! 	ZV -= reduced_size;
! 	Z -= reduced_size;
! 	GPT -= reduced_size;
! 	GAP_SIZE += reduced_size;
! 	inserted -= reduced_size;
!       }
!   }
  #endif /* DOS_NT */
  
    if (inserted > 0)
--- 3331,3347 ----
  
  #ifdef DOS_NT
    /* Demacs 1.1.1 91/10/16 HIRANO Satoshi, MW July 1993 */
!   /* Remove LFs from CR-LFs if the file is deemed to be a text file.  */
!   if (crlf_conversion_required)
!     {
!       int reduced_size
! 	= inserted - crlf_to_lf (inserted, &FETCH_CHAR (point - 1) + 1);
!       ZV -= reduced_size;
!       Z -= reduced_size;
!       GPT -= reduced_size;
!       GAP_SIZE += reduced_size;
!       inserted -= reduced_size;
!     }
  #endif /* DOS_NT */
  
    if (inserted > 0)
***************
*** 3500,3506 ****
      desc = open (fn, O_WRONLY);
  #endif /* not DOS_NT */
  
!   if (desc < 0)
  #ifdef VMS
      if (auto_saving)    /* Overwrite any previous version of autosave file */
        {
--- 3578,3584 ----
      desc = open (fn, O_WRONLY);
  #endif /* not DOS_NT */
  
!   if (desc < 0 && (NILP (append) || errno == ENOENT))
  #ifdef VMS
      if (auto_saving)    /* Overwrite any previous version of autosave file */
        {
diff -c pretest/src/firstfile.c.null pretest/src/firstfile.c
*** pretest/src/firstfile.c.null	Tue Jul 22 15:14:41 1997
--- pretest/src/firstfile.c	Mon Jul 14 14:11:54 1997
***************
*** 0 ****
--- 1,36 ----
+ /* Mark beginning of data space to dump as pure, for GNU Emacs.
+    Copyright (C) 1985 Free Software Foundation, Inc.
+ 
+ This file is part of GNU Emacs.
+ 
+ GNU Emacs is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+ 
+ GNU Emacs is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+ 
+ You should have received a copy of the GNU General Public License
+ along with GNU Emacs; see the file COPYING.  If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.  */
+ 
+ 
+ #include <config.h>
+ 
+ #ifdef WINDOWSNT
+ /* See comments in lastfile.c.  */
+ char my_begdata[] = "Beginning of Emacs initialized data";
+ 
+ /* The MSVC linker seems to segregate static vs public globals.  */
+ char my_begbss[1];
+ static char _my_begbss[1];
+ char * my_begbss_static = _my_begbss;
+ 
+ /* Add a dummy reference to ensure emacs.obj is linked in.  */
+ extern int initialized;
+ static int * dummy = &initialized;
+ #endif
diff -c pretest/src/keyboard.c.orig pretest/src/keyboard.c
*** pretest/src/keyboard.c.orig	Tue Jul 16 23:22:12 1996
--- pretest/src/keyboard.c	Mon Jul 14 14:11:56 1997
***************
*** 440,445 ****
--- 440,448 ----
  Lisp_Object Qfunction_key;
  Lisp_Object Qmouse_click;
  Lisp_Object Qtimer_event;
+ #ifdef WINDOWSNT
+ Lisp_Object Qmouse_wheel;
+ #endif
  /* Lisp_Object Qmouse_movement; - also an event header */
  
  /* Properties of event headers.  */
***************
*** 2535,2540 ****
--- 2538,2565 ----
      }
  }
  
+ /* Discard any mouse events in the event buffer by setting them to
+    no_event.  */
+ void
+ eat_mouse_events ()
+ {
+   struct input_event *sp;
+   for (sp = kbd_fetch_ptr; sp != kbd_store_ptr; sp++)
+     {
+       if (sp == kbd_buffer + KBD_BUFFER_SIZE)
+ 	sp = kbd_buffer;
+ 
+       if (sp->kind == mouse_click ||
+ #ifdef WINDOWSNT
+ 	  sp->kind == win32_scroll_bar_click ||
+ #endif
+ 	  sp->kind == scroll_bar_click)
+ 	{
+ 	  sp->kind = no_event;
+ 	}
+     }
+ }
+ 
  /* Read one event from the event buffer, waiting if necessary.
     The value is a Lisp object representing the event.
     The value is nil for an event that should be ignored,
***************
*** 2707,2712 ****
--- 2732,2739 ----
  	 (They shouldn't otherwise be found in the buffer,
  	 but on some machines it appears they do show up
  	 even without MULTI_KBOARD.)  */
+       /* The Windows NT version now uses no_event to delete extraneous
+          mouse events during a popup-menu call.  */
        else if (event->kind == no_event)
  	kbd_fetch_ptr = event + 1;
  
***************
*** 3189,3194 ****
--- 3216,3224 ----
  static Lisp_Object accent_key_syms;
  static Lisp_Object func_key_syms;
  static Lisp_Object mouse_syms;
+ #ifdef WINDOWSNT
+ static Lisp_Object mouse_wheel_syms;
+ #endif
  
  /* This is a list of keysym codes for special "accent" characters.
     It parallels lispy_accent_keys.  */
***************
*** 3550,3555 ****
--- 3580,3592 ----
    "mouse-1", "mouse-2", "mouse-3", "mouse-4", "mouse-5"
  };
  
+ #ifdef WINDOWSNT
+ static char *lispy_mouse_wheel_names[] = 
+ {
+   "mouse-wheel"
+ };
+ #endif /* WINDOWSNT */
+ 
  /* Scroll bar parts.  */
  Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
  Lisp_Object Qup, Qdown;
***************
*** 3960,3965 ****
--- 3997,4063 ----
  			       Qnil));
  	}
        }
+     case mouse_wheel:
+       {
+       int part;
+       FRAME_PTR f = XFRAME (event->frame_or_window);
+       Lisp_Object window;
+       Lisp_Object posn;
+       int row, column;
+ 
+       /* Ignore mouse events that were made on frame that
+          have been deleted.  */
+       if (! FRAME_LIVE_P (f))
+         return Qnil;
+       pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+                              &column, &row, NULL, 1);
+       window = window_from_coordinates (f, column, row, &part);
+ 
+       if (!WINDOWP (window))
+         {
+           window = event->frame_or_window;
+           posn = Qnil;
+         }
+       else
+         {
+           int pixcolumn, pixrow;
+           column -= XINT (XWINDOW (window)->left);
+           row -= XINT (XWINDOW (window)->top);
+           glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
+           XSETINT (event->x, pixcolumn);
+           XSETINT (event->y, pixrow);
+ 
+           if (part == 1)
+             posn = Qmode_line;
+           else if (part == 2)
+             posn = Qvertical_line;
+           else
+             XSETINT (posn,
+                      buffer_posn_from_coords (XWINDOW (window),
+                                               column, row));
+         }
+ 
+       {
+         Lisp_Object head, position;
+ 
+         position
+           = Fcons (window,
+                    Fcons (posn,
+                           Fcons (Fcons (event->x, event->y),
+                                  Fcons (make_number (event->timestamp),
+                                         Qnil))));
+ 
+         head = modify_event_symbol (0, event->modifiers,
+                                     Qmouse_wheel, Qnil,
+                                     lispy_mouse_wheel_names,
+                                     &mouse_wheel_syms, 1);
+         return Fcons (head,
+                       Fcons (position,
+                              Fcons (make_number (event->code),
+                                     Qnil)));
+ 
+       }
+       }
  #endif
  
  #endif /* HAVE_MOUSE */
***************
*** 7537,7543 ****
    stop_polling ();
  #endif
  
! #ifndef MSDOS
    /* this causes startup screen to be restored and messes with the mouse */
    reset_sys_modes ();
  #endif
--- 7635,7641 ----
    stop_polling ();
  #endif
  
! #ifndef DOS_NT
    /* this causes startup screen to be restored and messes with the mouse */
    reset_sys_modes ();
  #endif
***************
*** 7576,7582 ****
      /* Don't let this value be out of range.  */
      quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
  
! #ifndef MSDOS
    init_sys_modes ();
  #endif
  
--- 7674,7680 ----
      /* Don't let this value be out of range.  */
      quit_char = XINT (quit) & (meta_key ? 0377 : 0177);
  
! #ifndef DOS_NT
    init_sys_modes ();
  #endif
  
***************
*** 7804,7809 ****
--- 7902,7911 ----
    staticpro (&Qmouse_click);
    Qtimer_event = intern ("timer-event");
    staticpro (&Qtimer_event);
+ #ifdef WINDOWSNT
+   Qmouse_wheel = intern ("mouse-wheel");
+   staticpro (&Qmouse_wheel);
+ #endif
  
    Qmenu_enable = intern ("menu-enable");
    staticpro (&Qmenu_enable);
***************
*** 7895,7900 ****
--- 7997,8007 ----
  
    mouse_syms = Qnil;
    staticpro (&mouse_syms);
+ 
+ #ifdef WINDOWSNT
+   mouse_wheel_syms = Qnil;
+   staticpro (&mouse_wheel_syms);
+ #endif
  
    unread_switch_frame = Qnil;
    staticpro (&unread_switch_frame);
diff -c pretest/src/lastfile.c.orig pretest/src/lastfile.c
*** pretest/src/lastfile.c.orig	Tue Apr  9 23:14:24 1996
--- pretest/src/lastfile.c	Mon Jul 14 14:11:56 1997
***************
*** 19,24 ****
--- 19,26 ----
  Boston, MA 02111-1307, USA.  */
  
  
+ #include <config.h>
+ 
  /* How this works:
  
   Fdump_emacs dumps everything up to my_edata as text space (pure).
***************
*** 38,40 ****
--- 40,49 ----
  
  char my_edata[] = "End of Emacs initialized data";
  
+ #ifdef WINDOWSNT
+ /* Help unexec locate the end of the .bss area used by Emacs (which
+    isn't always a separate section in NT executables).  */
+ char my_endbss[1];
+ static char _my_endbss[1];
+ char * my_endbss_static = _my_endbss;
+ #endif
diff -c pretest/src/lisp.h.orig pretest/src/lisp.h
*** pretest/src/lisp.h.orig	Tue Jul 16 06:06:22 1996
--- pretest/src/lisp.h	Fri Jul 18 14:35:30 1997
***************
*** 1664,1669 ****
--- 1664,1670 ----
  extern Lisp_Object Fcommand_execute (), Finput_pending_p ();
  extern Lisp_Object menu_bar_items ();
  extern Lisp_Object Qvertical_scroll_bar;
+ extern void eat_mouse_events ();
  #ifdef MULTI_KBOARD
  extern void delete_kboard ();
  #endif
***************
*** 1793,1798 ****
--- 1794,1800 ----
  extern char *getenv (), *ctime (), *getwd ();
  extern long *xmalloc (), *xrealloc ();
  extern void xfree ();
+ extern char *xstrdup ();
  
  extern char *egetenv ();
   
diff -c pretest/src/makefile.nt.orig pretest/src/makefile.nt
*** pretest/src/makefile.nt.orig	Sat Jul 20 19:06:12 1996
--- pretest/src/makefile.nt	Mon Jul 14 14:11:56 1997
***************
*** 36,41 ****
--- 36,42 ----
  
  EMACS           = $(BLD)\emacs.exe
  TEMACS          = $(BLD)\temacs.exe
+ TLIB0           = $(BLD)\temacs0.lib
  TLIB1           = $(BLD)\temacs1.lib
  TLIB2           = $(BLD)\temacs2.lib
  !IFDEF NTGUI
***************
*** 43,49 ****
  !ELSE
  TLIBW32		=
  !ENDIF
! TOBJ            = $(BLD)\emacs.obj
  !if $(MSVCNT11)
  TRES		= $(BLD)\emacs.res
  !else
--- 44,50 ----
  !ELSE
  TLIBW32		=
  !ENDIF
! TOBJ            = $(BLD)\firstfile.obj
  !if $(MSVCNT11)
  TRES		= $(BLD)\emacs.res
  !else
***************
*** 53,64 ****
  
  # see comments in allocate_heap in ntheap.c before changing any of the
  # -stack, -heap, or -base settings.
! LINK_FLAGS      = $(ARCH_LDFLAGS) -stack:0x00800000 -heap:0x00100000 -base:0x01000000 -debug:full -debugtype:cv -machine:$(ARCH) -subsystem:$(SUBSYSTEM) -entry:_start -map:$(BLD)\temacs.map
  
  #
  # Split up the objects into two sets so that we don't run out of
  # command line space when we link them into a library.
  #
  OBJ1 =  $(BLD)\abbrev.obj       \
  	$(BLD)\alloc.obj        \
  	$(BLD)\alloca.obj       \
--- 54,74 ----
  
  # see comments in allocate_heap in ntheap.c before changing any of the
  # -stack, -heap, or -base settings.
! !if "$(BUILD_TYPE)" == "spd"
! LINK_FLAGS      = $(ARCH_LDFLAGS) -stack:0x00800000 -heap:0x00100000 -base:0x01000000 -debug:full -pdb:$(BLD)\temacs.pdb -machine:$(ARCH) -subsystem:$(SUBSYSTEM) -entry:_start -map:$(BLD)\temacs.map
! !else
! LINK_FLAGS      = $(ARCH_LDFLAGS) -stack:0x00800000 -heap:0x00100000 -base:0x01000000 -debug:full -pdb:$(BLD)\temacs.pdb -machine:$(ARCH) -subsystem:$(SUBSYSTEM) -entry:_start -map:$(BLD)\temacs.map
! !endif
  
  #
  # Split up the objects into two sets so that we don't run out of
  # command line space when we link them into a library.
  #
+ # Put emacs.obj in a separate lib, since we need to have firstfile.obj
+ # as the "main" object file when linking.
+ #
+ OBJ0 =  $(BLD)\emacs.obj
+ 
  OBJ1 =  $(BLD)\abbrev.obj       \
  	$(BLD)\alloc.obj        \
  	$(BLD)\alloca.obj       \
***************
*** 128,134 ****
  	   $(BLD)\w32menu.obj	\
  	   $(BLD)\w32reg.obj
  
! LIBS =  $(TLIB1)	\
  	$(TLIB2)	\
  !IFDEF NTGUI
  	$(TLIBW32)      \
--- 138,145 ----
  	   $(BLD)\w32menu.obj	\
  	   $(BLD)\w32reg.obj
  
! LIBS =  $(TLIB0)	\
! 	$(TLIB1)	\
  	$(TLIB2)	\
  !IFDEF NTGUI
  	$(TLIBW32)      \
***************
*** 174,186 ****
  $(EMACS):       $(PREPARED_HEADERS) $(DOC) $(TEMACS)
  		cd $(BLD)
  		temacs.exe -batch -l loadup dump
  		cd ..\..
  
  #
  # The undumped executable
  #
  temacs:         $(BLD) $(TEMACS)
! $(TEMACS):      $(TLIB1) $(TLIB2) $(TLIBW32) $(TLASTLIB) $(TOBJ) $(TRES)
  		$(LINK) -out:$(TEMACS) $(LINK_FLAGS) $(TOBJ) $(TRES) $(LIBS)
  
  #
--- 185,198 ----
  $(EMACS):       $(PREPARED_HEADERS) $(DOC) $(TEMACS)
  		cd $(BLD)
  		temacs.exe -batch -l loadup dump
+ 		copy temacs.map emacs.map
  		cd ..\..
  
  #
  # The undumped executable
  #
  temacs:         $(BLD) $(TEMACS)
! $(TEMACS):      $(TLIB0) $(TLIB1) $(TLIB2) $(TLIBW32) $(TLASTLIB) $(TOBJ) $(TRES)
  		$(LINK) -out:$(TEMACS) $(LINK_FLAGS) $(TOBJ) $(TRES) $(LIBS)
  
  #
***************
*** 197,202 ****
--- 209,216 ----
  # Build the library.  Split up the build into two phases...otherwise we 
  # run out of command line space.
  #
+ $(TLIB0):       $(OBJ0)
+ 		@- $(AR) -out:$@ $**
  $(TLIB1):       $(OBJ1)
  		@- $(AR) -out:$@ $**
  $(TLIB2):	$(OBJ2)
***************
*** 301,312 ****
--- 315,332 ----
  
  $(BLD)\bytecode.obj : \
  	$(SRC)\bytecode.c \
+ 	$(EMACS_ROOT)\src\s\windowsnt.h \
+ 	$(EMACS_ROOT)\src\m\intel386.h \
+ 	$(EMACS_ROOT)\src\config.h \
  	$(SRC)\lisp.h \
  	$(SRC)\buffer.h \
  	$(SRC)\syntax.h
  
  $(BLD)\callint.obj : \
  	$(SRC)\callint.c \
+ 	$(EMACS_ROOT)\src\s\windowsnt.h \
+ 	$(EMACS_ROOT)\src\m\intel386.h \
+ 	$(EMACS_ROOT)\src\config.h \
  	$(SRC)\lisp.h \
  	$(SRC)\buffer.h \
  	$(SRC)\commands.h \
***************
*** 529,534 ****
--- 549,560 ----
  	$(SRC)\m\intel386.h \
  	$(SRC)\config.h
  
+ $(BLD)\firstfile.obj : \
+ 	$(SRC)\firstfile.c \
+ 	$(EMACS_ROOT)\src\s\windowsnt.h \
+ 	$(EMACS_ROOT)\src\m\intel386.h \
+ 	$(EMACS_ROOT)\src\config.h
+ 
  $(BLD)\floatfns.obj : \
  	$(SRC)\floatfns.c \
  	$(EMACS_ROOT)\src\s\windowsnt.h \
***************
*** 672,678 ****
  	$(SRC)\blockinput.h
  
  $(BLD)\lastfile.obj : \
! 	$(SRC)\lastfile.c
  
  $(BLD)\lread.obj : \
  	$(SRC)\lread.c \
--- 698,707 ----
  	$(SRC)\blockinput.h
  
  $(BLD)\lastfile.obj : \
! 	$(SRC)\lastfile.c \
! 	$(EMACS_ROOT)\src\s\windowsnt.h \
! 	$(EMACS_ROOT)\src\m\intel386.h \
! 	$(EMACS_ROOT)\src\config.h
  
  $(BLD)\lread.obj : \
  	$(SRC)\lread.c \
***************
*** 740,746 ****
  
  $(BLD)\ntheap.obj : \
  	$(SRC)\ntheap.c \
! 	$(SRC)\ntheap.h
  
  $(BLD)\ntinevt.obj : \
  	$(SRC)\ntinevt.c \
--- 769,778 ----
  
  $(BLD)\ntheap.obj : \
  	$(SRC)\ntheap.c \
! 	$(SRC)\ntheap.h \
! 	$(SRC)\s\windowsnt.h \
! 	$(SRC)\m\intel386.h \
! 	$(SRC)\config.h
  
  $(BLD)\ntinevt.obj : \
  	$(SRC)\ntinevt.c \
***************
*** 759,764 ****
--- 791,797 ----
  	$(SRC)\config.h \
  	$(SRC)\lisp.h \
  	$(SRC)\nt.h \
+ 	$(SRC)\ntheap.h \
  	$(SRC)\vmstime.h \
  	$(SRC)\systime.h
  
***************
*** 981,986 ****
--- 1014,1022 ----
  
  $(BLD)\unexnt.obj : \
  	$(SRC)\unexnt.c \
+ 	$(EMACS_ROOT)\src\s\windowsnt.h \
+ 	$(EMACS_ROOT)\src\m\intel386.h \
+ 	$(EMACS_ROOT)\src\config.h \
  	$(SRC)\ntheap.h
  
  $(BLD)\vm-limit.obj : \
***************
*** 1124,1127 ****
--- 1160,1174 ----
  	$(SRC)\lisp.h \
  	$(SRC)\w32term.h \
  	$(SRC)\win32.h \
+ 	$(SRC)\blockinput.h
+ 
+ $(BLD)\w32xfns.obj: \
+ 	$(EMACS_ROOT)\src\s\windowsnt.h \
+ 	$(EMACS_ROOT)\src\m\intel386.h \
+ 	$(EMACS_ROOT)\src\config.h \
+ 	$(SRC)\w32xfns.c \
+ 	$(SRC)\lisp.h \
+ 	$(SRC)\w32term.h \
+ 	$(SRC)\win32.h \
+ 	$(SRC)\frame.h \
  	$(SRC)\blockinput.h
diff -c pretest/src/nt.c.orig pretest/src/nt.c
*** pretest/src/nt.c.orig	Sun Jul  7 02:42:57 1996
--- pretest/src/nt.c	Mon Jul 21 15:56:11 1997
***************
*** 22,27 ****
--- 22,28 ----
  */
  
  
+ #include <stddef.h> /* for offsetof */
  #include <stdlib.h>
  #include <stdio.h>
  #include <io.h>
***************
*** 78,83 ****
--- 79,90 ----
  #include "nt.h"
  #include "ndir.h"
  #include "ntheap.h"
+   
+ 
+ extern Lisp_Object Vwin32_downcase_file_names;
+ extern Lisp_Object Vwin32_generate_fake_inodes;
+ extern Lisp_Object Vwin32_get_true_file_attributes;
+ 
  
  /* Get the current working directory.  */
  char *
***************
*** 113,217 ****
    return i;
  }
  
- /* Emulate the Unix directory procedures opendir, closedir, 
-    and readdir.  We can't use the procedures supplied in sysdep.c,
-    so we provide them here.  */
- 
- struct direct dir_static;       /* simulated directory contents */
- static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
- static int    dir_is_fat;
- static char   dir_pathname[MAXPATHLEN+1];
- 
- extern Lisp_Object Vwin32_downcase_file_names;
- 
- DIR *
- opendir (char *filename)
- {
-   DIR *dirp;
- 
-   /* 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;
- 
-   dirp->dd_fd = 0;
-   dirp->dd_loc = 0;
-   dirp->dd_size = 0;
- 
-   strncpy (dir_pathname, filename, MAXPATHLEN);
-   dir_pathname[MAXPATHLEN] = '\0';
-   dir_is_fat = is_fat_volume (filename, NULL);
- 
-   return dirp;
- }
- 
- void
- closedir (DIR *dirp)
- {
-   /* If we have a find-handle open, close it.  */
-   if (dir_find_handle != INVALID_HANDLE_VALUE)
-     {
-       FindClose (dir_find_handle);
-       dir_find_handle = INVALID_HANDLE_VALUE;
-     }
-   xfree ((char *) dirp);
- }
- 
- struct direct *
- readdir (DIR *dirp)
- {
-   WIN32_FIND_DATA find_data;
-   
-   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
-   if (dir_find_handle == INVALID_HANDLE_VALUE)
-     {
-       char filename[MAXNAMLEN + 3];
-       int ln;
- 
-       strcpy (filename, dir_pathname);
-       ln = strlen (filename) - 1;
-       if (!IS_DIRECTORY_SEP (filename[ln]))
- 	strcat (filename, "\\");
-       strcat (filename, "*");
- 
-       dir_find_handle = FindFirstFile (filename, &find_data);
- 
-       if (dir_find_handle == INVALID_HANDLE_VALUE)
- 	return NULL;
-     }
-   else
-     {
-       if (!FindNextFile (dir_find_handle, &find_data))
- 	return NULL;
-     }
-   
-   /* Emacs never uses this value, so don't bother making it match
-      value returned by stat().  */
-   dir_static.d_ino = 1;
-   
-   dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
-     dir_static.d_namlen - dir_static.d_namlen % 4;
-   
-   dir_static.d_namlen = strlen (find_data.cFileName);
-   strcpy (dir_static.d_name, find_data.cFileName);
-   if (dir_is_fat)
-     _strlwr (dir_static.d_name);
-   else if (!NILP (Vwin32_downcase_file_names))
-     {
-       register char *p;
-       for (p = dir_static.d_name; *p; p++)
- 	if (*p >= 'a' && *p <= 'z')
- 	  break;
-       if (!*p)
- 	_strlwr (dir_static.d_name);
-     }
-   
-   return &dir_static;
- }
- 
  /* Emulate getpwuid, getpwnam and others.  */
  
  #define PASSWD_FIELD_SIZE 256
--- 120,125 ----
***************
*** 366,372 ****
    if (getenv ("HOME") == NULL)
      putenv ("HOME=c:/");
    if (getenv ("SHELL") == NULL)
!     putenv ((GetVersion () & 0x80000000) ? "SHELL=command" : "SHELL=cmd");
  
    /* Set dir and shell from environment variables. */
    strcpy (the_passwd.pw_dir, getenv ("HOME"));
--- 274,280 ----
    if (getenv ("HOME") == NULL)
      putenv ("HOME=c:/");
    if (getenv ("SHELL") == NULL)
!     putenv (os_subtype == OS_WIN95 ? "SHELL=command" : "SHELL=cmd");
  
    /* Set dir and shell from environment variables. */
    strcpy (the_passwd.pw_dir, getenv ("HOME"));
***************
*** 389,394 ****
--- 297,303 ----
    srand (seed);
  }
  
+ 
  /* Normalize filename by converting all path separators to
     the specified separator.  Also conditionally convert upper
     case path name components to lower case.  */
***************
*** 495,500 ****
--- 404,521 ----
    return np - startp;
  }
  
+ /* Parse the root part of file name, if present.  Return length and
+     optionally store pointer to char after root.  */
+ static int
+ parse_root (char * name, char ** pPath)
+ {
+   char * start = name;
+ 
+   if (name == NULL)
+     return 0;
+ 
+   /* find the root name of the volume if given */
+   if (isalpha (name[0]) && name[1] == ':')
+     {
+       /* skip past drive specifier */
+       name += 2;
+       if (IS_DIRECTORY_SEP (name[0]))
+ 	name++;
+     }
+   else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
+     {
+       int slashes = 2;
+       name += 2;
+       do
+         {
+ 	  if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
+ 	    break;
+ 	  name++;
+ 	}
+       while ( *name );
+       if (IS_DIRECTORY_SEP (name[0]))
+ 	name++;
+     }
+ 
+   if (pPath)
+     *pPath = name;
+ 
+   return name - start;
+ }
+ 
+ /* Get long base name for name; name is assumed to be absolute.  */
+ static int
+ get_long_basename (char * name, char * buf, int size)
+ {
+   WIN32_FIND_DATA find_data;
+   HANDLE dir_handle;
+   int len = 0;
+ 
+   dir_handle = FindFirstFile (name, &find_data);
+   if (dir_handle != INVALID_HANDLE_VALUE)
+     {
+       if ((len = strlen (find_data.cFileName)) < size)
+ 	memcpy (buf, find_data.cFileName, len + 1);
+       else
+ 	len = 0;
+       FindClose (dir_handle);
+     }
+   return len;
+ }
+ 
+ /* Get long name for file, if possible (assumed to be absolute).  */
+ BOOL
+ win32_get_long_filename (char * name, char * buf, int size)
+ {
+   char * o = buf;
+   char * p;
+   char * q;
+   char full[ MAX_PATH ];
+   int len;
+ 
+   len = strlen (name);
+   if (len >= MAX_PATH)
+     return FALSE;
+ 
+   /* Use local copy for destructive modification.  */
+   memcpy (full, name, len+1);
+   unixtodos_filename (full);
+ 
+   /* Copy root part verbatim.  */
+   len = parse_root (full, &p);
+   memcpy (o, full, len);
+   o += len;
+   size -= len;
+ 
+   do
+     {
+       q = p;
+       p = strchr (q, '\\');
+       if (p) *p = '\0';
+       len = get_long_basename (full, o, size);
+       if (len > 0)
+ 	{
+ 	  o += len;
+ 	  size -= len;
+ 	  if (p != NULL)
+ 	    {
+ 	      *p++ = '\\';
+ 	      if (size < 2)
+ 		return FALSE;
+ 	      *o++ = '\\';
+ 	      size--;
+ 	      *o = '\0';
+ 	    }
+ 	}
+       else
+ 	return FALSE;
+     }
+   while (p != NULL && *p);
+ 
+   return TRUE;
+ }
+ 
+ 
  /* Routines that are no-ops on NT but are defined to get Emacs to compile.  */
  
  int 
***************
*** 599,604 ****
--- 620,626 ----
        "emacs_dir",
        "EMACSLOADPATH",
        "SHELL",
+       "CMDPROXY",
        "EMACSDATA",
        "EMACSPATH",
        "EMACSLOCKDIR",
***************
*** 633,638 ****
--- 655,679 ----
        }
    }
  
+   /* Another special case: on NT, the PATH variable is actually named
+      "Path" although cmd.exe (perhaps NT itself) arranges for
+      environment variable lookup and setting to be case insensitive.
+      However, Emacs assumes a fully case sensitive environment, so we
+      need to change "Path" to "PATH" to match the expectations of
+      various elisp packages.  We do this by the sneaky method of
+      modifying the string in the C runtime environ entry.
+ 
+      The same applies to COMSPEC.  */
+   {
+     char ** envp;
+ 
+     for (envp = environ; *envp; envp++)
+       if (_strnicmp (*envp, "PATH=", 5) == 0)
+ 	memcpy (*envp, "PATH=", 5);
+       else if (_strnicmp (*envp, "COMSPEC=", 8) == 0)
+ 	memcpy (*envp, "COMSPEC=", 8);
+   }
+ 
    init_user_info ();
  }
  
***************
*** 688,694 ****
    /* Let oem be "*" until we figure out how to decode the OEM field.  */
    oem = "*";
  
!   os = (GetVersion () & 0x80000000) ? "win95" : "nt";
  
    sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
  	   get_nt_major_version (), get_nt_minor_version ());
--- 729,735 ----
    /* Let oem be "*" until we figure out how to decode the OEM field.  */
    oem = "*";
  
!   os = (os_subtype == OS_WIN95) ? "win95" : "nt";
  
    sprintf (configuration_buffer, "%s-%s-%s%d.%d", arch, oem, os,
  	   get_nt_major_version (), get_nt_minor_version ());
***************
*** 736,758 ****
    Sleep (seconds * 1000);
  }
  
! /* Internal MSVC data and functions for low-level descriptor munging */
! #if (_MSC_VER == 900)
! extern char _osfile[];
! #endif
  extern int __cdecl _set_osfhnd (int fd, long h);
  extern int __cdecl _free_osfhnd (int fd);
  
  /* parallel array of private info on file handles */
  filedesc fd_info [ MAXDESC ];
  
! static struct {
    DWORD     serialnum;
    DWORD     maxcomp;
    DWORD     flags;
!   char      name[32];
!   char      type[32];
! } volume_info;
  
  /* Get information on the volume where name is held; set path pointer to
     start of pathname in name (past UNC header\volume header if present).  */
--- 777,935 ----
    Sleep (seconds * 1000);
  }
  
! /* Internal MSVC functions for low-level descriptor munging */
  extern int __cdecl _set_osfhnd (int fd, long h);
  extern int __cdecl _free_osfhnd (int fd);
  
  /* parallel array of private info on file handles */
  filedesc fd_info [ MAXDESC ];
  
! typedef struct volume_info_data {
!   struct volume_info_data * next;
! 
!   /* time when info was obtained */
!   DWORD     timestamp;
! 
!   /* actual volume info */
!   char *    root_dir;
    DWORD     serialnum;
    DWORD     maxcomp;
    DWORD     flags;
!   char *    name;
!   char *    type;
! } volume_info_data;
! 
! /* Global referenced by various functions.  */
! static volume_info_data volume_info;
! 
! /* Vector to indicate which drives are local and fixed (for which cached
!    data never expires).  */
! static BOOL fixed_drives[26];
! 
! /* Consider cached volume information to be stale if older than 10s,
!    at least for non-local drives.  Info for fixed drives is never stale.  */
! #define DRIVE_INDEX( c ) ( (c) <= 'Z' ? (c) - 'A' : (c) - 'a' )
! #define VOLINFO_STILL_VALID( root_dir, info )		\
!   ( ( isalpha (root_dir[0]) &&				\
!       fixed_drives[ DRIVE_INDEX (root_dir[0]) ] )	\
!     || GetTickCount () - info->timestamp < 10000 )
! 
! /* Cache support functions.  */
! 
! /* Simple linked list with linear search is sufficient.  */
! static volume_info_data *volume_cache = NULL;
! 
! static volume_info_data *
! lookup_volume_info (char * root_dir)
! {
!   volume_info_data * info;
! 
!   for (info = volume_cache; info; info = info->next)
!     if (stricmp (info->root_dir, root_dir) == 0)
!       break;
!   return info;
! }
! 
! static void
! add_volume_info (char * root_dir, volume_info_data * info)
! {
!   info->root_dir = xstrdup (root_dir);
!   info->next = volume_cache;
!   volume_cache = info;
! }
! 
! 
! /* Wrapper for GetVolumeInformation, which uses caching to avoid
!    performance penalty (~2ms on 486 for local drives, 7.5ms for local
!    cdrom drive, ~5-10ms or more for remote drives on LAN).  */
! volume_info_data *
! GetCachedVolumeInformation (char * root_dir)
! {
!   volume_info_data * info;
!   char default_root[ MAX_PATH ];
! 
!   /* NULL for root_dir means use root from current directory.  */
!   if (root_dir == NULL)
!     {
!       if (GetCurrentDirectory (MAX_PATH, default_root) == 0)
! 	return NULL;
!       parse_root (default_root, &root_dir);
!       *root_dir = 0;
!       root_dir = default_root;
!     }
! 
!   /* Local fixed drives can be cached permanently.  Removable drives
!      cannot be cached permanently, since the volume name and serial
!      number (if nothing else) can change.  Remote drives should be
!      treated as if they are removable, since there is no sure way to
!      tell whether they are or not.  Also, the UNC association of drive
!      letters mapped to remote volumes can be changed at any time (even
!      by other processes) without notice.
!    
!      As a compromise, so we can benefit from caching info for remote
!      volumes, we use a simple expiry mechanism to invalidate cache
!      entries that are more than ten seconds old.  */
! 
! #if 0
!   /* No point doing this, because WNetGetConnection is even slower than
!      GetVolumeInformation, consistently taking ~50ms on a 486 (FWIW,
!      GetDriveType is about the only call of this type which does not
!      involve network access, and so is extremely quick).  */
! 
!   /* Map drive letter to UNC if remote. */
!   if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
!     {
!       char remote_name[ 256 ];
!       char drive[3] = { root_dir[0], ':' };
! 
!       if (WNetGetConnection (drive, remote_name, sizeof (remote_name))
! 	  == NO_ERROR)
! 	/* do something */ ;
!     }
! #endif
! 
!   info = lookup_volume_info (root_dir);
! 
!   if (info == NULL || ! VOLINFO_STILL_VALID (root_dir, info))
!   {
!     char  name[ 256 ];
!     DWORD serialnum;
!     DWORD maxcomp;
!     DWORD flags;
!     char  type[ 256 ];
! 
!     /* Info is not cached, or is stale. */
!     if (!GetVolumeInformation (root_dir,
! 			       name, sizeof (name),
! 			       &serialnum,
! 			       &maxcomp,
! 			       &flags,
! 			       type, sizeof (type)))
!       return NULL;
! 
!     /* Cache the volume information for future use, overwriting existing
!        entry if present.  */
!     if (info == NULL)
!       {
! 	info = (volume_info_data *) xmalloc (sizeof (volume_info_data));
! 	add_volume_info (root_dir, info);
!       }
!     else
!       {
! 	free (info->name);
! 	free (info->type);
!       }
! 
!     info->name = xstrdup (name);
!     info->serialnum = serialnum;
!     info->maxcomp = maxcomp;
!     info->flags = flags;
!     info->type = xstrdup (type);
!     info->timestamp = GetTickCount ();
!   }
! 
!   return info;
! }
  
  /* Get information on the volume where name is held; set path pointer to
     start of pathname in name (past UNC header\volume header if present).  */
***************
*** 761,766 ****
--- 938,944 ----
  {
    char temp[MAX_PATH];
    char *rootname = NULL;  /* default to current volume */
+   volume_info_data * info;
  
    if (name == NULL)
      return FALSE;
***************
*** 794,806 ****
    if (pPath)
      *pPath = name;
      
!   if (GetVolumeInformation (rootname,
! 			    volume_info.name, 32,
! 			    &volume_info.serialnum,
! 			    &volume_info.maxcomp,
! 			    &volume_info.flags,
! 			    volume_info.type, 32))
      {
        return TRUE;
      }
    return FALSE;
--- 972,982 ----
    if (pPath)
      *pPath = name;
      
!   info = GetCachedVolumeInformation (rootname);
!   if (info != NULL)
      {
+       /* Set global referenced by other functions.  */
+       volume_info = *info;
        return TRUE;
      }
    return FALSE;
***************
*** 913,918 ****
--- 1089,1190 ----
    return shortname;
  }
  
+ /* Emulate the Unix directory procedures opendir, closedir, 
+    and readdir.  We can't use the procedures supplied in sysdep.c,
+    so we provide them here.  */
+ 
+ struct direct dir_static;       /* simulated directory contents */
+ static HANDLE dir_find_handle = INVALID_HANDLE_VALUE;
+ static int    dir_is_fat;
+ static char   dir_pathname[MAXPATHLEN+1];
+ static WIN32_FIND_DATA dir_find_data;
+ 
+ DIR *
+ opendir (char *filename)
+ {
+   DIR *dirp;
+ 
+   /* 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;
+ 
+   dirp->dd_fd = 0;
+   dirp->dd_loc = 0;
+   dirp->dd_size = 0;
+ 
+   strncpy (dir_pathname, map_win32_filename (filename, NULL), MAXPATHLEN);
+   dir_pathname[MAXPATHLEN] = '\0';
+   dir_is_fat = is_fat_volume (filename, NULL);
+ 
+   return dirp;
+ }
+ 
+ void
+ closedir (DIR *dirp)
+ {
+   /* If we have a find-handle open, close it.  */
+   if (dir_find_handle != INVALID_HANDLE_VALUE)
+     {
+       FindClose (dir_find_handle);
+       dir_find_handle = INVALID_HANDLE_VALUE;
+     }
+   xfree ((char *) dirp);
+ }
+ 
+ struct direct *
+ readdir (DIR *dirp)
+ {
+   /* If we aren't dir_finding, do a find-first, otherwise do a find-next. */
+   if (dir_find_handle == INVALID_HANDLE_VALUE)
+     {
+       char filename[MAXNAMLEN + 3];
+       int ln;
+ 
+       strcpy (filename, dir_pathname);
+       ln = strlen (filename) - 1;
+       if (!IS_DIRECTORY_SEP (filename[ln]))
+ 	strcat (filename, "\\");
+       strcat (filename, "*");
+ 
+       dir_find_handle = FindFirstFile (filename, &dir_find_data);
+ 
+       if (dir_find_handle == INVALID_HANDLE_VALUE)
+ 	return NULL;
+     }
+   else
+     {
+       if (!FindNextFile (dir_find_handle, &dir_find_data))
+ 	return NULL;
+     }
+   
+   /* Emacs never uses this value, so don't bother making it match
+      value returned by stat().  */
+   dir_static.d_ino = 1;
+   
+   dir_static.d_reclen = sizeof (struct direct) - MAXNAMLEN + 3 +
+     dir_static.d_namlen - dir_static.d_namlen % 4;
+   
+   dir_static.d_namlen = strlen (dir_find_data.cFileName);
+   strcpy (dir_static.d_name, dir_find_data.cFileName);
+   if (dir_is_fat)
+     _strlwr (dir_static.d_name);
+   else if (!NILP (Vwin32_downcase_file_names))
+     {
+       register char *p;
+       for (p = dir_static.d_name; *p; p++)
+ 	if (*p >= 'a' && *p <= 'z')
+ 	  break;
+       if (!*p)
+ 	_strlwr (dir_static.d_name);
+     }
+   
+   return &dir_static;
+ }
+ 
  
  /* Shadow some MSVC runtime functions to map requests for long filenames
     to reasonable short names if necessary.  This was originally added to
***************
*** 984,997 ****
    if (fd < 0)
      return NULL;
  
!   return fdopen (fd, mode_save);
  }
  
  int
! sys_link (const char * path1, const char * path2)
  {
!   errno = EINVAL;
!   return -1;
  }
  
  int
--- 1256,1335 ----
    if (fd < 0)
      return NULL;
  
!   return _fdopen (fd, mode_save);
  }
  
+ /* This only works on NTFS volumes, but is useful to have.  */
  int
! sys_link (const char * old, const char * new)
  {
!   HANDLE fileh;
!   int   result = -1;
!   char oldname[MAX_PATH], newname[MAX_PATH];
! 
!   if (old == NULL || new == NULL)
!     {
!       errno = ENOENT;
!       return -1;
!     }
! 
!   strcpy (oldname, map_win32_filename (old, NULL));
!   strcpy (newname, map_win32_filename (new, NULL));
! 
!   fileh = CreateFile (oldname, 0, 0, NULL, OPEN_EXISTING,
! 		      FILE_FLAG_BACKUP_SEMANTICS, NULL);
!   if (fileh != INVALID_HANDLE_VALUE)
!     {
!       int wlen;
! 
!       /* Confusingly, the "alternate" stream name field does not apply
!          when restoring a hard link, and instead contains the actual
!          stream data for the link (ie. the name of the link to create).
!          The WIN32_STREAM_ID structure before the cStreamName field is
!          the stream header, which is then immediately followed by the
!          stream data.  */
! 
!       struct {
! 	WIN32_STREAM_ID wid;
! 	WCHAR wbuffer[MAX_PATH];	/* extra space for link name */
!       } data;
! 
!       wlen = MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, newname, -1,
! 				  data.wid.cStreamName, MAX_PATH);
!       if (wlen > 0)
! 	{
! 	  LPVOID context = NULL;
! 	  DWORD wbytes = 0;
! 
! 	  data.wid.dwStreamId = BACKUP_LINK;
! 	  data.wid.dwStreamAttributes = 0;
! 	  data.wid.Size.LowPart = wlen * sizeof(WCHAR);
! 	  data.wid.Size.HighPart = 0;
! 	  data.wid.dwStreamNameSize = 0;
! 
! 	  if (BackupWrite (fileh, (LPBYTE)&data,
! 			   offsetof (WIN32_STREAM_ID, cStreamName)
! 			   + data.wid.Size.LowPart,
! 			   &wbytes, FALSE, FALSE, &context)
! 	      && BackupWrite (fileh, NULL, 0, &wbytes, TRUE, FALSE, &context))
! 	    {
! 	      /* succeeded */
! 	      result = 0;
! 	    }
! 	  else
! 	    {
! 	      /* Should try mapping GetLastError to errno; for now just
! 		 indicate a general error (eg. links not supported).  */
! 	      errno = EINVAL;  // perhaps EMLINK?
! 	    }
! 	}
! 
!       CloseHandle (fileh);
!     }
!   else
!     errno = ENOENT;
! 
!   return result;
  }
  
  int
***************
*** 1078,1084 ****
  
    strcpy (temp, map_win32_filename (oldname, NULL));
  
!   if (GetVersion () & 0x80000000)
      {
        char * p;
  
--- 1416,1422 ----
  
    strcpy (temp, map_win32_filename (oldname, NULL));
  
!   if (os_subtype == OS_WIN95)
      {
        char * p;
  
***************
*** 1086,1096 ****
  	p++;
        else
  	p = temp;
-       strcpy (p, "__XXXXXX");
-       sys_mktemp (temp);
        /* Force temp name to require a manufactured 8.3 alias - this
  	 seems to make the second rename work properly. */
!       strcat (temp, ".long");
        if (rename (map_win32_filename (oldname, NULL), temp) < 0)
  	return -1;
      }
--- 1424,1433 ----
  	p++;
        else
  	p = temp;
        /* Force temp name to require a manufactured 8.3 alias - this
  	 seems to make the second rename work properly. */
!       strcpy (p, "_rename_temp.XXXXXX");
!       sys_mktemp (temp);
        if (rename (map_win32_filename (oldname, NULL), temp) < 0)
  	return -1;
      }
***************
*** 1100,1105 ****
--- 1437,1445 ----
       However, don't do this if we are just changing the case of the file
       name - we will end up deleting the file we are trying to rename!  */
    newname = map_win32_filename (newname, NULL);
+ 
+   /* TODO: Use GetInformationByHandle (on NT) to ensure newname and temp
+      do not refer to the same file, eg. through share aliases.  */
    if (stricmp (newname, temp) != 0
        && (attr = GetFileAttributes (newname)) != -1
        && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
***************
*** 1192,1229 ****
  }
  #endif
  
! /*  "PJW" algorithm (see the "Dragon" compiler book). */
  static unsigned
! hashval (const char * str)
  {
    unsigned h = 0;
-   unsigned g;
    while (*str)
      {
        h = (h << 4) + *str++;
!       if ((g = h & 0xf0000000) != 0)
! 	h = (h ^ (g >> 24)) & 0x0fffffff;
      }
    return h;
  }
  
  /* Return the hash value of the canonical pathname, excluding the
     drive/UNC header, to get a hopefully unique inode number. */
! static _ino_t
  generate_inode_val (const char * name)
  {
    char fullname[ MAX_PATH ];
    char * p;
    unsigned hash;
  
!   GetFullPathName (name, sizeof (fullname), fullname, &p);
!   get_volume_info (fullname, &p);
    /* Normal Win32 filesystems are still case insensitive. */
    _strlwr (p);
!   hash = hashval (p);
!   return (_ino_t) (hash ^ (hash >> 16));
  }
  
  /* MSVC stat function can't cope with UNC names and has other bugs, so
     replace it with our own.  This also allows us to calculate consistent
     inode values without hacks in the main Emacs code. */
--- 1532,1580 ----
  }
  #endif
  
! #if 0
! /* No reason to keep this; faking inode values either by hashing or even
!    using the file index from GetInformationByHandle, is not perfect and
!    so by default Emacs doesn't use the inode values on Windows.
!    Instead, we now determine file-truename correctly (except for
!    possible drive aliasing etc).  */
! 
! /*  Modified version of "PJW" algorithm (see the "Dragon" compiler book). */
  static unsigned
! hashval (const unsigned char * str)
  {
    unsigned h = 0;
    while (*str)
      {
        h = (h << 4) + *str++;
!       h ^= (h >> 28);
      }
    return h;
  }
  
  /* Return the hash value of the canonical pathname, excluding the
     drive/UNC header, to get a hopefully unique inode number. */
! static DWORD
  generate_inode_val (const char * name)
  {
    char fullname[ MAX_PATH ];
    char * p;
    unsigned hash;
  
!   /* Get the truly canonical filename, if it exists.  (Note: this
!      doesn't resolve aliasing due to subst commands, or recognise hard
!      links.  */
!   if (!win32_get_long_filename ((char *)name, fullname, MAX_PATH))
!     abort ();
! 
!   parse_root (fullname, &p);
    /* Normal Win32 filesystems are still case insensitive. */
    _strlwr (p);
!   return hashval (p);
  }
  
+ #endif
+ 
  /* MSVC stat function can't cope with UNC names and has other bugs, so
     replace it with our own.  This also allows us to calculate consistent
     inode values without hacks in the main Emacs code. */
***************
*** 1233,1238 ****
--- 1584,1590 ----
    char * name;
    WIN32_FIND_DATA wfd;
    HANDLE fh;
+   DWORD fake_inode;
    int permission;
    int len;
    int rootdir = FALSE;
***************
*** 1279,1308 ****
      {
        if (IS_DIRECTORY_SEP (name[len-1]))
  	name[len - 1] = 0;
!       fh = FindFirstFile (name, &wfd);
!       if (fh == INVALID_HANDLE_VALUE)
  	{
! 	  errno = ENOENT;
! 	  return -1;
  	}
-       FindClose (fh);
      }
  
    if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
      {
        buf->st_mode = _S_IFDIR;
        buf->st_nlink = 2;	/* doesn't really matter */
      }
!   else
      {
- #if 0
        /* 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;
  
!       fh = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
! 		       NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  
        if (GetFileInformationByHandle (fh, &info))
  	{
--- 1631,1676 ----
      {
        if (IS_DIRECTORY_SEP (name[len-1]))
  	name[len - 1] = 0;
! 
!       /* (This is hacky, but helps when doing file completions on
! 	 network drives.)  Optimize by using information available from
! 	 active readdir if possible.  */
!       if (dir_find_handle != INVALID_HANDLE_VALUE &&
! 	  (len = strlen (dir_pathname)),
! 	  strnicmp (name, dir_pathname, len) == 0 &&
! 	  IS_DIRECTORY_SEP (name[len]) &&
! 	  stricmp (name + len + 1, dir_static.d_name) == 0)
  	{
! 	  /* This was the last entry returned by readdir.  */
! 	  wfd = dir_find_data;
! 	}
!       else
! 	{
! 	  fh = FindFirstFile (name, &wfd);
! 	  if (fh == INVALID_HANDLE_VALUE)
! 	    {
! 	      errno = ENOENT;
! 	      return -1;
! 	    }
! 	  FindClose (fh);
  	}
      }
  
    if (wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
      {
        buf->st_mode = _S_IFDIR;
        buf->st_nlink = 2;	/* doesn't really matter */
+       fake_inode = 0;		/* this doesn't either I think */
      }
!   else if (!NILP (Vwin32_get_true_file_attributes))
      {
        /* 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))
  	{
***************
*** 1320,1328 ****
  	      buf->st_mode = _S_IFCHR;
  	    }
  	  buf->st_nlink = info.nNumberOfLinks;
! 	  /* Could use file index, but this is not guaranteed to be
! 	     unique unless we keep a handle open all the time. */
! 	  /* buf->st_ino = info.nFileIndexLow ^ info.nFileIndexHigh; */
  	  CloseHandle (fh);
  	}
        else
--- 1688,1699 ----
  	      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
! 	     all the time (even then there are situations where it is
! 	     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
***************
*** 1330,1340 ****
  	  errno = EACCES;
  	  return -1;
  	}
! #else
        buf->st_mode = _S_IFREG;
        buf->st_nlink = 1;
! #endif
      }
  
    /* consider files to belong to current user */
    buf->st_uid = the_passwd.pw_uid;
--- 1701,1732 ----
  	  errno = EACCES;
  	  return -1;
  	}
!     }
!   else
!     {
!       /* Don't bother to make this information more accurate.  */
        buf->st_mode = _S_IFREG;
        buf->st_nlink = 1;
!       fake_inode = 0;
!     }
! 
! #if 0
!   /* Not sure if there is any point in this.  */
!   if (!NILP (Vwin32_generate_fake_inodes))
!     fake_inode = generate_inode_val (name);
!   else if (fake_inode == 0)
!     {
!       /* For want of something better, try to make everything unique.  */
!       static DWORD gen_num = 0;
!       fake_inode = ++gen_num;
      }
+ #endif
+ 
+   /* MSVC defines _ino_t to be short; other libc's might not.  */
+   if (sizeof (buf->st_ino) == 2)
+     buf->st_ino = fake_inode ^ (fake_inode >> 16);
+   else
+     buf->st_ino = fake_inode;
  
    /* consider files to belong to current user */
    buf->st_uid = the_passwd.pw_uid;
***************
*** 1344,1350 ****
    buf->st_dev = volume_info.serialnum;
    buf->st_rdev = volume_info.serialnum;
  
-   buf->st_ino = generate_inode_val (name);
  
    buf->st_size = wfd.nFileSizeLow;
  
--- 1736,1741 ----
***************
*** 1889,1930 ****
    unsigned flags;
    child_process * cp;
  
!   /* make pipe handles non-inheritable; when we spawn a child,
!      we replace the relevant handle with an inheritable one. */
!   rc = _pipe (phandles, 0, _O_NOINHERIT);
  
    if (rc == 0)
      {
-       /* set internal flags, and put read and write handles into binary
- 	 mode as necessary; if not in binary mode, set the MSVC internal
- 	 FDEV (0x40) flag to prevent _read from treating ^Z as eof (this
- 	 could otherwise allow Emacs to hang because it then waits
- 	 indefinitely for the child process to exit, when it might not be
- 	 finished). */
        flags = FILE_PIPE | FILE_READ;
        if (!NILP (Vbinary_process_output))
! 	{
! 	  flags |= FILE_BINARY;
! 	  setmode (phandles[0], _O_BINARY);
! 	}
! #if (_MSC_VER == 900)
!       else
! 	_osfile[phandles[0]] |= 0x40;
! #endif
! 
        fd_info[phandles[0]].flags = flags;
  
        flags = FILE_PIPE | FILE_WRITE;
        if (!NILP (Vbinary_process_input))
! 	{
! 	  flags |= FILE_BINARY;
! 	  setmode (phandles[1], _O_BINARY);
! 	}
! #if (_MSC_VER == 900)
!       else
! 	_osfile[phandles[1]] |= 0x40;
! #endif
! 
        fd_info[phandles[1]].flags = flags;
      }
  
--- 2280,2301 ----
    unsigned flags;
    child_process * cp;
  
!   /* make pipe handles non-inheritable; when we spawn a child, we
!      replace the relevant handle with an inheritable one.  Also put
!      pipes into binary mode; we will do text mode translation ourselves
!      if required.  */
!   rc = _pipe (phandles, 0, _O_NOINHERIT | _O_BINARY);
  
    if (rc == 0)
      {
        flags = FILE_PIPE | FILE_READ;
        if (!NILP (Vbinary_process_output))
! 	flags |= FILE_BINARY;
        fd_info[phandles[0]].flags = flags;
  
        flags = FILE_PIPE | FILE_WRITE;
        if (!NILP (Vbinary_process_input))
! 	flags |= FILE_BINARY;
        fd_info[phandles[1]].flags = flags;
      }
  
***************
*** 1961,1967 ****
    
    if (fd_info[fd].flags & FILE_PIPE)
      {
-       /* Use read to get CRLF translation */
        rc = _read (fd, &cp->chr, sizeof (char));
  
        /* Give subprocess time to buffer some more output for us before
--- 2332,2337 ----
***************
*** 2001,2009 ****
  sys_read (int fd, char * buffer, unsigned int count)
  {
    int nchars;
-   int extra = 0;
    int to_read;
    DWORD waiting;
  
    if (fd < 0 || fd >= MAXDESC)
      {
--- 2371,2379 ----
  sys_read (int fd, char * buffer, unsigned int count)
  {
    int nchars;
    int to_read;
    DWORD waiting;
+   char * orig_buffer = buffer;
  
    if (fd < 0 || fd >= MAXDESC)
      {
***************
*** 2021,2026 ****
--- 2391,2407 ----
  	  return -1;
  	}
  
+       nchars = 0;
+ 
+       /* re-read CR carried over from last read */
+       if (fd_info[fd].flags & FILE_LAST_CR)
+ 	{
+ 	  if (fd_info[fd].flags & FILE_BINARY) abort ();
+ 	  *buffer++ = 0x0d;
+ 	  count--;
+ 	  nchars++;
+ 	}
+ 
        /* presence of a child_process structure means we are operating in
  	 non-blocking mode - otherwise we just call _read directly.
  	 Note that the child_process structure might be missing because
***************
*** 2047,2053 ****
  	      /* consume read-ahead char */
  	      *buffer++ = cp->chr;
  	      count--;
! 	      extra = 1;
  	      cp->status = STATUS_READ_ACKNOWLEDGED;
  	      ResetEvent (cp->char_avail);
  
--- 2428,2434 ----
  	      /* consume read-ahead char */
  	      *buffer++ = cp->chr;
  	      count--;
! 	      nchars++;
  	      cp->status = STATUS_READ_ACKNOWLEDGED;
  	      ResetEvent (cp->char_avail);
  
***************
*** 2065,2072 ****
  	      PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
  	      to_read = min (waiting, (DWORD) count);
        
! 	      /* Use read to get CRLF translation */
! 	      nchars = _read (fd, buffer, to_read);
  	    }
  #ifdef HAVE_SOCKETS
  	  else /* FILE_SOCKET */
--- 2446,2452 ----
  	      PeekNamedPipe ((HANDLE) _get_osfhandle (fd), NULL, 0, NULL, &waiting, NULL);
  	      to_read = min (waiting, (DWORD) count);
        
! 	      nchars += _read (fd, buffer, to_read);
  	    }
  #ifdef HAVE_SOCKETS
  	  else /* FILE_SOCKET */
***************
*** 2075,2113 ****
  
  	      /* do the equivalent of a non-blocking read */
  	      pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
! 	      if (waiting == 0 && extra == 0)
  	        {
  		  h_errno = errno = EWOULDBLOCK;
  		  return -1;
  		}
  
- 	      nchars = 0;
  	      if (waiting)
  	        {
  		  /* always use binary mode for sockets */
! 		  nchars = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
! 		  if (nchars == SOCKET_ERROR)
  		    {
  		      DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
  				pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
! 		      if (extra == 0)
! 		        {
! 			  set_errno ();
! 			  return -1;
! 			}
! 		      nchars = 0;
  		    }
  		}
  	    }
  #endif
  	}
        else
! 	nchars = _read (fd, buffer, count);
      }
    else
      nchars = _read (fd, buffer, count);
  
!   return nchars + extra;
  }
  
  /* For now, don't bother with a non-blocking mode */
--- 2455,2506 ----
  
  	      /* do the equivalent of a non-blocking read */
  	      pfn_ioctlsocket (SOCK_HANDLE (fd), FIONREAD, &waiting);
! 	      if (waiting == 0 && nchars == 0)
  	        {
  		  h_errno = errno = EWOULDBLOCK;
  		  return -1;
  		}
  
  	      if (waiting)
  	        {
  		  /* always use binary mode for sockets */
! 		  int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
! 		  if (res == SOCKET_ERROR)
  		    {
  		      DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
  				pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
! 		      set_errno ();
! 		      return -1;
  		    }
+ 		  nchars += res;
  		}
  	    }
  #endif
  	}
        else
! 	nchars += _read (fd, buffer, count);
! 
!       /* Perform text mode translation if required.  */
!       if ((fd_info[fd].flags & FILE_BINARY) == 0)
! 	{
! 	  nchars = crlf_to_lf (nchars, orig_buffer);
! 	  /* If buffer contains only CR, return that.  To be absolutely
! 	     sure we should attempt to read the next char, but in
! 	     practice a CR to be followed by LF would not appear by
! 	     itself in the buffer.  */
! 	  if (nchars > 1 && orig_buffer[nchars - 1] == 0x0d)
! 	    {
! 	      fd_info[fd].flags |= FILE_LAST_CR;
! 	      nchars--;
! 	    }
! 	  else
! 	    fd_info[fd].flags &= ~FILE_LAST_CR;
! 	}
      }
    else
      nchars = _read (fd, buffer, count);
  
!   return nchars;
  }
  
  /* For now, don't bother with a non-blocking mode */
***************
*** 2123,2133 ****
      }
  
    if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
!     if ((fd_info[fd].flags & FILE_WRITE) == 0)
!       {
! 	errno = EBADF;
! 	return -1;
!       }
  #ifdef HAVE_SOCKETS
    if (fd_info[fd].flags & FILE_SOCKET)
      {
--- 2516,2561 ----
      }
  
    if (fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
!     {
!       if ((fd_info[fd].flags & FILE_WRITE) == 0)
! 	{
! 	  errno = EBADF;
! 	  return -1;
! 	}
! 
!       /* Perform text mode translation if required.  */
!       if ((fd_info[fd].flags & FILE_BINARY) == 0)
! 	{
! 	  char * tmpbuf = alloca (count * 2);
! 	  unsigned char * src = (void *)buffer;
! 	  unsigned char * dst = tmpbuf;
! 	  int nbytes = count;
! 
! 	  while (1)
! 	    {
! 	      unsigned char *next;
! 	      /* copy next line or remaining bytes */
! 	      next = _memccpy (dst, src, '\n', nbytes);
! 	      if (next)
! 		{
! 		  /* copied one line ending with '\n' */
! 		  int copied = next - dst;
! 		  nbytes -= copied;
! 		  src += copied;
! 		  /* insert '\r' before '\n' */
! 		  next[-1] = '\r';
! 		  next[0] = '\n';
! 		  dst = next + 1;
! 		  count++;
! 		}	    
! 	      else
! 		/* copied remaining partial line -> now finished */
! 		break;
! 	    }
! 	  buffer = tmpbuf;
! 	}
!     }
! 
  #ifdef HAVE_SOCKETS
    if (fd_info[fd].flags & FILE_SOCKET)
      {
***************
*** 2157,2164 ****
  #endif
  }
  
- extern BOOL dos_process_running;
- 
  void
  init_ntproc ()
  {
--- 2585,2590 ----
***************
*** 2221,2259 ****
      if (stdin_save != INVALID_HANDLE_VALUE)
        _open_osfhandle ((long) stdin_save, O_TEXT);
      else
!       open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
!     fdopen (0, "r");
  
      if (stdout_save != INVALID_HANDLE_VALUE)
        _open_osfhandle ((long) stdout_save, O_TEXT);
      else
!       open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
!     fdopen (1, "w");
  
      if (stderr_save != INVALID_HANDLE_VALUE)
        _open_osfhandle ((long) stderr_save, O_TEXT);
      else
!       open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
!     fdopen (2, "w");
    }
  
-   /* Restrict Emacs to running only one DOS program at a time (with any
-      number of Win32 programs).  This is to prevent the user from
-      running into problems with DOS programs being run in the same VDM
-      under both Windows 95 and Windows NT.
- 
-      Note that it is possible for Emacs to run DOS programs in separate
-      VDMs, but unfortunately the pipe implementation on Windows 95 then
-      fails to report when the DOS process exits (which is supposed to
-      break the pipe).  Until this bug is fixed, or we can devise a
-      work-around, we must try to avoid letting the user start more than
-      one DOS program if possible.  */
- 
-   dos_process_running = FALSE;
- 
    /* unfortunately, atexit depends on implementation of malloc */
    /* atexit (term_ntproc); */
    signal (SIGABRT, term_ntproc);
  }
  
  /* end of nt.c */
--- 2647,2687 ----
      if (stdin_save != INVALID_HANDLE_VALUE)
        _open_osfhandle ((long) stdin_save, O_TEXT);
      else
!       _open ("nul", O_TEXT | O_NOINHERIT | O_RDONLY);
!     _fdopen (0, "r");
  
      if (stdout_save != INVALID_HANDLE_VALUE)
        _open_osfhandle ((long) stdout_save, O_TEXT);
      else
!       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
!     _fdopen (1, "w");
  
      if (stderr_save != INVALID_HANDLE_VALUE)
        _open_osfhandle ((long) stderr_save, O_TEXT);
      else
!       _open ("nul", O_TEXT | O_NOINHERIT | O_WRONLY);
!     _fdopen (2, "w");
    }
  
    /* unfortunately, atexit depends on implementation of malloc */
    /* atexit (term_ntproc); */
    signal (SIGABRT, term_ntproc);
+ 
+   /* determine which drives are fixed, for GetCachedVolumeInformation */
+   {
+     /* GetDriveType must have trailing backslash. */
+     char drive[] = "A:\\";
+ 
+     /* Loop over all possible drive letters */
+     while ( *drive <= 'Z' )
+     {
+       /* Record if this drive letter refers to a fixed drive. */
+       fixed_drives[ DRIVE_INDEX (*drive) ] =
+ 	(GetDriveType (drive) == DRIVE_FIXED);
+ 
+       (*drive)++;
+     }
+   }
  }
  
  /* end of nt.c */
diff -c pretest/src/nt.h.orig pretest/src/nt.h
*** pretest/src/nt.h.orig	Fri May 17 22:29:43 1996
--- pretest/src/nt.h	Tue Jul 22 12:29:07 1997
***************
*** 21,35 ****
  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.  */
  
- /* #define FULL_DEBUG */
- #define EMACSDEBUG
- 
- #ifdef EMACSDEBUG
- #define DebPrint(stuff) _DebPrint stuff
- #else
- #define DebPrint(stuff)
- #endif
- 
  /* File descriptor set emulation.  */
  
  /* MSVC runtime library has limit of 64 descriptors by default */
--- 21,26 ----
***************
*** 74,83 ****
  {
    int                   fd;
    int                   pid;
-   int                   is_dos_process;
    HANDLE                char_avail;
    HANDLE                char_consumed;
    HANDLE                thrd;
    PROCESS_INFORMATION   procinfo;
    volatile int          status;
    char                  chr;
--- 65,74 ----
  {
    int                   fd;
    int                   pid;
    HANDLE                char_avail;
    HANDLE                char_consumed;
    HANDLE                thrd;
+   HWND                  hwnd;
    PROCESS_INFORMATION   procinfo;
    volatile int          status;
    char                  chr;
***************
*** 101,106 ****
--- 92,98 ----
  #define FILE_READ    0x0001
  #define FILE_WRITE   0x0002
  #define FILE_BINARY  0x0010
+ #define FILE_LAST_CR 0x0020
  #define FILE_PIPE    0x0100
  #define FILE_SOCKET  0x0200
  
***************
*** 109,114 ****
--- 101,108 ----
  
  /* ------------------------------------------------------------------------- */
  
+ /* Get long (aka "true") form of file name, if it exists.  */
+ extern BOOL win32_get_long_filename (char * name, char * buf, int size);
  
  /* Prepare our standard handles for proper inheritance by child processes.  */
  extern void prepare_standard_handles (int in, int out, 
diff -c pretest/src/ntheap.c.orig pretest/src/ntheap.c
*** pretest/src/ntheap.c.orig	Mon May 13 16:06:42 1996
--- pretest/src/ntheap.c	Mon Jul 14 14:12:00 1997
***************
*** 41,46 ****
--- 41,49 ----
  int nt_major_version;
  int nt_minor_version;
  
+ /* Distinguish between Windows NT and Windows 95.  */
+ int os_subtype;
+ 
  /* Cache information describing the NT system for later use.  */
  void
  cache_system_info (void)
***************
*** 61,66 ****
--- 64,74 ----
    nt_major_version = version.info.major;
    nt_minor_version = version.info.minor;
  
+   if (version.info.platform & 0x8000)
+     os_subtype = OS_WIN95;
+   else
+     os_subtype = OS_NT;
+ 
    /* Cache page size, allocation unit, processor type, etc.  */
    GetSystemInfo (&sysinfo_cache);
    syspage_mask = sysinfo_cache.dwPageSize - 1;
***************
*** 79,89 ****
  }
  
  /* Info for keeping track of our heap.  */
! unsigned char *data_region_base = NULL;
! unsigned char *data_region_end = NULL;
! unsigned char *real_data_region_end = NULL;
! unsigned long  data_region_size = 0;
! unsigned long  reserved_heap_size = 0;
  
  /* The start of the data segment.  */
  unsigned char *
--- 87,97 ----
  }
  
  /* Info for keeping track of our heap.  */
! unsigned char *data_region_base = UNINIT_PTR;
! unsigned char *data_region_end = UNINIT_PTR;
! unsigned char *real_data_region_end = UNINIT_PTR;
! unsigned long  data_region_size = UNINIT_LONG;
! unsigned long  reserved_heap_size = UNINIT_LONG;
  
  /* The start of the data segment.  */
  unsigned char *
***************
*** 142,147 ****
--- 150,156 ----
    unsigned long end  = 1 << VALBITS; /* 256MB */
    void *ptr = NULL;
  
+ #define NTHEAP_PROBE_BASE 1
  #if NTHEAP_PROBE_BASE /* This is never normally defined */
    /* Try various addresses looking for one the kernel will let us have.  */
    while (!ptr && (base < end))
***************
*** 173,179 ****
    long size = (long) increment;
    
    /* Allocate our heap if we haven't done so already.  */
!   if (!data_region_base) 
      {
        data_region_base = allocate_heap ();
        if (!data_region_base)
--- 182,188 ----
    long size = (long) increment;
    
    /* Allocate our heap if we haven't done so already.  */
!   if (data_region_base == UNINIT_PTR) 
      {
        data_region_base = allocate_heap ();
        if (!data_region_base)
***************
*** 267,272 ****
--- 276,284 ----
       any funny interactions between file I/O and file mapping.  */
    read_in_bss (executable_path);
    map_in_heap (executable_path);
+ 
+   /* Update system version information to match current system.  */
+   cache_system_info ();
  }
  
  /* Round the heap up to the given alignment.  */
***************
*** 282,284 ****
--- 294,319 ----
    if (need_to_alloc) 
      sbrk (need_to_alloc);
  }
+ 
+ #if (_MSC_VER >= 1000)
+ 
+ /* MSVC 4.2 invokes these functions from mainCRTStartup to initialize
+    a heap via HeapCreate.  They are normally defined by the runtime,
+    but we override them here so that the unnecessary HeapCreate call
+    is not performed.  */
+ 
+ int __cdecl
+ _heap_init (void)
+ {
+   /* Stepping through the assembly indicates that mainCRTStartup is
+      expecting a nonzero success return value.  */
+   return 1;
+ }
+ 
+ void __cdecl
+ _heap_term (void)
+ {
+   return;
+ }
+ 
+ #endif
diff -c pretest/src/ntheap.h.orig pretest/src/ntheap.h
*** pretest/src/ntheap.h.orig	Mon Jan 15 09:06:29 1996
--- pretest/src/ntheap.h	Mon Jul 14 14:12:00 1997
***************
*** 44,53 ****
  extern unsigned long  data_region_size;
  extern unsigned long  reserved_heap_size;
  extern SYSTEM_INFO    sysinfo_cache;
- extern BOOL   	      need_to_recreate_heap;
  extern int    	      nt_major_version;
  extern int    	      nt_minor_version;
  
  /* Emulation of Unix sbrk().  */
  extern void *sbrk (unsigned long size);
  
--- 44,64 ----
  extern unsigned long  data_region_size;
  extern unsigned long  reserved_heap_size;
  extern SYSTEM_INFO    sysinfo_cache;
  extern int    	      nt_major_version;
  extern int    	      nt_minor_version;
  
+ /* To prevent zero-initialized variables from being placed into the bss
+    section, use non-zero values to represent an uninitialized state.  */
+ #define UNINIT_PTR ((void *) 0xF0A0F0A0)
+ #define UNINIT_LONG (0xF0A0F0A0L)
+ 
+ enum {
+   OS_WIN95 = 1,
+   OS_NT
+ };
+ 
+ extern int os_subtype;
+ 
  /* Emulation of Unix sbrk().  */
  extern void *sbrk (unsigned long size);
  
***************
*** 69,73 ****
--- 80,117 ----
  /* Round ADDRESS up to be aligned with ALIGN.  */
  extern unsigned char *round_to_next (unsigned char *address, 
  				     unsigned long align);
+ 
+ /* ----------------------------------------------------------------- */
+ /* Useful routines for manipulating memory-mapped files. */
+ 
+ typedef struct file_data {
+     char          *name;
+     unsigned long  size;
+     HANDLE         file;
+     HANDLE         file_mapping;
+     unsigned char *file_base;
+ } file_data;
+ 
+ #define OFFSET_TO_RVA(var,section) \
+ 	  (section->VirtualAddress + ((DWORD)(var) - section->PointerToRawData))
+ 
+ #define RVA_TO_OFFSET(var,section) \
+ 	  (section->PointerToRawData + ((DWORD)(var) - section->VirtualAddress))
+ 
+ #define RVA_TO_PTR(var,section,filedata) \
+ 	  ((void *)(RVA_TO_OFFSET(var,section) + (filedata).file_base))
+ 
+ int open_input_file (file_data *p_file, char *name);
+ int open_output_file (file_data *p_file, char *name, unsigned long size);
+ void close_file_data (file_data *p_file);
+ 
+ unsigned long get_section_size (PIMAGE_SECTION_HEADER p_section);
+ 
+ /* Return pointer to section header for named section. */
+ IMAGE_SECTION_HEADER * find_section (char * name, IMAGE_NT_HEADERS * nt_header);
+ 
+ /* Return pointer to section header for section containing the given
+    relative virtual address. */
+ IMAGE_SECTION_HEADER * rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header);
  
  #endif /* NTHEAP_H_ */
diff -c pretest/src/ntinevt.c.orig pretest/src/ntinevt.c
*** pretest/src/ntinevt.c.orig	Thu Jul 25 08:13:20 1996
--- pretest/src/ntinevt.c	Mon Jul 14 14:12:00 1997
***************
*** 288,298 ****
  /* return code -1 means that event_queue_ptr won't be incremented. 
     In other word, this event makes two key codes.   (by himi)       */
  int 
! key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev)
  {
    int map;
    int key_flag = 0;
    static BOOL map_virt_key_init_done;
    
    /* Skip key-up events.  */
    if (!event->bKeyDown)
--- 288,300 ----
  /* return code -1 means that event_queue_ptr won't be incremented. 
     In other word, this event makes two key codes.   (by himi)       */
  int 
! key_event (KEY_EVENT_RECORD *event, struct input_event *emacs_ev, int *isdead)
  {
    int map;
    int key_flag = 0;
    static BOOL map_virt_key_init_done;
+ 
+   *isdead = 0;
    
    /* Skip key-up events.  */
    if (!event->bKeyDown)
***************
*** 334,339 ****
--- 336,343 ----
        key_flag = win32_kbd_patch_key (event); /* 95.7.25 by himi */
        if (key_flag == 0) 
  	return 0;
+       if (key_flag < 0)
+ 	*isdead = 1;
        XSETINT (emacs_ev->code, event->uChar.AsciiChar);
      }
  #ifdef MULE
***************
*** 512,518 ****
  {
    BOOL no_events = TRUE;
    int nev, ret = 0, add;
!   
    if (interrupt_input_blocked)
      {
        interrupt_input_pending = 1;
--- 516,523 ----
  {
    BOOL no_events = TRUE;
    int nev, ret = 0, add;
!   int isdead;
! 
    if (interrupt_input_blocked)
      {
        interrupt_input_pending = 1;
***************
*** 539,545 ****
  	  switch (queue_ptr->EventType)
              {
              case KEY_EVENT:
! 	      add = key_event (&queue_ptr->Event.KeyEvent, bufp);
  	      if (add == -1) /* 95.7.25 by himi */
  		{ 
  		  queue_ptr--;
--- 544,550 ----
  	  switch (queue_ptr->EventType)
              {
              case KEY_EVENT:
! 	      add = key_event (&queue_ptr->Event.KeyEvent, bufp, &isdead);
  	      if (add == -1) /* 95.7.25 by himi */
  		{ 
  		  queue_ptr--;
diff -c pretest/src/ntproc.c.orig pretest/src/ntproc.c
*** pretest/src/ntproc.c.orig	Wed Jun 12 19:18:59 1996
--- pretest/src/ntproc.c	Mon Jul 21 15:55:36 1997
***************
*** 41,46 ****
--- 41,47 ----
  
  #include "lisp.h"
  #include "nt.h"
+ #include "ntheap.h"
  #include "systime.h"
  #include "syswait.h"
  #include "process.h"
***************
*** 51,56 ****
--- 52,61 ----
     conditional (off by default). */
  Lisp_Object Vwin32_quote_process_args;
  
+ /* Control whether create_child causes the process' window to be
+    hidden.  The default is nil. */
+ Lisp_Object Vw32_start_process_show_window;
+ 
  /* Time to sleep before reading from a subprocess output pipe - this
     avoids the inefficiency of frequently reading small amounts of data.
     This is primarily necessary for handling DOS processes on Windows 95,
***************
*** 61,68 ****
     nil means no, t means yes. */
  Lisp_Object Vwin32_downcase_file_names;
  
! /* Keep track of whether we have already started a DOS program. */
! BOOL dos_process_running;
  
  #ifndef SYS_SIGLIST_DECLARED
  extern char *sys_siglist[];
--- 66,81 ----
     nil means no, t means yes. */
  Lisp_Object Vwin32_downcase_file_names;
  
! /* Control whether stat() attempts to generate fake but hopefully
!    "accurate" inode values, by hashing the absolute truenames of files.
!    This should detect aliasing between long and short names, but still
!    allows the possibility of hash collisions.  */
! Lisp_Object Vwin32_generate_fake_inodes;
! 
! /* Control whether stat() attempts to determine file type and link count
!    exactly, at the expense of slower operation.  Since true hard links
!    are supported on NTFS volumes, this is only relevant on NT.  */
! Lisp_Object Vwin32_get_true_file_attributes;
  
  #ifndef SYS_SIGLIST_DECLARED
  extern char *sys_siglist[];
***************
*** 284,290 ****
    start.cb = sizeof (start);
    
  #ifdef HAVE_NTGUI
!   start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    start.wShowWindow = SW_HIDE;
  
    start.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
--- 297,306 ----
    start.cb = sizeof (start);
    
  #ifdef HAVE_NTGUI
!   if (NILP (Vw32_start_process_show_window))
!     start.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
!   else
!     start.dwFlags = STARTF_USESTDHANDLES;
    start.wShowWindow = SW_HIDE;
  
    start.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
***************
*** 302,308 ****
--- 318,328 ----
    sec_attrs.bInheritHandle = FALSE;
    
    if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE,
+ #ifdef SHARE_CONSOLE
  		      CREATE_NEW_PROCESS_GROUP,
+ #else
+ 		      CREATE_NEW_CONSOLE,
+ #endif
  		      env, NULL,
  		      &start, &cp->procinfo))
      goto EH_Fail;
***************
*** 316,326 ****
    /* pid must fit in a Lisp_Int */
    cp->pid = (cp->pid & VALMASK);
  
- 
    *pPid = cp->pid;
!   
    return TRUE;
!   
   EH_Fail:
    DebPrint (("create_child.CreateProcess failed: %ld\n", GetLastError()););
    return FALSE;
--- 336,345 ----
    /* pid must fit in a Lisp_Int */
    cp->pid = (cp->pid & VALMASK);
  
    *pPid = cp->pid;
! 
    return TRUE;
! 
   EH_Fail:
    DebPrint (("create_child.CreateProcess failed: %ld\n", GetLastError()););
    return FALSE;
***************
*** 373,390 ****
    if (cp->procinfo.hProcess)
      {
        /* Reap the process */
!       if (WaitForSingleObject (cp->procinfo.hProcess, INFINITE) != WAIT_OBJECT_0)
! 	DebPrint (("reap_subprocess.WaitForSingleObject (process) failed "
! 		   "with %lu for fd %ld\n", GetLastError (), cp->fd));
        CloseHandle (cp->procinfo.hProcess);
        cp->procinfo.hProcess = NULL;
        CloseHandle (cp->procinfo.hThread);
        cp->procinfo.hThread = NULL;
- 
-       /* If this was a DOS process, indicate that it is now safe to
- 	 start a new one.  */
-       if (cp->is_dos_process)
- 	dos_process_running = FALSE;
      }
  
    /* For asynchronous children, the child_proc resources will be freed
--- 392,406 ----
    if (cp->procinfo.hProcess)
      {
        /* Reap the process */
! #ifdef FULL_DEBUG
!       /* Process should have already died before we are called.  */
!       if (WaitForSingleObject (cp->procinfo.hProcess, 0) != WAIT_OBJECT_0)
! 	DebPrint (("reap_subprocess: child fpr fd %d has not died yet!", cp->fd));
! #endif
        CloseHandle (cp->procinfo.hProcess);
        cp->procinfo.hProcess = NULL;
        CloseHandle (cp->procinfo.hThread);
        cp->procinfo.hThread = NULL;
      }
  
    /* For asynchronous children, the child_proc resources will be freed
***************
*** 416,421 ****
--- 432,439 ----
        cps[nh] = dead_child;
        if (!wait_hnd[nh]) abort ();
        nh++;
+       active = 0;
+       goto get_result;
      }
    else
      {
***************
*** 425,431 ****
  	  {
  	    wait_hnd[nh] = cp->procinfo.hProcess;
  	    cps[nh] = cp;
- 	    if (!wait_hnd[nh]) abort ();
  	    nh++;
  	  }
      }
--- 443,448 ----
***************
*** 436,454 ****
        errno = ECHILD;
        return -1;
      }
!   
!   active = WaitForMultipleObjects (nh, wait_hnd, FALSE, INFINITE);
    if (active == WAIT_FAILED)
      {
        errno = EBADF;
        return -1;
      }
-   else if (active == WAIT_TIMEOUT)
-     {
-       /* Should never happen */
-       errno = EINVAL;
-       return -1;
-     }
    else if (active >= WAIT_OBJECT_0 &&
  	   active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
      {
--- 453,471 ----
        errno = ECHILD;
        return -1;
      }
! 
!   do
!     {
!       /* Check for quit about once a second. */
!       QUIT;
!       active = WaitForMultipleObjects (nh, wait_hnd, FALSE, 1000);
!     } while (active == WAIT_TIMEOUT);
! 
    if (active == WAIT_FAILED)
      {
        errno = EBADF;
        return -1;
      }
    else if (active >= WAIT_OBJECT_0 &&
  	   active < WAIT_OBJECT_0+MAXIMUM_WAIT_OBJECTS)
      {
***************
*** 459,465 ****
      {
        active -= WAIT_ABANDONED_0;
      }
!   
    if (!GetExitCodeProcess (wait_hnd[active], &retval))
      {
        DebPrint (("Wait.GetExitCodeProcess failed with %lu\n",
--- 476,485 ----
      {
        active -= WAIT_ABANDONED_0;
      }
!   else
!     abort ();
! 
! get_result:
    if (!GetExitCodeProcess (wait_hnd[active], &retval))
      {
        DebPrint (("Wait.GetExitCodeProcess failed with %lu\n",
***************
*** 493,498 ****
--- 513,519 ----
      {
        *status = retval;
      }
+ #if 0
    else if (synch_process_alive)
      {
        synch_process_alive = 0;
***************
*** 518,578 ****
  
        reap_subprocess (cp);
      }
    
    return pid;
  }
  
! int
! win32_is_dos_binary (char * filename)
  {
!   IMAGE_DOS_HEADER dos_header;
!   DWORD signature;
!   int fd;
!   int is_dos_binary = FALSE;
  
!   fd = open (filename, O_RDONLY | O_BINARY, 0);
!   if (fd >= 0)
!     {
!       char * p = strrchr (filename, '.');
  
        /* We can only identify DOS .com programs from the extension. */
!       if (p && stricmp (p, ".com") == 0)
! 	is_dos_binary = TRUE;
!       else if (p && stricmp (p, ".bat") == 0)
  	{
! 	  /* A DOS shell script - it appears that CreateProcess is happy
! 	     to accept this (somewhat surprisingly); presumably it looks
! 	     at COMSPEC to determine what executable to actually invoke.
! 	     Therefore, we have to do the same here as well. */
! 	  p = getenv ("COMSPEC");
! 	  if (p)
! 	    is_dos_binary = win32_is_dos_binary (p);
  	}
!       else
  	{
! 	  /* Look for DOS .exe signature - if found, we must also check
! 	     that it isn't really a 16- or 32-bit Windows exe, since
! 	     both formats start with a DOS program stub.  Note that
! 	     16-bit Windows executables use the OS/2 1.x format. */
! 	  if (read (fd, &dos_header, sizeof (dos_header)) == sizeof (dos_header)
! 	      && dos_header.e_magic == IMAGE_DOS_SIGNATURE
! 	      && lseek (fd, dos_header.e_lfanew, SEEK_SET) != -1)
  	    {
! 	      if (read (fd, &signature, sizeof (signature)) != sizeof (signature)
! 		  || (signature != IMAGE_NT_SIGNATURE &&
! 		      LOWORD (signature) != IMAGE_OS2_SIGNATURE))
! 		is_dos_binary = TRUE;
  	    }
  	}
-       close (fd);
      }
  
!   return is_dos_binary;
  }
  
! /* We pass our process ID to our children by setting up an environment
!    variable in their environment.  */
! char ppid_env_var_buffer[64];
  
  /* When a new child process is created we need to register it in our list,
     so intercept spawn requests.  */
--- 539,674 ----
  
        reap_subprocess (cp);
      }
+ #endif
+ 
+   reap_subprocess (cp);
    
    return pid;
  }
  
! void
! win32_executable_type (char * filename, int * is_dos_app, int * is_cygnus_app)
  {
!   file_data executable;
!   char * p;
  
!   /* Default values in case we can't tell for sure.  */
!   *is_dos_app = FALSE;
!   *is_cygnus_app = FALSE;
! 
!   if (!open_input_file (&executable, filename))
!     return;
! 
!   p = strrchr (filename, '.');
  
        /* We can only identify DOS .com programs from the extension. */
!   if (p && stricmp (p, ".com") == 0)
!     *is_dos_app = TRUE;
!   else if (p && (stricmp (p, ".bat") == 0 ||
! 		 stricmp (p, ".cmd") == 0))
!     {
!       /* A DOS shell script - it appears that CreateProcess is happy to
! 	 accept this (somewhat surprisingly); presumably it looks at
! 	 COMSPEC to determine what executable to actually invoke.
! 	 Therefore, we have to do the same here as well. */
!       /* Actually, I think it uses the program association for that
! 	 extension, which is defined in the registry.  */
!       p = egetenv ("COMSPEC");
!       if (p)
! 	win32_executable_type (p, is_dos_app, is_cygnus_app);
!     }
!   else
!     {
!       /* Look for DOS .exe signature - if found, we must also check that
! 	 it isn't really a 16- or 32-bit Windows exe, since both formats
! 	 start with a DOS program stub.  Note that 16-bit Windows
! 	 executables use the OS/2 1.x format. */
! 
!       IMAGE_DOS_HEADER * dos_header;
!       IMAGE_NT_HEADERS * nt_header;
! 
!       dos_header = (PIMAGE_DOS_HEADER) executable.file_base;
!       if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
! 	goto unwind;
! 
!       nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
! 
!       if (nt_header->Signature != IMAGE_NT_SIGNATURE &&
! 	  LOWORD (nt_header->Signature) != IMAGE_OS2_SIGNATURE)
  	{
! 	  *is_dos_app = TRUE;
  	}
!       else if (nt_header->Signature == IMAGE_NT_SIGNATURE)
  	{
! 	  /* Look for cygwin.dll in DLL import list. */
! 	  IMAGE_DATA_DIRECTORY import_dir =
! 	    nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
! 	  IMAGE_IMPORT_DESCRIPTOR * imports;
! 	  IMAGE_SECTION_HEADER * section;
! 
! 	  section = rva_to_section (import_dir.VirtualAddress, nt_header);
! 	  imports = RVA_TO_PTR (import_dir.VirtualAddress, section, executable);
! 
! 	  for ( ; imports->Name; imports++)
  	    {
! 	      char * dllname = RVA_TO_PTR (imports->Name, section, executable);
! 
! 	      if (strcmp (dllname, "cygwin.dll") == 0)
! 		{
! 		  *is_cygnus_app = TRUE;
! 		  break;
! 		}
  	    }
  	}
      }
  
! unwind:
!   close_file_data (&executable);
! }
! 
! int
! compare_env (const char **strp1, const char **strp2)
! {
!   const char *str1 = *strp1, *str2 = *strp2;
! 
!   while (*str1 && *str2 && *str1 != '=' && *str2 != '=')
!     {
!       if ((*str1) > (*str2))
! 	return 1;
!       else if ((*str1) < (*str2))
! 	return -1;
!       str1++, str2++;
!     }
! 
!   if (*str1 == '=' && *str2 == '=')
!     return 0;
!   else if (*str1 == '=')
!     return -1;
!   else
!     return 1;
  }
  
! void
! merge_and_sort_env (char **envp1, char **envp2, char **new_envp)
! {
!   char **optr, **nptr;
!   int num;
! 
!   nptr = new_envp;
!   optr = envp1;
!   while (*optr)
!     *nptr++ = *optr++;
!   num = optr - envp1;
! 
!   optr = envp2;
!   while (*optr)
!     *nptr++ = *optr++;
!   num += optr - envp2;
! 
!   qsort (new_envp, num, sizeof (char *), compare_env);
! 
!   *nptr = NULL;
! }
  
  /* When a new child process is created we need to register it in our list,
     so intercept spawn requests.  */
***************
*** 581,590 ****
  {
    Lisp_Object program, full;
    char *cmdline, *env, *parg, **targ;
!   int arglen;
    int pid;
    child_process *cp;
!   int is_dos_binary;
    
    /* We don't care about the other modes */
    if (mode != _P_NOWAIT)
--- 677,692 ----
  {
    Lisp_Object program, full;
    char *cmdline, *env, *parg, **targ;
!   int arglen, numenv;
    int pid;
    child_process *cp;
!   int is_dos_app, is_cygnus_app;
!   int do_quoting = 0;
!   char escape_char;
!   /* We pass our process ID to our children by setting up an environment
!      variable in their environment.  */
!   char ppid_env_var_buffer[64];
!   char *extra_env[] = {ppid_env_var_buffer, NULL};
    
    /* We don't care about the other modes */
    if (mode != _P_NOWAIT)
***************
*** 608,629 ****
  	  errno = EINVAL;
  	  return -1;
  	}
!       cmdname = XSTRING (full)->data;
!       argv[0] = cmdname;
      }
  
!   /* make sure cmdname is in DOS format */
!   strcpy (cmdname = alloca (strlen (cmdname) + 1), argv[0]);
    unixtodos_filename (cmdname);
    argv[0] = cmdname;
  
!   /* Check if program is a DOS executable, and if so whether we are
!      allowed to start it. */
!   is_dos_binary = win32_is_dos_binary (cmdname);
!   if (is_dos_binary && dos_process_running)
!     {
!       errno = EAGAIN;
!       return -1;
      }
    
    /* we have to do some conjuring here to put argv and envp into the
--- 710,744 ----
  	  errno = EINVAL;
  	  return -1;
  	}
!       program = full;
      }
  
!   /* make sure argv[0] and cmdname are both in DOS format */
!   cmdname = XSTRING (program)->data;
    unixtodos_filename (cmdname);
    argv[0] = cmdname;
  
!   /* Determine whether program is a 16-bit DOS executable, or a Win32
!      executable that is implicitly linked to the Cygnus dll (implying it
!      was compiled with the Cygnus GNU toolchain and hence relies on
!      cygwin.dll to parse the command line - we use this to decide how to
!      escape quote chars in command line args that must be quoted). */
!   win32_executable_type (cmdname, &is_dos_app, &is_cygnus_app);
! 
!   /* On Windows 95, if cmdname is a DOS app, we invoke a helper
!      application to start it by specifying the helper app as cmdname,
!      while leaving the real app name as argv[0].  */
!   if (is_dos_app)
!     {
!       cmdname = alloca (MAXPATHLEN);
!       if (egetenv ("CMDPROXY"))
! 	strcpy (cmdname, egetenv ("CMDPROXY"));
!       else
! 	{
! 	  strcpy (cmdname, XSTRING (Vinvocation_directory)->data);
! 	  strcat (cmdname, "cmdproxy.exe");
! 	}
!       unixtodos_filename (cmdname);
      }
    
    /* we have to do some conjuring here to put argv and envp into the
***************
*** 631,647 ****
       terminated list of parameters, and envp is a null
       separated/double-null terminated list of parameters.
  
!      Additionally, zero-length args and args containing whitespace need
!      to be wrapped in double quotes.  Args containing embedded double
!      quotes (as opposed to enclosing quotes, which we leave alone) are
!      usually illegal (most Win32 programs do not implement escaping of
!      double quotes - sad but true, at least for programs compiled with
!      MSVC), but we will escape quotes anyway for those programs that can
!      handle it.  The Win32 gcc library from Cygnus doubles quotes to
!      escape them, so we will use that convention.
     
!      Since I have no idea how large argv and envp are likely to be
!      we figure out list lengths on the fly and allocate them.  */
    
    /* do argv...  */
    arglen = 0;
--- 746,786 ----
       terminated list of parameters, and envp is a null
       separated/double-null terminated list of parameters.
  
!      Additionally, zero-length args and args containing whitespace or
!      quote chars need to be wrapped in double quotes - for this to work,
!      embedded quotes need to be escaped as well.  The aim is to ensure
!      the child process reconstructs the argv array we start with
!      exactly, so we treat quotes at the beginning and end of arguments
!      as embedded quotes.
! 
!      The Win32 GNU-based library from Cygnus doubles quotes to escape
!      them, while MSVC uses backslash for escaping.  (Actually the MSVC
!      startup code does attempt to recognise doubled quotes and accept
!      them, but gets it wrong and ends up requiring three quotes to get a
!      single embedded quote!)  So by default we decide whether to use
!      quote or backslash as the escape character based on whether the
!      binary is apparently a Cygnus compiled app.
! 
!      Note that using backslash to escape embedded quotes requires
!      additional special handling if an embedded quote is already
!      preceeded by backslash, or if an arg requiring quoting ends with
!      backslash.  In such cases, the run of escape characters needs to be
!      doubled.  For consistency, we apply this special handling as long
!      as the escape character is not quote.
     
!      Since we have no idea how large argv and envp are likely to be we
!      figure out list lengths on the fly and allocate them.  */
! 
!   if (!NILP (Vwin32_quote_process_args))
!     {
!       do_quoting = 1;
!       /* Override escape char by binding win32-quote-process-args to
! 	 desired character, or use t for auto-selection.  */
!       if (INTEGERP (Vwin32_quote_process_args))
! 	escape_char = XINT (Vwin32_quote_process_args);
!       else
! 	escape_char = is_cygnus_app ? '"' : '\\';
!     }
    
    /* do argv...  */
    arglen = 0;
***************
*** 649,670 ****
    while (*targ)
      {
        char * p = *targ;
!       int add_quotes = 0;
  
        if (*p == 0)
! 	add_quotes = 1;
!       while (*p)
! 	if (*p++ == '"')
! 	  {
! 	    /* allow for embedded quotes to be doubled - we won't
! 	       actually double quotes that aren't embedded though */
! 	    arglen++;
! 	    add_quotes = 1;
! 	  }
!       else if (*p == ' ' || *p == '\t')
! 	add_quotes = 1;
!       if (add_quotes)
! 	arglen += 2;
        arglen += strlen (*targ++) + 1;
      }
    cmdline = alloca (arglen);
--- 788,832 ----
    while (*targ)
      {
        char * p = *targ;
!       int need_quotes = 0;
!       int escape_char_run = 0;
  
        if (*p == 0)
! 	need_quotes = 1;
!       for ( ; *p; p++)
! 	{
! 	  if (*p == '"')
! 	    {
! 	      /* allow for embedded quotes to be escaped */
! 	      arglen++;
! 	      need_quotes = 1;
! 	      /* handle the case where the embedded quote is already escaped */
! 	      if (escape_char_run > 0)
! 		{
! 		  /* To preserve the arg exactly, we need to double the
! 		     preceding escape characters (plus adding one to
! 		     escape the quote character itself).  */
! 		  arglen += escape_char_run;
! 		}
! 	    }
! 	  else if (*p == ' ' || *p == '\t')
! 	    {
! 	      need_quotes = 1;
! 	    }
! 
! 	  if (*p == escape_char && escape_char != '"')
! 	    escape_char_run++;
! 	  else
! 	    escape_char_run = 0;
! 	}
!       if (need_quotes)
! 	{
! 	  arglen += 2;
! 	  /* handle the case where the arg ends with an escape char - we
! 	     must not let the enclosing quote be escaped.  */
! 	  if (escape_char_run > 0)
! 	    arglen += escape_char_run;
! 	}
        arglen += strlen (*targ++) + 1;
      }
    cmdline = alloca (arglen);
***************
*** 673,696 ****
    while (*targ)
      {
        char * p = *targ;
!       int add_quotes = 0;
  
        if (*p == 0)
! 	add_quotes = 1;
  
!       if (!NILP (Vwin32_quote_process_args))
  	{
- 	  /* This is conditional because it sometimes causes more
- 	     problems than it solves, since argv arrays are not always
- 	     carefully constructed.  M-x grep, for instance, passes the
- 	     whole command line as one argument, so it becomes
- 	     impossible to pass a regexp which contains spaces. */
  	  for ( ; *p; p++)
  	    if (*p == ' ' || *p == '\t' || *p == '"')
! 	      add_quotes = 1;
  	}
!       if (add_quotes)
  	{
  	  char * first;
  	  char * last;
  
--- 835,854 ----
    while (*targ)
      {
        char * p = *targ;
!       int need_quotes = 0;
  
        if (*p == 0)
! 	need_quotes = 1;
  
!       if (do_quoting)
  	{
  	  for ( ; *p; p++)
  	    if (*p == ' ' || *p == '\t' || *p == '"')
! 	      need_quotes = 1;
  	}
!       if (need_quotes)
  	{
+ 	  int escape_char_run = 0;
  	  char * first;
  	  char * last;
  
***************
*** 698,709 ****
  	  first = p;
  	  last = p + strlen (p) - 1;
  	  *parg++ = '"';
  	  while (*p)
  	    {
  	      if (*p == '"' && p > first && p < last)
! 		*parg++ = '"';	/* double up embedded quotes only */
  	      *parg++ = *p++;
  	    }
  	  *parg++ = '"';
  	}
        else
--- 856,902 ----
  	  first = p;
  	  last = p + strlen (p) - 1;
  	  *parg++ = '"';
+ #if 0
+ 	  /* This version does not escape quotes if they occur at the
+ 	     beginning or end of the arg - this could lead to incorrect
+ 	     behaviour when the arg itself represents a command line
+ 	     containing quoted args.  I believe this was originally done
+ 	     as a hack to make some things work, before
+ 	     `win32-quote-process-args' was added.  */
  	  while (*p)
  	    {
  	      if (*p == '"' && p > first && p < last)
! 		*parg++ = escape_char;	/* escape embedded quotes */
  	      *parg++ = *p++;
  	    }
+ #else
+ 	  for ( ; *p; p++)
+ 	    {
+ 	      if (*p == '"')
+ 		{
+ 		  /* double preceding escape chars if any */
+ 		  while (escape_char_run > 0)
+ 		    {
+ 		      *parg++ = escape_char;
+ 		      escape_char_run--;
+ 		    }
+ 		  /* escape all quote chars, even at beginning or end */
+ 		  *parg++ = escape_char;
+ 		}
+ 	      *parg++ = *p;
+ 
+ 	      if (*p == escape_char && escape_char != '"')
+ 		escape_char_run++;
+ 	      else
+ 		escape_char_run = 0;
+ 	    }
+ 	  /* double escape chars before enclosing quote */
+ 	  while (escape_char_run > 0)
+ 	    {
+ 	      *parg++ = escape_char;
+ 	      escape_char_run--;
+ 	    }
+ #endif
  	  *parg++ = '"';
  	}
        else
***************
*** 719,734 ****
    /* and envp...  */
    arglen = 1;
    targ = envp;
    while (*targ)
      {
        arglen += strlen (*targ++) + 1;
      }
    sprintf (ppid_env_var_buffer, "__PARENT_PROCESS_ID=%d", 
  	   GetCurrentProcessId ());
    arglen += strlen (ppid_env_var_buffer) + 1;
  
    env = alloca (arglen);
-   targ = envp;
    parg = env;
    while (*targ)
      {
--- 912,935 ----
    /* and envp...  */
    arglen = 1;
    targ = envp;
+   numenv = 1; /* for end null */
    while (*targ)
      {
        arglen += strlen (*targ++) + 1;
+       numenv++;
      }
+   /* extra env vars... */
    sprintf (ppid_env_var_buffer, "__PARENT_PROCESS_ID=%d", 
  	   GetCurrentProcessId ());
    arglen += strlen (ppid_env_var_buffer) + 1;
+   numenv++;
+ 
+   /* merge env passed in and extra env into one, and sort it.  */
+   targ = (char **) alloca (numenv * sizeof (char *));
+   merge_and_sort_env (envp, extra_env, targ);
  
+   /* concatenate env entries.  */
    env = alloca (arglen);
    parg = env;
    while (*targ)
      {
***************
*** 736,743 ****
        parg += strlen (*targ++);
        *parg++ = '\0';
      }
-   strcpy (parg, ppid_env_var_buffer);
-   parg += strlen (ppid_env_var_buffer);
    *parg++ = '\0';
    *parg = '\0';
  
--- 937,942 ----
***************
*** 755,766 ****
        errno = ENOEXEC;
        return -1;
      }
- 
-   if (is_dos_binary)
-     {
-       cp->is_dos_process = TRUE;
-       dos_process_running = TRUE;
-     }
    
    return pid;
  }
--- 954,959 ----
***************
*** 768,774 ****
  /* Emulate the select call
     Wait for available input on any of the given rfds, or timeout if
     a timeout is given and no input is detected
!    wfds and efds are not supported and must be NULL.  */
  
  /* From ntterm.c */
  extern HANDLE keyboard_handle;
--- 961,974 ----
  /* Emulate the select call
     Wait for available input on any of the given rfds, or timeout if
     a timeout is given and no input is detected
!    wfds and efds are not supported and must be NULL.
! 
!    For simplicity, we detect the death of child processes here and
!    synchronously call the SIGCHLD handler.  Since it is possible for
!    children to be created without a corresponding pipe handle from which
!    to read output, we wait separately on the process handles as well as
!    the char_avail events for each process pipe.  We only call
!    wait/reap_process when the process actually terminates.  */
  
  /* From ntterm.c */
  extern HANDLE keyboard_handle;
***************
*** 780,796 ****
  	    EMACS_TIME *timeout)
  {
    SELECT_TYPE orfds;
!   DWORD timeout_ms;
!   int i, nh, nr;
    DWORD active;
!   child_process *cp;
!   HANDLE wait_hnd[MAXDESC];
    int fdindex[MAXDESC];   /* mapping from wait handles back to descriptors */
    
    /* If the descriptor sets are NULL but timeout isn't, then just Sleep.  */
    if (rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL) 
      {
!       Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
        return 0;
      }
  
--- 980,998 ----
  	    EMACS_TIME *timeout)
  {
    SELECT_TYPE orfds;
!   DWORD timeout_ms, start_time;
!   int i, nh, nc, nr;
    DWORD active;
!   child_process *cp, *cps[MAX_CHILDREN];
!   HANDLE wait_hnd[MAXDESC + MAX_CHILDREN];
    int fdindex[MAXDESC];   /* mapping from wait handles back to descriptors */
    
+   timeout_ms = timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFINITE;
+ 
    /* If the descriptor sets are NULL but timeout isn't, then just Sleep.  */
    if (rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL) 
      {
!       Sleep (timeout_ms);
        return 0;
      }
  
***************
*** 805,811 ****
    FD_ZERO (rfds);
    nr = 0;
    
!   /* Build a list of handles to wait on.  */
    nh = 0;
    for (i = 0; i < nfds; i++)
      if (FD_ISSET (i, &orfds))
--- 1007,1013 ----
    FD_ZERO (rfds);
    nr = 0;
    
!   /* Build a list of pipe handles to wait on.  */
    nh = 0;
    for (i = 0; i < nfds; i++)
      if (FD_ISSET (i, &orfds))
***************
*** 894,922 ****
  	      }
  	  }
        }
    
    /* Nothing to look for, so we didn't find anything */
!   if (nh == 0) 
      {
        if (timeout)
! 	Sleep (timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
        return 0;
      }
    
!   /*
!      Wait for input
!      If a child process dies while this is waiting, its pipe will break
!      so the reader thread will signal an error condition, thus, the wait
!      will wake up
!      */
!   timeout_ms = timeout ? (timeout->tv_sec * 1000 + timeout->tv_usec / 1000) : INFINITE;
! 
!   active = WaitForMultipleObjects (nh, wait_hnd, FALSE, timeout_ms);
  
    if (active == WAIT_FAILED)
      {
        DebPrint (("select.WaitForMultipleObjects (%d, %lu) failed with %lu\n",
! 		 nh, timeout_ms, GetLastError ()));
        /* don't return EBADF - this causes wait_reading_process_input to
  	 abort; WAIT_FAILED is returned when single-stepping under
  	 Windows 95 after switching thread focus in debugger, and
--- 1096,1130 ----
  	      }
  	  }
        }
+ 
+ count_children:
+   /* Add handles of child processes.  */
+   nc = 0;
+   for (cp = child_procs+(child_proc_count-1); cp >= child_procs; cp--)
+     /* some child_procs might be sockets; ignore them */
+     if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess)
+       {
+ 	wait_hnd[nh + nc] = cp->procinfo.hProcess;
+ 	cps[nc] = cp;
+ 	nc++;
+       }
    
    /* Nothing to look for, so we didn't find anything */
!   if (nh + nc == 0) 
      {
        if (timeout)
! 	Sleep (timeout_ms);
        return 0;
      }
    
!   /* Wait for input or child death to be signalled.  */
!   start_time = GetTickCount ();
!   active = WaitForMultipleObjects (nh + nc, wait_hnd, FALSE, timeout_ms);
  
    if (active == WAIT_FAILED)
      {
        DebPrint (("select.WaitForMultipleObjects (%d, %lu) failed with %lu\n",
! 		 nh + nc, timeout_ms, GetLastError ()));
        /* don't return EBADF - this causes wait_reading_process_input to
  	 abort; WAIT_FAILED is returned when single-stepping under
  	 Windows 95 after switching thread focus in debugger, and
***************
*** 938,943 ****
--- 1146,1153 ----
      {
        active -= WAIT_ABANDONED_0;
      }
+   else
+     abort ();
  
    /* Loop over all handles after active (now officially documented as
       being the first signalled handle in the array).  We do this to
***************
*** 945,951 ****
       processed - otherwise higher numbered channels could be starved. */
    do
      {
!       if (fdindex[active] == 0)
  	{
  	  /* Keyboard input available */
  	  FD_SET (0, rfds);
--- 1155,1177 ----
       processed - otherwise higher numbered channels could be starved. */
    do
      {
!       if (active >= nh)
! 	{
! 	  cp = cps[active - nh];
! 	  /* SIG_DFL for SIGCHLD is ignore */
! 	  if (sig_handlers[SIGCHLD] != SIG_DFL &&
! 	      sig_handlers[SIGCHLD] != SIG_IGN)
! 	    {
! #ifdef FULL_DEBUG
! 	      DebPrint (("select calling SIGCHLD handler for pid %d\n",
! 			 cp->pid));
! #endif
! 	      dead_child = cp;
! 	      sig_handlers[SIGCHLD] (SIGCHLD);
! 	      dead_child = NULL;
! 	    }
! 	}
!       else if (fdindex[active] == 0)
  	{
  	  /* Keyboard input available */
  	  FD_SET (0, rfds);
***************
*** 953,1012 ****
  	}
        else
  	{
! 	  /* must be a socket or pipe */
! 	  int current_status;
! 
! 	  cp = fd_info[ fdindex[active] ].cp;
! 
! 	  /* Read ahead should have completed, either succeeding or failing. */
  	  FD_SET (fdindex[active], rfds);
  	  nr++;
- 	  current_status = cp->status;
- 	  if (current_status != STATUS_READ_SUCCEEDED)
- 	    {
- 	      if (current_status != STATUS_READ_FAILED)
- 		DebPrint (("internal error: subprocess pipe signalled "
- 			   "at the wrong time (status %d)\n!", current_status));
- 
- 	      /* The child_process entry for a socket or pipe will be
- 		 freed when the last descriptor using it is closed; for
- 		 pipes, we call the SIGCHLD handler. */
- 	      if (fd_info[ fdindex[active] ].flags & FILE_PIPE)
- 		{
- 		  /* The SIGCHLD handler will do a Wait so we know it won't
- 		     return until the process is dead
- 		     We force Wait to only wait for this process to avoid it
- 		     picking up other children that happen to be dead but that
- 		     we haven't noticed yet
- 		     SIG_DFL for SIGCHLD is ignore? */
- 		  if (sig_handlers[SIGCHLD] != SIG_DFL &&
- 		      sig_handlers[SIGCHLD] != SIG_IGN)
- 		    {
- #ifdef FULL_DEBUG
- 		      DebPrint (("select calling SIGCHLD handler for pid %d\n",
- 				 cp->pid));
- #endif
- 		      dead_child = cp;
- 		      sig_handlers[SIGCHLD] (SIGCHLD);
- 		      dead_child = NULL;
- 		    }
- 
- 		  /* Clean up the child process entry in the table */
- 		  reap_subprocess (cp);
- 		}
- 	    }
  	}
  
!       /* Test for input on remaining channels. */
!       while (++active < nh)
  	if (WaitForSingleObject (wait_hnd[active], 0) == WAIT_OBJECT_0)
  	  break;
!     } while (active < nh);
  
    return nr;
  }
  
  /* Substitute for certain kill () operations */
  int 
  sys_kill (int pid, int sig)
  {
--- 1179,1245 ----
  	}
        else
  	{
! 	  /* must be a socket or pipe - read ahead should have
!              completed, either succeeding or failing.  */
  	  FD_SET (fdindex[active], rfds);
  	  nr++;
  	}
  
!       /* Even though wait_reading_process_output only reads from at most
! 	 one channel, we must process all channels here so that we reap
! 	 all children that have died.  */
!       while (++active < nh + nc)
  	if (WaitForSingleObject (wait_hnd[active], 0) == WAIT_OBJECT_0)
  	  break;
!     } while (active < nh + nc);
! 
!   /* If no input has arrived and timeout hasn't expired, wait again.  */
!   if (nr == 0)
!     {
!       DWORD elapsed = GetTickCount () - start_time;
! 
!       if (timeout_ms > elapsed)	/* INFINITE is MAX_UINT */
! 	{
! 	  if (timeout_ms != INFINITE)
! 	    timeout_ms -= elapsed;
! 	  goto count_children;
! 	}
!     }
  
    return nr;
  }
  
  /* Substitute for certain kill () operations */
+ 
+ #ifndef SHARE_CONSOLE
+ 
+ static BOOL CALLBACK
+ find_child_console (HWND hwnd, child_process * cp)
+ {
+   DWORD thread_id;
+   DWORD process_id;
+ 
+   thread_id = GetWindowThreadProcessId (hwnd, &process_id);
+   if (process_id == cp->procinfo.dwProcessId)
+     {
+       char window_class[32];
+ 
+       GetClassName (hwnd, window_class, sizeof (window_class));
+       if (strcmp (window_class,
+ 		  (os_subtype == OS_WIN95)
+ 		  ? "tty"
+ 		  : "ConsoleWindowClass") == 0)
+ 	{
+ 	  cp->hwnd = hwnd;
+ 	  return FALSE;
+ 	}
+     }
+   /* keep looking */
+   return TRUE;
+ }
+ 
+ #endif /* !SHARE_CONSOLE */
+ 
  int 
  sys_kill (int pid, int sig)
  {
***************
*** 1037,1046 ****
--- 1270,1285 ----
      {
        proc_hand = cp->procinfo.hProcess;
        pid = cp->procinfo.dwProcessId;
+ 
+ #ifndef SHARE_CONSOLE
+       /* Try to locate console window for process. */
+       EnumWindows (find_child_console, (LPARAM) cp);
+ #endif
      }
    
    if (sig == SIGINT)
      {
+ #ifdef SHARE_CONSOLE
        /* Ctrl-Break is NT equivalent of SIGINT.  */
        if (!GenerateConsoleCtrlEvent (CTRL_BREAK_EVENT, pid))
          {
***************
*** 1049,1063 ****
  	  errno = EINVAL;
  	  rc = -1;
          }
      }
    else
      {
        /* Kill the process.  On Win32 this doesn't kill child processes
  	 so it doesn't work very well for shells which is why it's not
! 	 used in every case.  Also, don't try to terminate DOS processes
! 	 (on Win95), because this will hang Emacs. */
!       if (!(cp && cp->is_dos_process)
! 	  && !TerminateProcess (proc_hand, 0xff))
          {
  	  DebPrint (("sys_kill.TerminateProcess returned %d "
  		     "for pid %lu\n", GetLastError (), pid));
--- 1288,1358 ----
  	  errno = EINVAL;
  	  rc = -1;
          }
+ #else
+       if (cp && cp->hwnd)
+ 	{
+ 	  BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
+ 	  BYTE vk_break_code = VK_CANCEL;
+ 	  BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
+ 	  HWND foreground_window;
+ 
+ 	  if (break_scan_code == 0)
+ 	    {
+ 	      /* Fake Ctrl-C if we can't manage Ctrl-Break. */
+ 	      vk_break_code = 'C';
+ 	      break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
+ 	    }
+ 
+ 	  foreground_window = GetForegroundWindow ();
+ 	  if (foreground_window && SetForegroundWindow (cp->hwnd))
+ 	    {
+ 	      /* Generate keystrokes as if user had typed Ctrl-Break or Ctrl-C.  */
+ 	      keybd_event (VK_CONTROL, control_scan_code, 0, 0);
+ 	      keybd_event (vk_break_code, break_scan_code, 0, 0);
+ 	      keybd_event (vk_break_code, break_scan_code, KEYEVENTF_KEYUP, 0);
+ 	      keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
+ 
+ 	      SetForegroundWindow (foreground_window);
+ 	    }
+ 	}
+ #endif
      }
    else
      {
+ #ifndef SHARE_CONSOLE
+       if (cp && cp->hwnd)
+ 	{
+ #if 1
+ 	  if (os_subtype == OS_WIN95)
+ 	    {
+ /*
+    Another possibility is to try terminating the VDM out-right by
+    calling the Shell VxD (id 0x17) V86 interface, function #4
+    "SHELL_Destroy_VM", ie.
+ 
+      mov edx,4
+      mov ebx,vm_handle
+      call shellapi
+ 
+    First need to determine the current VM handle, and then arrange for
+    the shellapi call to be made from the system vm (by using
+    Switch_VM_and_callback).
+ 
+    Could try to invoke DestroyVM through CallVxD.
+ 
+ */
+ 	      PostMessage (cp->hwnd, WM_QUIT, 0xff, 0);
+ 	    }
+ 	  else
+ #endif
+ 	    PostMessage (cp->hwnd, WM_CLOSE, 0, 0);
+ 	}
+       else
+ #endif
        /* Kill the process.  On Win32 this doesn't kill child processes
  	 so it doesn't work very well for shells which is why it's not
! 	 used in every case.  */
!       if (!TerminateProcess (proc_hand, 0xff))
          {
  	  DebPrint (("sys_kill.TerminateProcess returned %d "
  		     "for pid %lu\n", GetLastError (), pid));
***************
*** 1225,1236 ****
--- 1520,1589 ----
  #endif /* HAVE_SOCKETS */
  
  
+ /* Some miscellaneous functions that are Window specific.  */
+ 
+ /* lifted from fileio.c  */
+ #define CORRECT_DIR_SEPS(s) \
+   do { if ('/' == DIRECTORY_SEP) dostounix_filename (s); \
+        else unixtodos_filename (s); \
+   } while (0)
+ 
+ DEFUN ("win32-short-file-name", Fwin32_short_file_name, Swin32_short_file_name, 1, 1, 0,
+   "Return the short file name version (8.3) of the full path of FILENAME.\n\
+ If FILENAME does not exist, return nil.\n\
+ All path elements in FILENAME are converted to their short names.")
+      (filename)
+      Lisp_Object filename;
+ {
+   char shortname[MAX_PATH];
+ 
+   CHECK_STRING (filename, 0);
+ 
+   /* first expand it.  */
+   filename = Fexpand_file_name (filename, Qnil);
+ 
+   /* luckily, this returns the short version of each element in the path.  */
+   if (GetShortPathName (XSTRING (filename)->data, shortname, MAX_PATH) == 0)
+     return Qnil;
+ 
+   CORRECT_DIR_SEPS (shortname);
+ 
+   return build_string (shortname);
+ }
+ 
+ 
+ DEFUN ("win32-long-file-name", Fwin32_long_file_name, Swin32_long_file_name,
+        1, 1, 0,
+   "Return the long file name version of the full path of FILENAME.\n\
+ If FILENAME does not exist, return nil.\n\
+ All path elements in FILENAME are converted to their long names.")
+   (filename)
+      Lisp_Object filename;
+ {
+   char longname[ MAX_PATH ];
+ 
+   CHECK_STRING (filename, 0);
+ 
+   /* first expand it.  */
+   filename = Fexpand_file_name (filename, Qnil);
+ 
+   if (!win32_get_long_filename (XSTRING (filename)->data, longname, MAX_PATH))
+     return Qnil;
+ 
+   CORRECT_DIR_SEPS (longname);
+ 
+   return build_string (longname);
+ }
+ 
+ 
  syms_of_ntproc ()
  {
  #ifdef HAVE_SOCKETS
    defsubr (&Swin32_has_winsock);
    defsubr (&Swin32_unload_winsock);
  #endif
+   defsubr (&Swin32_short_file_name);
+   defsubr (&Swin32_long_file_name);
  
    DEFVAR_LISP ("win32-quote-process-args", &Vwin32_quote_process_args,
      "Non-nil enables quoting of process arguments to ensure correct parsing.\n\
***************
*** 1239,1248 ****
  line string.  For an argument to contain a space, it must be enclosed\n\
  in double quotes or it will be parsed as multiple arguments.\n\
  \n\
! However, the argument list to call-process is not always correctly\n\
! constructed (or arguments have already been quoted), so enabling this\n\
! option may cause unexpected behavior.");
!   Vwin32_quote_process_args = Qnil;
  
    DEFVAR_INT ("win32-pipe-read-delay", &Vwin32_pipe_read_delay,
      "Forced delay before reading subprocess output.\n\
--- 1592,1607 ----
  line string.  For an argument to contain a space, it must be enclosed\n\
  in double quotes or it will be parsed as multiple arguments.\n\
  \n\
! If the value is a character, that character will be used to escape any\n\
! quote characters that appear, otherwise a suitable escape character\n\
! will be chosen based on the type of the program.");
!   Vwin32_quote_process_args = Qt;
! 
!   DEFVAR_LISP ("w32-start-process-show-window",
! 	       &Vw32_start_process_show_window,
!     "When nil, processes started via start-process hide their windows.\n\
! When non-nil, they show their window in the method of their choice.");
!   Vw32_start_process_show_window = Qnil;
  
    DEFVAR_INT ("win32-pipe-read-delay", &Vwin32_pipe_read_delay,
      "Forced delay before reading subprocess output.\n\
***************
*** 1259,1263 ****
--- 1618,1639 ----
      "Non-nil means convert all-upper case file names to lower case.\n\
  This applies when performing completions and file name expansion.");
    Vwin32_downcase_file_names = Qnil;
+ 
+ #if 0
+   DEFVAR_LISP ("win32-generate-fake-inodes", &Vwin32_generate_fake_inodes,
+     "Non-nil means attempt to fake realistic inode values.\n\
+ This works by hashing the truename of files, and should detect \n\
+ aliasing between long and short (8.3 DOS) names, but can have\n\
+ false positives because of hash collisions.  Note that determing\n\
+ the truename of a file can be slow.");
+   Vwin32_generate_fake_inodes = Qnil;
+ #endif
+ 
+   DEFVAR_LISP ("win32-get-true-file-attributes", &Vwin32_get_true_file_attributes,
+     "Non-nil means determine accurate link count in file-attributes.\n\
+ This option slows down file-attributes noticeably, so is disabled by\n\
+ default.  Note that it is only useful for files on NTFS volumes,\n\
+ where hard links are supported.");
+   Vwin32_get_true_file_attributes = Qnil;
  }
  /* end of ntproc.c */
diff -c pretest/src/ntterm.c.orig pretest/src/ntterm.c
*** pretest/src/ntterm.c.orig	Fri May 10 21:31:57 1996
--- pretest/src/ntterm.c	Tue Jul 22 12:44:47 1997
***************
*** 64,87 ****
  static void set_terminal_window (int size);
  static void update_begin (FRAME_PTR f);
  static void update_end (FRAME_PTR f);
- static void reset_kbd (void);
- static void unset_kbd (void);
  static int  hl_mode (int new_highlight);
  
- void
- DebPrint ()
- {
- }
- 
- /* Init hook called in init_keyboard.  */
- void (*keyboard_init_hook)(void) = reset_kbd;
-     
  COORD	cursor_coords;
  HANDLE	prev_screen, cur_screen;
  UCHAR	char_attr, char_attr_normal, char_attr_reverse;
  HANDLE  keyboard_handle;
  DWORD   prev_console_mode;
  
  
  /* Setting this as the ctrl handler prevents emacs from being killed when
     someone hits ^C in a 'suspended' session (child shell).
--- 64,81 ----
  static void set_terminal_window (int size);
  static void update_begin (FRAME_PTR f);
  static void update_end (FRAME_PTR f);
  static int  hl_mode (int new_highlight);
  
  COORD	cursor_coords;
  HANDLE	prev_screen, cur_screen;
  UCHAR	char_attr, char_attr_normal, char_attr_reverse;
  HANDLE  keyboard_handle;
  DWORD   prev_console_mode;
  
+ #ifndef USE_SEPARATE_SCREEN
+ CONSOLE_CURSOR_INFO prev_console_cursor;
+ #endif
+ 
  
  /* Setting this as the ctrl handler prevents emacs from being killed when
     someone hits ^C in a 'suspended' session (child shell).
***************
*** 90,96 ****
  BOOL
  ctrl_c_handler (unsigned long type)
  {
!   return (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT);
  }
  
  /* If we're updating a frame, use it as the current frame
--- 84,92 ----
  BOOL
  ctrl_c_handler (unsigned long type)
  {
!   /* Only ignore "interrupt" events when running interactively.  */
!   return (!noninteractive &&
! 	  (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT));
  }
  
  /* If we're updating a frame, use it as the current frame
***************
*** 453,472 ****
  
    return sound;
  }
- 
- /* Put our console back up, for ending a suspended session.  */
- void
- take_console (void)
- {
-   reset_kbd ();
-   SetConsoleActiveScreenBuffer (cur_screen);
- }
     
  void
  reset_terminal_modes (void)
  {
!   unset_kbd ();
    SetConsoleActiveScreenBuffer (prev_screen);
  }
  
  void
--- 449,464 ----
  
    return sound;
  }
     
  void
  reset_terminal_modes (void)
  {
! #ifdef USE_SEPARATE_SCREEN
    SetConsoleActiveScreenBuffer (prev_screen);
+ #else
+   SetConsoleCursorInfo (prev_screen, &prev_console_cursor);
+ #endif
+   SetConsoleMode (keyboard_handle, prev_console_mode);
  }
  
  void
***************
*** 474,502 ****
  {
    CONSOLE_CURSOR_INFO cci;
  
!   if (cur_screen == NULL)
!     {
!       reset_kbd ();
!       cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
!                                               0, NULL,
!                                               CONSOLE_TEXTMODE_BUFFER,
!                                               NULL);
  
!       if (cur_screen == INVALID_HANDLE_VALUE)
!         {
! 	  printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
! 	  printf ("LastError = 0x%lx\n", GetLastError ());
! 	  fflush (stdout);
! 	  exit (0);
! 	}
  
!       SetConsoleActiveScreenBuffer (cur_screen);
  
!       /* make cursor big and visible (100 on Win95 makes it disappear)  */
!       cci.dwSize = 99;
!       cci.bVisible = TRUE;
!       (void) SetConsoleCursorInfo (cur_screen, &cci);
!     }
  }
  
  /* hmmm... perhaps these let us bracket screen changes so that we can flush
--- 466,483 ----
  {
    CONSOLE_CURSOR_INFO cci;
  
!   /* make cursor big and visible (100 on Win95 makes it disappear)  */
!   cci.dwSize = 99;
!   cci.bVisible = TRUE;
!   (void) SetConsoleCursorInfo (cur_screen, &cci);
  
!   SetConsoleActiveScreenBuffer (cur_screen);
  
!   SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
  
!   /* Initialize input mode: interrupt_input off, no flow control, allow
!      8 bit character input, standard quit char.  */
!   Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
  }
  
  /* hmmm... perhaps these let us bracket screen changes so that we can flush
***************
*** 519,541 ****
  {
  }
  
- void
- unset_kbd (void)
- {
-   SetConsoleMode (keyboard_handle, prev_console_mode);
- }
- 
- void
- reset_kbd (void)
- {
-   keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
-   GetConsoleMode (keyboard_handle, &prev_console_mode);
-   SetConsoleMode (keyboard_handle, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
- 
-   /* Try to use interrupt input; if we can't, then start polling.  */
-   Fset_input_mode (Qt, Qnil, Qt, Qnil);
- }
- 
  typedef int (*term_hook) ();
  
  void
--- 500,505 ----
***************
*** 563,576 ****
    
    read_socket_hook = win32_read_socket;
    mouse_position_hook = win32_mouse_position;
!   
    prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
!   
!   set_terminal_modes ();
    
    GetConsoleScreenBufferInfo (cur_screen, &info);
    
-   meta_key = 1;
    char_attr = info.wAttributes & 0xFF;
    char_attr_normal = char_attr;
    char_attr_reverse = ((char_attr & 0xf) << 4) + ((char_attr & 0xf0) >> 4);
--- 527,559 ----
    
    read_socket_hook = win32_read_socket;
    mouse_position_hook = win32_mouse_position;
! 
!   /* Remember original console settings.  */
!   keyboard_handle = GetStdHandle (STD_INPUT_HANDLE);
!   GetConsoleMode (keyboard_handle, &prev_console_mode);
! 
    prev_screen = GetStdHandle (STD_OUTPUT_HANDLE);
! 
! #ifdef USE_SEPARATE_SCREEN
!   cur_screen = CreateConsoleScreenBuffer (GENERIC_READ | GENERIC_WRITE,
! 					  0, NULL,
! 					  CONSOLE_TEXTMODE_BUFFER,
! 					  NULL);
! 
!   if (cur_screen == INVALID_HANDLE_VALUE)
!     {
!       printf ("CreateConsoleScreenBuffer failed in ResetTerm\n");
!       printf ("LastError = 0x%lx\n", GetLastError ());
!       fflush (stdout);
!       exit (0);
!     }
! #else
!   cur_screen = prev_screen;
!   GetConsoleCursorInfo (prev_screen, &prev_console_cursor);
! #endif
    
    GetConsoleScreenBufferInfo (cur_screen, &info);
    
    char_attr = info.wAttributes & 0xFF;
    char_attr_normal = char_attr;
    char_attr_reverse = ((char_attr & 0xf) << 4) + ((char_attr & 0xf0) >> 4);
***************
*** 578,586 ****
    FRAME_HEIGHT (selected_frame) = info.dwSize.Y;	/* lines per page */
    FRAME_WIDTH (selected_frame) = info.dwSize.X;  /* characters per line */
    
!   move_cursor (0, 0);
    
!   clear_frame ();
  }
  
  DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
--- 561,569 ----
    FRAME_HEIGHT (selected_frame) = info.dwSize.Y;	/* lines per page */
    FRAME_WIDTH (selected_frame) = info.dwSize.X;  /* characters per line */
    
! //  move_cursor (0, 0);
    
! //  clear_frame ();
  }
  
  DEFUN ("set-screen-color", Fset_screen_color, Sset_screen_color, 2, 2, 0,
diff -c pretest/src/sysdep.c.orig pretest/src/sysdep.c
*** pretest/src/sysdep.c.orig	Tue Jul 16 23:34:45 1996
--- pretest/src/sysdep.c	Mon Jul 14 14:12:04 1997
***************
*** 792,799 ****
        pid = _spawnlp (_P_WAIT, sh, sh, NULL);
        if (pid == -1)
  	write (1, "Can't execute subshell", 22);
- 
-       take_console ();
  #else   /* not WINDOWSNT */
        execlp (sh, sh, 0);
        write (1, "Can't execute subshell", 22);
--- 792,797 ----
***************
*** 1500,1506 ****
  #ifdef HAVE_WINDOW_SYSTEM
    /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
       needs the initialization code below.  */
!   if (! read_socket_hook && EQ (Vwindow_system, Qnil))
  #endif
      set_terminal_modes ();
  
--- 1498,1510 ----
  #ifdef HAVE_WINDOW_SYSTEM
    /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
       needs the initialization code below.  */
!   if (
! #ifndef WINDOWSNT
!       /* When running in tty mode on NT/Win95, we have a read_socket
! 	 hook, but still need the rest of the initialization code below.  */
!       ! read_socket_hook &&
! #endif
!       EQ (Vwindow_system, Qnil))
  #endif
      set_terminal_modes ();
  
***************
*** 1643,1649 ****
  #ifdef HAVE_WINDOW_SYSTEM
    /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
       needs the clean-up code below.  */
!   if (read_socket_hook || !EQ (Vwindow_system, Qnil))
      return;
  #endif
    cursor_to (FRAME_HEIGHT (selected_frame) - 1, 0);
--- 1647,1659 ----
  #ifdef HAVE_WINDOW_SYSTEM
    /* Emacs' window system on MSDOG uses the `internal terminal' and therefore
       needs the clean-up code below.  */
!   if (
! #ifndef WINDOWSNT
!       /* When running in tty mode on NT/Win95, we have a read_socket
! 	 hook, but still need the rest of the clean-up code below.  */
!       read_socket_hook ||
! #endif
!       !EQ (Vwindow_system, Qnil))
      return;
  #endif
    cursor_to (FRAME_HEIGHT (selected_frame) - 1, 0);
diff -c pretest/src/termhooks.h.orig pretest/src/termhooks.h
*** pretest/src/termhooks.h.orig	Wed May  8 01:03:29 1996
--- pretest/src/termhooks.h	Mon Jul 14 14:12:04 1997
***************
*** 234,239 ****
--- 234,250 ----
  				   the mouse click occurred in.
  				   .timestamp gives a timestamp (in
  				   milliseconds) for the click.  */
+ #ifdef WINDOWSNT
+   mouse_wheel,			/* .code gives the delta.
+ 				   .modifiers holds the state of the
+ 				   modifier keys.
+ 				   .x and .y give the mouse position,
+ 				   in characters, within the window.
+ 				   .frame_or_window gives the frame
+ 				   the wheel event occurred in.
+ 				   .timestamp gives a timestamp (in
+ 				   milliseconds) for the wheel event.  */
+ #endif
    scroll_bar_click,		/* .code gives the number of the mouse button
  				   that was clicked.
  				   .modifiers holds the state of the modifier
***************
*** 284,289 ****
--- 295,301 ----
    /* For an ascii_keystroke, this is the character.
       For a non_ascii_keystroke, this is the keysym code.
       For a mouse event, this is the button number.  */
+   /* In WindowsNT, for a mouse wheel event, this is the delta.  */
    int code;
    enum scroll_bar_part part;
  
diff -c pretest/src/unexnt.c.orig pretest/src/unexnt.c
*** pretest/src/unexnt.c.orig	Fri May  3 19:30:52 1996
--- pretest/src/unexnt.c	Mon Jul 14 14:12:06 1997
***************
*** 21,66 ****
     Geoff Voelker (voelker@cs.washington.edu)                         8-12-94
  */
  
  #include <stdlib.h> 	/* _fmode */
  #include <stdio.h>
  #include <fcntl.h>
  #include <windows.h>
  
  extern BOOL ctrl_c_handler (unsigned long type);
  
  #include "ntheap.h"
  
! /* A convenient type for keeping all the info about a mapped file together.  */
! typedef struct file_data {
!     char          *name;
!     unsigned long  size;
!     HANDLE         file;
!     HANDLE         file_mapping;
!     unsigned char *file_base;
! } file_data;
  
  /* Basically, our "initialized" flag.  */
! BOOL need_to_recreate_heap = FALSE;
  
  /* So we can find our heap in the file to recreate it.  */
! unsigned long heap_index_in_executable = 0;
! 
! void open_input_file (file_data *p_file, char *name);
! void open_output_file (file_data *p_file, char *name, unsigned long size);
! void close_file_data (file_data *p_file);
  
  void get_section_info (file_data *p_file);
  void copy_executable_and_dump_data_section (file_data *, file_data *);
  void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
  
  /* Cached info about the .data section in the executable.  */
! PUCHAR data_start_va = 0;
! DWORD  data_start_file = 0;
! DWORD  data_size = 0;
  
  /* Cached info about the .bss section in the executable.  */
! PUCHAR bss_start = 0;
! DWORD  bss_size = 0;
  
  #ifdef HAVE_NTGUI
  HINSTANCE hinst = NULL;
--- 21,78 ----
     Geoff Voelker (voelker@cs.washington.edu)                         8-12-94
  */
  
+ #include <config.h>
+ 
  #include <stdlib.h> 	/* _fmode */
  #include <stdio.h>
  #include <fcntl.h>
+ #include <time.h>
  #include <windows.h>
  
+ /* Include relevant definitions from IMAGEHLP.H, which can be found
+    in \\win32sdk\mstools\samples\image\include\imagehlp.h. */
+ 
+ PIMAGE_NT_HEADERS
+ (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress,
+ 				    DWORD FileLength,
+ 				    LPDWORD HeaderSum,
+ 				    LPDWORD CheckSum);
+ 
  extern BOOL ctrl_c_handler (unsigned long type);
  
+ extern char my_begdata[];
+ extern char my_edata[];
+ extern char my_begbss[];
+ extern char my_endbss[];
+ extern char *my_begbss_static;
+ extern char *my_endbss_static;
+ 
  #include "ntheap.h"
  
! enum {
!   HEAP_UNINITIALIZED = 1,
!   HEAP_UNLOADED,
!   HEAP_LOADED
! };
  
  /* Basically, our "initialized" flag.  */
! int heap_state = HEAP_UNINITIALIZED;
  
  /* So we can find our heap in the file to recreate it.  */
! unsigned long heap_index_in_executable = UNINIT_LONG;
  
  void get_section_info (file_data *p_file);
  void copy_executable_and_dump_data_section (file_data *, file_data *);
  void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile);
  
  /* Cached info about the .data section in the executable.  */
! PUCHAR data_start_va = UNINIT_PTR;
! DWORD  data_start_file = UNINIT_LONG;
! DWORD  data_size = UNINIT_LONG;
  
  /* Cached info about the .bss section in the executable.  */
! PUCHAR bss_start = UNINIT_PTR;
! DWORD  bss_size = UNINIT_LONG;
  
  #ifdef HAVE_NTGUI
  HINSTANCE hinst = NULL;
***************
*** 78,83 ****
--- 90,102 ----
  {
    extern void mainCRTStartup (void);
  
+ #if 0
+   /* Give us a way to debug problems with crashes on startup when
+      running under the MSVC profiler. */
+   if (GetEnvironmentVariable ("EMACS_DEBUG", NULL, 0) > 0)
+     DebugBreak ();
+ #endif
+ 
    /* Cache system info, e.g., the NT page size.  */
    cache_system_info ();
  
***************
*** 86,92 ****
       start up.  (WARNING:  Do not put any code before this section
       that relies upon malloc () and runs in the dumped version.  It
       won't work.)  */
!   if (need_to_recreate_heap) 
      {
        char executable_path[MAX_PATH];
  
--- 105,111 ----
       start up.  (WARNING:  Do not put any code before this section
       that relies upon malloc () and runs in the dumped version.  It
       won't work.)  */
!   if (heap_state == HEAP_UNLOADED) 
      {
        char executable_path[MAX_PATH];
  
***************
*** 95,102 ****
  	  printf ("Failed to find path for executable.\n");
  	  exit (1);
  	}
        recreate_heap (executable_path);
!       need_to_recreate_heap = FALSE;
      }
  
    /* The default behavior is to treat files as binary and patch up
--- 114,147 ----
  	  printf ("Failed to find path for executable.\n");
  	  exit (1);
  	}
+ 
+ #if 1
+       /* To allow profiling, make sure executable_path names the .exe
+ 	 file, not the ._xe file created by the profiler which contains
+ 	 extra code that makes the stored exe offsets incorrect.  (This
+ 	 will not be necessary when unexec properly extends the .bss (or
+ 	 .data as appropriate) section to include the dumped bss data,
+ 	 and dumps the heap into a proper section of its own.)  */
+       {
+ 	char * p = strrchr (executable_path, '.');
+ 	if (p && p[1] == '_')
+ 	  p[1] = 'e';
+       }
+ 
+       /* Using HiProf profiler, exe name is different still. */
+       {
+ 	char * p = strrchr (executable_path, '\\');
+ 	strcpy (p, "\\emacs.exe");
+       }
+ #endif
+ 
        recreate_heap (executable_path);
!       heap_state = HEAP_LOADED;
!     }
!   else
!     {
!       /* Grab our malloc arena space now, before CRT starts up. */
!       sbrk (0);
      }
  
    /* The default behavior is to treat files as binary and patch up
***************
*** 147,153 ****
    round_heap (get_allocation_unit ());
  
    /* Open the undumped executable file.  */
!   open_input_file (&in_file, in_filename);
  
    /* Get the interesting section info, like start and size of .bss...  */
    get_section_info (&in_file);
--- 192,203 ----
    round_heap (get_allocation_unit ());
  
    /* Open the undumped executable file.  */
!   if (!open_input_file (&in_file, in_filename))
!     {
!       printf ("Failed to open %s (%d)...bailing.\n", 
! 	      in_filename, GetLastError ());
!       exit (1);
!     }
  
    /* Get the interesting section info, like start and size of .bss...  */
    get_section_info (&in_file);
***************
*** 157,170 ****
    heap_index_in_executable = (unsigned long)
      round_to_next ((unsigned char *) in_file.size, get_allocation_unit ());
    size = heap_index_in_executable + get_committed_heap_size () + bss_size;
!   open_output_file (&out_file, out_filename, size);
  
    /* Set the flag (before dumping).  */
!   need_to_recreate_heap = TRUE;
  
    copy_executable_and_dump_data_section (&in_file, &out_file);
    dump_bss_and_heap (&in_file, &out_file);
  
    close_file_data (&in_file);
    close_file_data (&out_file);
  }
--- 207,254 ----
    heap_index_in_executable = (unsigned long)
      round_to_next ((unsigned char *) in_file.size, get_allocation_unit ());
    size = heap_index_in_executable + get_committed_heap_size () + bss_size;
!   if (!open_output_file (&out_file, out_filename, size))
!     {
!       printf ("Failed to open %s (%d)...bailing.\n", 
! 	      out_filename, GetLastError ());
!       exit (1);
!     }
  
    /* Set the flag (before dumping).  */
!   heap_state = HEAP_UNLOADED;
  
    copy_executable_and_dump_data_section (&in_file, &out_file);
    dump_bss_and_heap (&in_file, &out_file);
  
+   /* Patch up header fields; profiler is picky about this. */
+   {
+     PIMAGE_DOS_HEADER dos_header;
+     PIMAGE_NT_HEADERS nt_header;
+     HANDLE hImagehelp = LoadLibrary ("imagehlp.dll");
+     DWORD  headersum;
+     DWORD  checksum;
+ 
+     dos_header = (PIMAGE_DOS_HEADER) out_file.file_base;
+     nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
+ 
+     nt_header->OptionalHeader.CheckSum = 0;
+ //    nt_header->FileHeader.TimeDateStamp = time (NULL);
+ //    dos_header->e_cp = size / 512;
+ //    nt_header->OptionalHeader.SizeOfImage = size;
+ 
+     pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile");
+     if (pfnCheckSumMappedFile)
+       {
+ //	nt_header->FileHeader.TimeDateStamp = time (NULL);
+ 	pfnCheckSumMappedFile (out_file.file_base,
+ 			       out_file.size,
+ 			       &headersum,
+ 			       &checksum);
+ 	nt_header->OptionalHeader.CheckSum = checksum;
+       }
+     FreeLibrary (hImagehelp);
+   }
+ 
    close_file_data (&in_file);
    close_file_data (&out_file);
  }
***************
*** 173,179 ****
  /* File handling.  */
  
  
! void 
  open_input_file (file_data *p_file, char *filename)
  {
    HANDLE file;
--- 257,263 ----
  /* File handling.  */
  
  
! int
  open_input_file (file_data *p_file, char *filename)
  {
    HANDLE file;
***************
*** 184,266 ****
    file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
  		     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if (file == INVALID_HANDLE_VALUE) 
!       {
! 	printf ("Failed to open %s (%d)...bailing.\n", 
! 	       filename, GetLastError ());
! 	exit (1);
!       }
  
    size = GetFileSize (file, &upper_size);
    file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, 
  				    0, size, NULL);
    if (!file_mapping) 
!     {
!       printf ("Failed to create file mapping of %s (%d)...bailing.\n",
! 	     filename, GetLastError ());
!       exit (1);
!     }
  
    file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
    if (file_base == 0) 
!     {
!       printf ("Failed to map view of file of %s (%d)...bailing.\n",
! 	     filename, GetLastError ());
!       exit (1);
!     }
  
    p_file->name = filename;
    p_file->size = size;
    p_file->file = file;
    p_file->file_mapping = file_mapping;
    p_file->file_base = file_base;
  }
  
! void 
  open_output_file (file_data *p_file, char *filename, unsigned long size)
  {
    HANDLE file;
    HANDLE file_mapping;
    void  *file_base;
-   int    i;
  
    file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  		     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if (file == INVALID_HANDLE_VALUE) 
!     {
!       i = GetLastError ();
!       printf ("open_output_file: Failed to open %s (%d).\n", 
! 	     filename, i);
!       exit (1);
!     }
!   
    file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 
  				    0, size, NULL);
    if (!file_mapping) 
!     {
!       i = GetLastError ();
!       printf ("open_output_file: Failed to create file mapping of %s (%d).\n",
! 	     filename, i);
!       exit (1);
!     }
    
    file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
    if (file_base == 0) 
!     {
!       i = GetLastError ();
!       printf ("open_output_file: Failed to map view of file of %s (%d).\n",
! 	     filename, i);
!       exit (1);
!     }
    
    p_file->name = filename;
    p_file->size = size;
    p_file->file = file;
    p_file->file_mapping = file_mapping;
    p_file->file_base = file_base;
  }
  
  /* Close the system structures associated with the given file.  */
! static void
  close_file_data (file_data *p_file)
  {
      UnmapViewOfFile (p_file->file_base);
--- 268,326 ----
    file = CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
  		     OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if (file == INVALID_HANDLE_VALUE) 
!     return FALSE;
  
    size = GetFileSize (file, &upper_size);
    file_mapping = CreateFileMapping (file, NULL, PAGE_READONLY, 
  				    0, size, NULL);
    if (!file_mapping) 
!     return FALSE;
  
    file_base = MapViewOfFile (file_mapping, FILE_MAP_READ, 0, 0, size);
    if (file_base == 0) 
!     return FALSE;
  
    p_file->name = filename;
    p_file->size = size;
    p_file->file = file;
    p_file->file_mapping = file_mapping;
    p_file->file_base = file_base;
+ 
+   return TRUE;
  }
  
! int
  open_output_file (file_data *p_file, char *filename, unsigned long size)
  {
    HANDLE file;
    HANDLE file_mapping;
    void  *file_base;
  
    file = CreateFile (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  		     CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if (file == INVALID_HANDLE_VALUE) 
!     return FALSE;
! 
    file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, 
  				    0, size, NULL);
    if (!file_mapping) 
!     return FALSE;
    
    file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size);
    if (file_base == 0) 
!     return FALSE;
    
    p_file->name = filename;
    p_file->size = size;
    p_file->file = file;
    p_file->file_mapping = file_mapping;
    p_file->file_base = file_base;
+ 
+   return TRUE;
  }
  
  /* Close the system structures associated with the given file.  */
! void
  close_file_data (file_data *p_file)
  {
      UnmapViewOfFile (p_file->file_base);
***************
*** 310,328 ****
    *p_bss_size = (DWORD) len;
  }
  
! static unsigned long
  get_section_size (PIMAGE_SECTION_HEADER p_section)
  {
!   /* The section size is in different locations in the different versions.  */
!   switch (get_nt_minor_version ()) 
      {
!     case 10:
!       return p_section->SizeOfRawData;
!     default:
!       return p_section->Misc.VirtualSize;
      }
  }
  
  /* Flip through the executable and cache the info necessary for dumping.  */
  static void
  get_section_info (file_data *p_infile)
--- 370,423 ----
    *p_bss_size = (DWORD) len;
  }
  
! unsigned long
  get_section_size (PIMAGE_SECTION_HEADER p_section)
  {
!   /* The true section size, before rounding.  Some linkers swap the
!      meaning of these two values.  */
!   return min (p_section->SizeOfRawData,
! 	      p_section->Misc.VirtualSize);
! }
! 
! /* Return pointer to section header for named section. */
! IMAGE_SECTION_HEADER *
! find_section (char * name, IMAGE_NT_HEADERS * nt_header)
! {
!   PIMAGE_SECTION_HEADER section;
!   int i;
! 
!   section = IMAGE_FIRST_SECTION (nt_header);
! 
!   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
      {
!       if (strcmp (section->Name, name) == 0)
! 	return section;
!       section++;
      }
+   return NULL;
  }
  
+ /* Return pointer to section header for section containing the given
+    relative virtual address. */
+ IMAGE_SECTION_HEADER *
+ rva_to_section (DWORD rva, IMAGE_NT_HEADERS * nt_header)
+ {
+   PIMAGE_SECTION_HEADER section;
+   int i;
+ 
+   section = IMAGE_FIRST_SECTION (nt_header);
+ 
+   for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++)
+     {
+       if (rva >= section->VirtualAddress &&
+ 	  rva < section->VirtualAddress + section->SizeOfRawData)
+ 	return section;
+       section++;
+     }
+   return NULL;
+ }
+ 
+ 
  /* Flip through the executable and cache the info necessary for dumping.  */
  static void
  get_section_info (file_data *p_infile)
***************
*** 359,364 ****
--- 454,460 ----
    section = (PIMAGE_SECTION_HEADER) IMAGE_FIRST_SECTION (nt_header);
    for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) 
      {
+ #ifdef SEPARATE_BSS_SECTION
        if (!strcmp (section->Name, ".bss")) 
  	{
  	  /* The .bss section.  */
***************
*** 367,372 ****
--- 463,470 ----
  	  bss_start = ptr;
  	  bss_size = get_section_size (section);
  	}
+ #endif
+ #if 0
        if (!strcmp (section->Name, ".data")) 
  	{
  	  /* From lastfile.c  */
***************
*** 385,394 ****
  	     than the one Emacs was dumped on).  */
  	  data_size = my_edata - data_start_va;
  	}
        section++;
      }
  
!   if (!bss_start && !bss_size)
      {
        /* Starting with MSVC 4.0, the .bss section has been eliminated
  	 and appended virtually to the end of the .data section.  Our
--- 483,507 ----
  	     than the one Emacs was dumped on).  */
  	  data_size = my_edata - data_start_va;
  	}
+ #else
+       if (!strcmp (section->Name, "APPDATA")) 
+ 	{
+ 	  /* The Emacs initialized data section.  */
+ 	  data_section = section;
+ 	  ptr = (char *) nt_header->OptionalHeader.ImageBase +
+ 	    section->VirtualAddress;
+ 	  data_start_va = ptr;
+ 	  data_start_file = section->PointerToRawData;
+ 
+ 	  /* Write back the full section.  */
+ 	  data_size = get_section_size (section);
+ 	}
+ #endif
        section++;
      }
  
! #ifdef SEPARATE_BSS_SECTION
!   if (bss_start == UNINIT_PTR && bss_size == UNINIT_LONG)
      {
        /* Starting with MSVC 4.0, the .bss section has been eliminated
  	 and appended virtually to the end of the .data section.  Our
***************
*** 402,407 ****
--- 515,524 ----
        bss_start = ptr + nt_header->OptionalHeader.ImageBase
  	+ data_section->VirtualAddress;
      }
+ #else
+   bss_start = min (my_begbss, my_begbss_static);
+   bss_size = max (my_endbss, my_endbss_static) - bss_start;
+ #endif
  }
  
  
diff -c pretest/src/w32fns.c.orig pretest/src/w32fns.c
*** pretest/src/w32fns.c.orig	Tue Jul 16 06:10:12 1996
--- pretest/src/w32fns.c	Mon Jul 14 14:12:08 1997
***************
*** 20,28 ****
  
  /* Added by Kevin Gallo */
  
- #include <signal.h>
  #include <config.h>
  #include <stdio.h>
  
  #include "lisp.h"
  #include "w32term.h"
--- 20,31 ----
  
  /* Added by Kevin Gallo */
  
  #include <config.h>
+ 
+ #include <signal.h>
  #include <stdio.h>
+ #include <limits.h>
+ #include <errno.h>
  
  #include "lisp.h"
  #include "w32term.h"
***************
*** 174,180 ****
  
  /* The below are defined in frame.c.  */
  extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
! extern Lisp_Object Qunsplittable, Qmenu_bar_lines;
  
  extern Lisp_Object Vwindow_system_version;
  
--- 177,183 ----
  
  /* The below are defined in frame.c.  */
  extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
! extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
  
  extern Lisp_Object Vwindow_system_version;
  
***************
*** 536,564 ****
  void x_set_visibility ();
  void x_set_menu_bar_lines ();
  void x_set_scroll_bar_width ();
  void x_set_unsplittable ();
  
  static struct x_frame_parm_table x_frame_parms[] =
  {
!   "foreground-color", x_set_foreground_color,
    "background-color", x_set_background_color,
-   "mouse-color", x_set_mouse_color,
-   "cursor-color", x_set_cursor_color,
    "border-color", x_set_border_color,
    "cursor-type", x_set_cursor_type,
-   "icon-type", x_set_icon_type,
-   "icon-name", x_set_icon_name,
    "font", x_set_font,
!   "border-width", x_set_border_width,
    "internal-border-width", x_set_internal_border_width,
-   "name", x_explicitly_set_name,
-   "auto-raise", x_set_autoraise,
-   "auto-lower", x_set_autolower,
-   "vertical-scroll-bars", x_set_vertical_scroll_bars,
-   "visibility", x_set_visibility,
    "menu-bar-lines", x_set_menu_bar_lines,
    "scroll-bar-width", x_set_scroll_bar_width,
    "unsplittable", x_set_unsplittable,
  };
  
  /* Attach the `x-frame-parameter' properties to
--- 539,569 ----
  void x_set_visibility ();
  void x_set_menu_bar_lines ();
  void x_set_scroll_bar_width ();
+ void x_set_title ();
  void x_set_unsplittable ();
  
  static struct x_frame_parm_table x_frame_parms[] =
  {
!   "auto-raise", x_set_autoraise,
!   "auto-lower", x_set_autolower,
    "background-color", x_set_background_color,
    "border-color", x_set_border_color,
+   "border-width", x_set_border_width,
+   "cursor-color", x_set_cursor_color,
    "cursor-type", x_set_cursor_type,
    "font", x_set_font,
!   "foreground-color", x_set_foreground_color,
!   "icon-name", x_set_icon_name,
!   "icon-type", x_set_icon_type,
    "internal-border-width", x_set_internal_border_width,
    "menu-bar-lines", x_set_menu_bar_lines,
+   "mouse-color", x_set_mouse_color,
+   "name", x_explicitly_set_name,
    "scroll-bar-width", x_set_scroll_bar_width,
+   "title", x_set_title,
    "unsplittable", x_set_unsplittable,
+   "vertical-scroll-bars", x_set_vertical_scroll_bars,
+   "visibility", x_set_visibility,
  };
  
  /* Attach the `x-frame-parameter' properties to
***************
*** 1245,1250 ****
--- 1250,1412 ----
    register Lisp_Object tail, ret = Qnil;
    
    BLOCK_INPUT;
+ 
+   if (colorname[0] == '#')
+     {
+       /* Could be an old-style RGB Device specification.  */
+       char *color;
+       int size;
+       color = colorname + 1;
+       
+       size = strlen(color);
+       if (size == 3 || size == 6 || size == 9 || size == 12)
+ 	{
+ 	  UINT colorval;
+ 	  int i, pos;
+ 	  pos = 0;
+ 	  size /= 3;
+ 	  colorval = 0;
+ 	  
+ 	  for (i = 0; i < 3; i++)
+ 	    {
+ 	      char *end;
+ 	      char t;
+ 	      unsigned long value;
+ 
+ 	      /* The check for 'x' in the following conditional takes into
+ 		 account the fact that strtol allows a "0x" in front of
+ 		 our numbers, and we don't.  */
+ 	      if (!isxdigit(color[0]) || color[1] == 'x')
+ 		break;
+ 	      t = color[size];
+ 	      color[size] = '\0';
+ 	      value = strtoul(color, &end, 16);
+ 	      color[size] = t;
+ 	      if (errno == ERANGE || end - color != size)
+ 		break;
+ 	      switch (size)
+ 		{
+ 		case 1:
+ 		  value = value * 0x10;
+ 		  break;
+ 		case 2:
+ 		  break;
+ 		case 3:
+ 		  value /= 0x10;
+ 		  break;
+ 		case 4:
+ 		  value /= 0x100;
+ 		  break;
+ 		}
+ 	      colorval |= (value << pos);
+ 	      pos += 0x8;
+ 	      if (i == 2)
+ 		{
+ 		  UNBLOCK_INPUT;
+ 		  return (colorval);
+ 		}
+ 	      color = end;
+ 	    }
+ 	}
+     }
+   else if (strnicmp(colorname, "rgb:", 4) == 0)
+     {
+       char *color;
+       UINT colorval;
+       int i, pos;
+       pos = 0;
+ 
+       colorval = 0;
+       color = colorname + 4;
+       for (i = 0; i < 3; i++)
+ 	{
+ 	  char *end;
+ 	  unsigned long value;
+ 	  
+ 	  /* The check for 'x' in the following conditional takes into
+ 	     account the fact that strtol allows a "0x" in front of
+ 	     our numbers, and we don't.  */
+ 	  if (!isxdigit(color[0]) || color[1] == 'x')
+ 	    break;
+ 	  value = strtoul(color, &end, 16);
+ 	  if (errno == ERANGE)
+ 	    break;
+ 	  switch (end - color)
+ 	    {
+ 	    case 1:
+ 	      value = value * 0x10 + value;
+ 	      break;
+ 	    case 2:
+ 	      break;
+ 	    case 3:
+ 	      value /= 0x10;
+ 	      break;
+ 	    case 4:
+ 	      value /= 0x100;
+ 	      break;
+ 	    default:
+ 	      value = ULONG_MAX;
+ 	    }
+ 	  if (value == ULONG_MAX)
+ 	    break;
+ 	  colorval |= (value << pos);
+ 	  pos += 0x8;
+ 	  if (i == 2)
+ 	    {
+ 	      if (*end != '\0')
+ 		break;
+ 	      UNBLOCK_INPUT;
+ 	      return (colorval);
+ 	    }
+ 	  if (*end != '/')
+ 	    break;
+ 	  color = end + 1;
+ 	}
+     }
+   else if (strnicmp(colorname, "rgbi:", 5) == 0)
+     {
+       /* This is an RGB Intensity specification.  */
+       char *color;
+       UINT colorval;
+       int i, pos;
+       pos = 0;
+ 
+       colorval = 0;
+       color = colorname + 5;
+       for (i = 0; i < 3; i++)
+ 	{
+ 	  char *end;
+ 	  double value;
+ 	  UINT val;
+ 
+ 	  value = strtod(color, &end);
+ 	  if (errno == ERANGE)
+ 	    break;
+ 	  if (value < 0.0 || value > 1.0)
+ 	    break;
+ 	  val = (UINT)(0x100 * value);
+ 	  /* We used 0x100 instead of 0xFF to give an continuous
+              range between 0.0 and 1.0 inclusive.  The next statement
+              fixes the 1.0 case.  */
+ 	  if (val == 0x100)
+ 	    val = 0xFF;
+ 	  colorval |= (val << pos);
+ 	  pos += 0x8;
+ 	  if (i == 2)
+ 	    {
+ 	      if (*end != '\0')
+ 		break;
+ 	      UNBLOCK_INPUT;
+ 	      return (colorval);
+ 	    }
+ 	  if (*end != '/')
+ 	    break;
+ 	  color = end + 1;
+ 	}
+     }
+   /* I am not going to attempt to handle any of the CIE color schemes
+      or TekHVC, since I don't know the algorithms for conversion to
+      RGB.  */
    
    for (tail = Vwin32_color_map; !NILP (tail); tail = Fcdr (tail))
      {
***************
*** 1827,1834 ****
    BLOCK_INPUT;
  
    result = x_text_icon (f,
! 			 (char *) XSTRING ((!NILP (f->icon_name)
  					   ? f->icon_name
  					   : f->name))->data);
  
    if (result)
--- 1989,1998 ----
    BLOCK_INPUT;
  
    result = x_text_icon (f,
! 			(char *) XSTRING ((!NILP (f->icon_name)
  					   ? f->icon_name
+ 					   : !NILP (f->title)
+ 					   ? f->title
  					   : f->name))->data);
  
    if (result)
***************
*** 1965,1970 ****
--- 2129,2139 ----
        if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
  	free_frame_menubar (f);
        FRAME_EXTERNAL_MENU_BAR (f) = 0;
+ 
+       /* Adjust the frame size so that the client (text) dimensions
+ 	 remain the same.  This depends on FRAME_EXTERNAL_MENU_BAR being
+ 	 set correctly.  */
+       x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
      }
  }
  
***************
*** 2016,2029 ****
    if (! NILP (Fstring_equal (name, f->name)))
      return;
  
    if (FRAME_WIN32_WINDOW (f))
      {
        BLOCK_INPUT;
        SetWindowText(FRAME_WIN32_WINDOW (f), XSTRING (name)->data);
        UNBLOCK_INPUT;
      }
- 
-   f->name = name;
  }
  
  /* This function should be called when the user's lisp code has
--- 2185,2203 ----
    if (! NILP (Fstring_equal (name, f->name)))
      return;
  
+   f->name = name;
+ 
+   /* For setting the frame title, the title parameter should override
+      the name parameter.  */
+   if (! NILP (f->title))
+     name = f->title;
+ 
    if (FRAME_WIN32_WINDOW (f))
      {
        BLOCK_INPUT;
        SetWindowText(FRAME_WIN32_WINDOW (f), XSTRING (name)->data);
        UNBLOCK_INPUT;
      }
  }
  
  /* This function should be called when the user's lisp code has
***************
*** 2047,2054 ****
--- 2221,2263 ----
  {
    x_set_name (f, arg, 0);
  }
+ 
+ /* Change the title of frame F to NAME.
+    If NAME is nil, use the frame name as the title.
+ 
+    If EXPLICIT is non-zero, that indicates that lisp code is setting the
+        name; if NAME is a string, set F's name to NAME and set
+        F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
+ 
+    If EXPLICIT is zero, that indicates that Emacs redisplay code is
+        suggesting a new name, which lisp code should override; if
+        F->explicit_name is set, ignore the new name; otherwise, set it.  */
  
  void
+ x_set_title (f, name)
+      struct frame *f;
+      Lisp_Object name;
+ {
+   /* Don't change the title if it's already NAME.  */
+   if (EQ (name, f->title))
+     return;
+ 
+   update_mode_lines = 1;
+ 
+   f->title = name;
+ 
+   if (NILP (name))
+     name = f->name;
+ 
+   if (FRAME_WIN32_WINDOW (f))
+     {
+       BLOCK_INPUT;
+       SetWindowText(FRAME_WIN32_WINDOW (f), XSTRING (name)->data);
+       UNBLOCK_INPUT;
+     }
+ }
+ 
+ void
  x_set_autoraise (f, arg, oldval)
       struct frame *f;
       Lisp_Object arg, oldval;
***************
*** 2615,2620 ****
--- 2824,2837 ----
       struct frame *f;
  {
    HWND hwnd;
+   RECT rect;
+ 
+   rect.left = rect.top = 0;
+   rect.right = PIXEL_WIDTH (f);
+   rect.bottom = PIXEL_HEIGHT (f);
+       
+   AdjustWindowRect (&rect, f->output_data.win32->dwStyle,
+ 		    FRAME_EXTERNAL_MENU_BAR (f));
    
    /* Do first time app init */
    
***************
*** 2623,2644 ****
        win32_init_class (hinst);
      }
    
!   FRAME_WIN32_WINDOW (f) = hwnd = CreateWindow (EMACS_CLASS,
! 						f->namebuf,
! 						f->output_data.win32->dwStyle | WS_CLIPCHILDREN,
! 						f->output_data.win32->left_pos,
! 						f->output_data.win32->top_pos,
! 						PIXEL_WIDTH (f),
! 						PIXEL_HEIGHT (f),
! 						NULL,
! 						NULL,
! 						hinst,
! 						NULL);
    
    if (hwnd)
      {
!       SetWindowLong (hwnd, WND_X_UNITS_INDEX, FONT_WIDTH (f->output_data.win32->font));
!       SetWindowLong (hwnd, WND_Y_UNITS_INDEX, f->output_data.win32->line_height);
        SetWindowLong (hwnd, WND_BACKGROUND_INDEX, f->output_data.win32->background_pixel);
  
        /* Do this to discard the default setting specified by our parent. */
--- 2840,2864 ----
        win32_init_class (hinst);
      }
    
!   FRAME_WIN32_WINDOW (f) = hwnd
!     = CreateWindow (EMACS_CLASS,
! 		    f->namebuf,
! 		    f->output_data.win32->dwStyle | WS_CLIPCHILDREN,
! 		    f->output_data.win32->left_pos,
! 		    f->output_data.win32->top_pos,
! 		    rect.right - rect.left,
! 		    rect.bottom - rect.top,
! 		    NULL,
! 		    NULL,
! 		    hinst,
! 		    NULL);
    
    if (hwnd)
      {
!       SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.win32->font));
!       SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.win32->line_height);
!       SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.win32->internal_border_width);
!       SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.win32->vertical_scroll_bar_extra);
        SetWindowLong (hwnd, WND_BACKGROUND_INDEX, f->output_data.win32->background_pixel);
  
        /* Do this to discard the default setting specified by our parent. */
***************
*** 2882,2888 ****
    
    PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
    
!   PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
    
    while (GetMessage (&msg, NULL, 0, 0))
      {
--- 3102,3109 ----
    
    PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
    
!   if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
!     abort ();
    
    while (GetMessage (&msg, NULL, 0, 0))
      {
***************
*** 2892,2899 ****
  	    {
  	    case WM_EMACS_CREATEWINDOW:
  	      win32_createwindow ((struct frame *) msg.wParam);
! 	      PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0);
  	      break;
  	    case WM_EMACS_CREATESCROLLBAR:
  	      {
  		HWND hwnd = win32_createscrollbar ((struct frame *) msg.wParam,
--- 3113,3122 ----
  	    {
  	    case WM_EMACS_CREATEWINDOW:
  	      win32_createwindow ((struct frame *) msg.wParam);
! 	      if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
! 		abort ();
  	      break;
+ #if 0
  	    case WM_EMACS_CREATESCROLLBAR:
  	      {
  		HWND hwnd = win32_createscrollbar ((struct frame *) msg.wParam,
***************
*** 2901,2908 ****
  		PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, (WPARAM)hwnd, 0);
  	      }
  	      break;
! 	    case WM_EMACS_KILL:
! 	      return (0);
  	    }
  	}
        else
--- 3124,3132 ----
  		PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, (WPARAM)hwnd, 0);
  	      }
  	      break;
! #endif
! 	    default:
! 	      abort ();
  	    }
  	}
        else
***************
*** 2926,2932 ****
       LPARAM lParam;
  {
    struct frame *f;
-   LRESULT ret = 1;
    struct win32_display_info *dpyinfo = &one_win32_display_info;
    Win32Msg wmsg;
    int windows_translate;
--- 3150,3155 ----
***************
*** 3040,3063 ****
      case WM_CHAR:
        wmsg.dwModifiers = construct_modifiers (wParam, lParam);
  
-       enter_crit ();
-       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
- 
  #if 1
!       /* Detect quit_char and set quit-flag directly.  Note that we dow
!          this *after* posting the message to ensure the main thread will
!          be woken up if blocked in sys_select(). */
        {
  	int c = wParam;
  	if (isalpha (c) && (wmsg.dwModifiers == LEFT_CTRL_PRESSED 
  			    || wmsg.dwModifiers == RIGHT_CTRL_PRESSED))
  	  c = make_ctrl_char (c) & 0377;
  	if (c == quit_char)
! 	  Vquit_flag = Qt;
        }
  #endif
  
!       leave_crit ();
        break;
  
        /* Simulate middle mouse button events when left and right buttons
--- 3263,3293 ----
      case WM_CHAR:
        wmsg.dwModifiers = construct_modifiers (wParam, lParam);
  
  #if 1
!       /* Detect quit_char and set quit-flag directly.  Note that we
! 	 still need to post a message to ensure the main thread will be
! 	 woken up if blocked in sys_select(), but we do NOT want to post
! 	 the quit_char message itself (because it will usually be as if
! 	 the user had typed quit_char twice).  Instead, we post a dummy
! 	 message that has no particular effect. */
        {
  	int c = wParam;
  	if (isalpha (c) && (wmsg.dwModifiers == LEFT_CTRL_PRESSED 
  			    || wmsg.dwModifiers == RIGHT_CTRL_PRESSED))
  	  c = make_ctrl_char (c) & 0377;
  	if (c == quit_char)
! 	  {
! 	    Vquit_flag = Qt;
! 
! 	    /* The choice of message is somewhat arbitrary, as long as
! 	       the main thread handler just ignores it. */
! 	    msg = WM_NULL;
! 	  }
        }
  #endif
  
!       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
! 
        break;
  
        /* Simulate middle mouse button events when left and right buttons
***************
*** 3177,3187 ****
      handle_plain_button:
        {
  	BOOL up;
  
! 	if (parse_button (msg, NULL, &up))
  	  {
  	    if (up) ReleaseCapture ();
  	    else SetCapture (hwnd);
  	  }
        }
        
--- 3407,3424 ----
      handle_plain_button:
        {
  	BOOL up;
+ 	int button;
  
! 	if (parse_button (msg, &button, &up))
  	  {
  	    if (up) ReleaseCapture ();
  	    else SetCapture (hwnd);
+ 	    button = (button == 0) ? LMOUSE : 
+ 	      ((button == 1) ? MMOUSE  : RMOUSE);
+ 	    if (up)
+ 	      button_state &= ~button;
+ 	    else
+ 	      button_state |= button;
  	  }
        }
        
***************
*** 3218,3223 ****
--- 3455,3465 ----
    
        return 0;
  
+     case WM_MOUSEWHEEL:
+       wmsg.dwModifiers = win32_get_modifiers ();
+       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+       return 0;
+ 
      case WM_TIMER:
        /* Flush out saved messages if necessary. */
        if (wParam == mouse_button_timer)
***************
*** 3251,3262 ****
        reset_modifiers ();
        goto dflt;
  
      case WM_SETFOCUS:
        reset_modifiers ();
      case WM_KILLFOCUS:
      case WM_MOVE:
      case WM_SIZE:
-     case WM_SYSCOMMAND:
      case WM_COMMAND:
        wmsg.dwModifiers = win32_get_modifiers ();
        my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
--- 3493,3523 ----
        reset_modifiers ();
        goto dflt;
  
+ #if 0
+       /* Still not right - can't distinguish between clicks in the
+ 	 client area of the frame from clicks forwarded from the scroll
+ 	 bars - may have to hook WM_NCHITTEST to remember the mouse
+ 	 position and then check if it is in the client area ourselves.  */
+     case WM_MOUSEACTIVATE:
+       /* Discard the mouse click that activates a frame, allowing the
+ 	 user to click anywhere without changing point (or worse!).
+ 	 Don't eat mouse clicks on scrollbars though!!  */
+       if (LOWORD (lParam) == HTCLIENT )
+ 	return MA_ACTIVATEANDEAT;
+       goto dflt;
+ #endif
+ 
+     case WM_SHOWWINDOW:
+       /* Inform lisp thread that a frame might have just been obscured
+ 	 or exposed, so should recheck visibility of all frames.  */
+       my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
+       goto dflt;
+ 
      case WM_SETFOCUS:
        reset_modifiers ();
      case WM_KILLFOCUS:
      case WM_MOVE:
      case WM_SIZE:
      case WM_COMMAND:
        wmsg.dwModifiers = win32_get_modifiers ();
        my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
***************
*** 3271,3286 ****
        {
  	WINDOWPLACEMENT wp;
  	LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
! 	
  	GetWindowPlacement (hwnd, &wp);
  	
! 	if (wp.showCmd != SW_SHOWMINIMIZED && ! (lppos->flags & SWP_NOSIZE))
  	  {
  	    RECT rect;
  	    int wdiff;
  	    int hdiff;
! 	    DWORD dwXUnits;
! 	    DWORD dwYUnits;
  	    RECT wr;
  	    
  	    wp.length = sizeof(wp);
--- 3532,3550 ----
        {
  	WINDOWPLACEMENT wp;
  	LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
! 
! 	wp.length = sizeof (WINDOWPLACEMENT);
  	GetWindowPlacement (hwnd, &wp);
  	
! 	if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
  	  {
  	    RECT rect;
  	    int wdiff;
  	    int hdiff;
! 	    DWORD font_width;
! 	    DWORD line_height;
! 	    DWORD internal_border;
! 	    DWORD scrollbar_extra;
  	    RECT wr;
  	    
  	    wp.length = sizeof(wp);
***************
*** 3288,3295 ****
  	    
  	    enter_crit ();
  	    
! 	    dwXUnits = GetWindowLong (hwnd, WND_X_UNITS_INDEX);
! 	    dwYUnits = GetWindowLong (hwnd, WND_Y_UNITS_INDEX);
  	    
  	    leave_crit ();
  	    
--- 3552,3561 ----
  	    
  	    enter_crit ();
  	    
! 	    font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
! 	    line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
! 	    internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
! 	    scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
  	    
  	    leave_crit ();
  	    
***************
*** 3297,3306 ****
  	    AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE), 
  			      GetMenu (hwnd) != NULL);
  
! 	    /* All windows have an extra pixel so subtract 1 */
! 	    
! 	    wdiff = (lppos->cx - (rect.right - rect.left) - 0) % dwXUnits;
! 	    hdiff = (lppos->cy - (rect.bottom - rect.top) - 0) % dwYUnits;
  	    
  	    if (wdiff || hdiff)
  	      {
--- 3563,3576 ----
  	    AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE), 
  			      GetMenu (hwnd) != NULL);
  
! 	    /* Force width and height of client area to be exact
! 	       multiples of the character cell dimensions.  */
! 	    wdiff = (lppos->cx - (rect.right - rect.left)
! 		     - 2 * internal_border - scrollbar_extra)
! 	      % font_width;
! 	    hdiff = (lppos->cy - (rect.bottom - rect.top)
! 		     - 2 * internal_border)
! 	      % line_height;
  	    
  	    if (wdiff || hdiff)
  	      {
***************
*** 3312,3318 ****
  		lppos->cy -= hdiff;
  		
  		if (wp.showCmd != SW_SHOWMAXIMIZED 
! 		    && ! (lppos->flags & SWP_NOMOVE))
  		  {
  		    if (lppos->x != wr.left || lppos->y != wr.top)
  		      {
--- 3582,3588 ----
  		lppos->cy -= hdiff;
  		
  		if (wp.showCmd != SW_SHOWMAXIMIZED 
! 		    && (lppos->flags & SWP_NOMOVE) == 0)
  		  {
  		    if (lppos->x != wr.left || lppos->y != wr.top)
  		      {
***************
*** 3325,3355 ****
  		      }
  		  }
  		
! 		ret = 0;
  	      }
  	  }
        }
-     
-       if (ret == 0) return (0);
        
        goto dflt;
      case WM_EMACS_SHOWWINDOW:
!       return ShowWindow (hwnd, wParam);
      case WM_EMACS_SETWINDOWPOS:
        {
! 	Win32WindowPos * pos = (Win32WindowPos *) wParam;
! 	return SetWindowPos (hwnd, pos->hwndAfter,
  			     pos->x, pos->y, pos->cx, pos->cy, pos->flags);
        }
      case WM_EMACS_DESTROYWINDOW:
!       DestroyWindow ((HWND) wParam);
!       break;
      default:
      dflt:
        return DefWindowProc (hwnd, msg, wParam, lParam);
      }
!   
!   return (1);
  }
  
  void 
--- 3595,3675 ----
  		      }
  		  }
  		
! 		return 0;
  	      }
  	  }
        }
        
        goto dflt;
+ 
+     case WM_EMACS_CREATESCROLLBAR:
+       return win32_createscrollbar ((struct frame *) wParam,
+ 				    (struct scroll_bar *) lParam);
+ 
      case WM_EMACS_SHOWWINDOW:
!       return ShowWindow ((HWND) wParam, (WPARAM) lParam);
! 
      case WM_EMACS_SETWINDOWPOS:
        {
! 	WINDOWPOS * pos = (WINDOWPOS *) wParam;
! 	return SetWindowPos (hwnd, pos->hwndInsertAfter,
  			     pos->x, pos->y, pos->cx, pos->cy, pos->flags);
        }
+ 
      case WM_EMACS_DESTROYWINDOW:
!       return DestroyWindow ((HWND) wParam);
! 
!     case WM_EMACS_TRACKPOPUPMENU:
!       {
! 	UINT flags;
! 	POINT *pos;
! 	int retval;
! 	pos = (POINT *)lParam;
! 	flags = TPM_CENTERALIGN;
! 	if (button_state & LMOUSE)
! 	  flags |= TPM_LEFTBUTTON;
! 	else if (button_state & RMOUSE)
! 	  flags |= TPM_RIGHTBUTTON;
! 	
! 	if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y, 
! 			    0, hwnd, NULL))
! 	  {
! 	    MSG amsg;
! 	    /* Eat any mouse messages during popupmenu */
! 	    while (PeekMessage(&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
! 			       PM_REMOVE));
! 	    /* Get the menu selection, if any */
! 	    if (PeekMessage(&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
! 	      {
! 		retval =  LOWORD(amsg.wParam);
! 	      }
! 	    else
! 	      {
! 		retval = 0;
! 	      }
! 	    button_state = 0;
! 
! 	    /* Remember we did a SetCapture on the initial mouse down
! 	       event, but window focus will usually have changed to the
! 	       popup menu before we released the mouse button.  For
! 	       safety, we make sure the capture is cancelled now.  */
! 	    ReleaseCapture ();
! 	  }
! 	else
! 	  {
! 	    retval = -1;
! 	  }
! 
! 	return retval;
!       }
! 
      default:
      dflt:
        return DefWindowProc (hwnd, msg, wParam, lParam);
      }
! 
!   /* The most common default return code for handled messages is 0.  */
!   return 0;
  }
  
  void 
***************
*** 3358,3364 ****
  {
    MSG msg;
  
!   PostThreadMessage (dwWinThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0);
    GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
  }
  
--- 3678,3685 ----
  {
    MSG msg;
  
!   if (!PostThreadMessage (dwWinThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
!     abort ();
    GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
  }
  
***************
*** 3439,3444 ****
--- 3760,3777 ----
    if (! EQ (icon_x, Qunbound))
      x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
  
+ #if 0 /* TODO */
+   /* Start up iconic or window? */
+   x_wm_set_window_state
+     (f, (EQ (x_get_arg (parms, Qvisibility, 0, 0, symbol), Qicon)
+ 	 ? IconicState
+ 	 : NormalState));
+ 
+   x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
+ 				     ? f->icon_name
+ 				     : f->name))->data);
+ #endif
+ 
    UNBLOCK_INPUT;
  }
  
***************
*** 3463,3469 ****
    long window_prompting = 0;
    int width, height;
    int count = specpdl_ptr - specpdl;
!   struct gcpro gcpro1;
    Lisp_Object display;
    struct win32_display_info *dpyinfo;
    Lisp_Object parent;
--- 3796,3802 ----
    long window_prompting = 0;
    int width, height;
    int count = specpdl_ptr - specpdl;
!   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
    Lisp_Object display;
    struct win32_display_info *dpyinfo;
    Lisp_Object parent;
***************
*** 3483,3489 ****
    kb = &the_only_kboard;
  #endif
  
!   name = x_get_arg (parms, Qname, "title", "Title", string);
    if (!STRINGP (name)
        && ! EQ (name, Qunbound)
        && ! NILP (name))
--- 3816,3822 ----
    kb = &the_only_kboard;
  #endif
  
!   name = x_get_arg (parms, Qname, "name", "Name", string);
    if (!STRINGP (name)
        && ! EQ (name, Qunbound)
        && ! NILP (name))
***************
*** 3499,3504 ****
--- 3832,3842 ----
    if (! NILP (parent))
      CHECK_NUMBER (parent, 0);
  
+   /* make_frame_without_minibuffer can run Lisp code and garbage collect.  */
+   /* No need to protect DISPLAY because that's not used after passing
+      it to make_frame_without_minibuffer.  */
+   frame = Qnil;
+   GCPRO4 (parms, parent, name, frame);
    tem = x_get_arg (parms, Qminibuffer, 0, 0, symbol);
    if (EQ (tem, Qnone) || NILP (tem))
      f = make_frame_without_minibuffer (Qnil, kb, display);
***************
*** 3512,3529 ****
    else
      f = make_frame (1);
  
    /* Note that Windows does support scroll bars.  */
    FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
    /* By default, make scrollbars the system standard width. */
    f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
  
-   XSETFRAME (frame, f);
-   GCPRO1 (frame);
- 
    f->output_method = output_win32;
    f->output_data.win32 = (struct win32_output *) xmalloc (sizeof (struct win32_output));
    bzero (f->output_data.win32, sizeof (struct win32_output));
  
  /*  FRAME_WIN32_DISPLAY_INFO (f) = dpyinfo; */
  #ifdef MULTI_KBOARD
    FRAME_KBOARD (f) = kb;
--- 3850,3871 ----
    else
      f = make_frame (1);
  
+   XSETFRAME (frame, f);
+ 
    /* Note that Windows does support scroll bars.  */
    FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
    /* By default, make scrollbars the system standard width. */
    f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
  
    f->output_method = output_win32;
    f->output_data.win32 = (struct win32_output *) xmalloc (sizeof (struct win32_output));
    bzero (f->output_data.win32, sizeof (struct win32_output));
  
+   f->icon_name
+     = x_get_arg (parms, Qicon_name, "iconName", "Title", string);
+   if (! STRINGP (f->icon_name))
+     f->icon_name = Qnil;
+ 
  /*  FRAME_WIN32_DISPLAY_INFO (f) = dpyinfo; */
  #ifdef MULTI_KBOARD
    FRAME_KBOARD (f) = kb;
***************
*** 3570,3596 ****
      /* First, try whatever font the caller has specified.  */
      if (STRINGP (font))
        font = x_new_font (f, XSTRING (font)->data);
- #if 0
      /* Try out a font which we hope has bold and italic variations.  */
      if (!STRINGP (font))
!       font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
      if (! STRINGP (font))
!       font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
!     if (! STRINGP (font))
!       /* This was formerly the first thing tried, but it finds too many fonts
! 	 and takes too long.  */
!       font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
      /* If those didn't work, look for something which will at least work.  */
      if (! STRINGP (font))
!       font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
!     if (! STRINGP (font))
!       font = x_new_font (f, "-*-system-medium-r-normal-*-*-200-*-*-c-120-*-*");
! #endif
!     if (! STRINGP (font))
!       font = x_new_font (f, "-*-Fixedsys-*-r-*-*-12-90-*-*-c-*-*-*");
      UNBLOCK_INPUT;
      if (! STRINGP (font))
!       font = build_string ("-*-system");
  
      x_default_parameter (f, parms, Qfont, font, 
  			 "font", "Font", string);
--- 3912,3928 ----
      /* First, try whatever font the caller has specified.  */
      if (STRINGP (font))
        font = x_new_font (f, XSTRING (font)->data);
      /* Try out a font which we hope has bold and italic variations.  */
      if (!STRINGP (font))
!       font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-97-*-*-c-*-*-ansi-");
      if (! STRINGP (font))
!       font = x_new_font (f, "-*-Courier-normal-r-*-*-13-97-*-*-c-*-*-ansi-");
      /* If those didn't work, look for something which will at least work.  */
      if (! STRINGP (font))
!       font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-13-97-*-*-c-*-*-ansi-");
      UNBLOCK_INPUT;
      if (! STRINGP (font))
!       font = build_string ("Fixedsys");
  
      x_default_parameter (f, parms, Qfont, font, 
  			 "font", "Font", string);
***************
*** 3611,3616 ****
--- 3943,3949 ----
  	parms = Fcons (Fcons (Qinternal_border_width, value),
  		       parms);
      }
+   /* Default internalBorderWidth to 0 on Windows to match other programs.  */
    x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
  		       "internalBorderWidth", "BorderWidth", number);
    x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
***************
*** 3632,3637 ****
--- 3965,3974 ----
  		       "menuBar", "MenuBar", number);
    x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
  		       "scrollBarWidth", "ScrollBarWidth", number);
+   x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
+ 		       "bufferPredicate", "BufferPredicate", symbol);
+   x_default_parameter (f, parms, Qtitle, Qnil,
+ 		       "title", "Title", string);
  
    f->output_data.win32->dwStyle = WS_OVERLAPPEDWINDOW;
    f->output_data.win32->parent_desc = FRAME_WIN32_DISPLAY_INFO (f)->root_window;
***************
*** 3896,3901 ****
--- 4233,4239 ----
    else if (stricmp (lpw,"extrabold") == 0)    return FW_EXTRABOLD;
    else if (stricmp (lpw,"bold") == 0)         return FW_BOLD;
    else if (stricmp (lpw,"demibold") == 0)     return FW_SEMIBOLD;
+   else if (stricmp (lpw,"semibold") == 0)     return FW_SEMIBOLD;
    else if (stricmp (lpw,"medium") == 0)       return FW_MEDIUM;
    else if (stricmp (lpw,"normal") == 0)       return FW_NORMAL;
    else if (stricmp (lpw,"light") == 0)        return FW_LIGHT;
***************
*** 3937,3950 ****
    else if (stricmp (lpcs,"unicode") == 0)       return UNICODE_CHARSET;
    else if (stricmp (lpcs,"iso10646") == 0)      return UNICODE_CHARSET;
  #endif
    else
!     return 0;
  }
  
  char *
  win32_to_x_charset (fncharset)
      int fncharset;
  {
    switch (fncharset)
      {
      case ANSI_CHARSET:     return "ansi";
--- 4275,4291 ----
    else if (stricmp (lpcs,"unicode") == 0)       return UNICODE_CHARSET;
    else if (stricmp (lpcs,"iso10646") == 0)      return UNICODE_CHARSET;
  #endif
+   else if (lpcs[0] == '#')			return atoi (lpcs + 1);
    else
!     return DEFAULT_CHARSET;
  }
  
  char *
  win32_to_x_charset (fncharset)
      int fncharset;
  {
+   static char buf[16];
+ 
    switch (fncharset)
      {
      case ANSI_CHARSET:     return "ansi";
***************
*** 3954,3960 ****
      case UNICODE_CHARSET:  return "unicode";
  #endif
      }
!   return "*";
  }
  
  BOOL 
--- 4295,4303 ----
      case UNICODE_CHARSET:  return "unicode";
  #endif
      }
!   /* Encode numerical value of unknown charset.  */
!   sprintf (buf, "#%u", fncharset);
!   return buf;
  }
  
  BOOL 
***************
*** 4194,4201 ****
      int FontType;
      enumfont_t * lpef;
  {
!   if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline
!       || (lplf->elfLogFont.lfCharSet != ANSI_CHARSET && lplf->elfLogFont.lfCharSet != OEM_CHARSET))
      return (1);
    
    /*    if (!lpef->size_ref || lptm->tmMaxCharWidth == FONT_WIDTH (lpef->size_ref)) */
--- 4537,4543 ----
      int FontType;
      enumfont_t * lpef;
  {
!   if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
      return (1);
    
    /*    if (!lpef->size_ref || lptm->tmMaxCharWidth == FONT_WIDTH (lpef->size_ref)) */
***************
*** 4427,4435 ****
      {
        Lisp_Object rgb[3];
  
!       rgb[0] = make_number (GetRValue (foo));
!       rgb[1] = make_number (GetGValue (foo));
!       rgb[2] = make_number (GetBValue (foo));
        return Flist (3, rgb);
      }
    else
--- 4769,4777 ----
      {
        Lisp_Object rgb[3];
  
!       rgb[0] = make_number ((GetRValue (foo) << 8) | GetRValue (foo));
!       rgb[1] = make_number ((GetGValue (foo) << 8) | GetGValue (foo));
!       rgb[2] = make_number ((GetBValue (foo) << 8) | GetBValue (foo));
        return Flist (3, rgb);
      }
    else
***************
*** 4744,4749 ****
--- 5086,5094 ----
  
    CHECK_STRING (name, 0);
  
+   if (! EQ (Vwindow_system, intern ("win32")))
+     error ("Not using Microsoft Windows");
+ 
    for (dpyinfo = &one_win32_display_info, names = win32_display_name_list;
         dpyinfo;
         dpyinfo = dpyinfo->next, names = XCONS (names)->cdr)
***************
*** 4786,4791 ****
--- 5131,5139 ----
    CHECK_STRING (display, 0);
    if (! NILP (xrm_string))
      CHECK_STRING (xrm_string, 1);
+ 
+   if (! EQ (Vwindow_system, intern ("win32")))
+     error ("Not using Microsoft Windows");
  
    /* Allow color mapping to be defined externally; first look in user's
       HOME directory, then in Emacs etc dir for a file called rgb.txt. */
diff -c pretest/src/w32menu.c.orig pretest/src/w32menu.c
*** pretest/src/w32menu.c.orig	Tue May 21 19:09:46 1996
--- pretest/src/w32menu.c	Mon Jul 14 14:12:10 1997
***************
*** 79,84 ****
--- 79,85 ----
  /* Initialize the menu_items structure if we haven't already done so.
     Also mark it as currently empty.  */
  
+ #if 0
  static void 
  init_menu_items (lpmm)
       menu_map * lpmm;
***************
*** 93,109 ****
    lpmm->menu_items_used = 0;
  }
  
- /* Call when finished using the data for the current menu
-    in menu_items.  */
- 
- static void 
- discard_menu_items (lpmm)
-      menu_map * lpmm;
- {
-   lpmm->menu_items = Qnil;
-   lpmm->menu_items_allocated = lpmm->menu_items_used = 0;
- }
- 
  /* Make the menu_items vector twice as large.  */
  
  static void 
--- 94,99 ----
***************
*** 120,125 ****
--- 110,148 ----
    
    lpmm->menu_items = new;
  }
+ #endif
+ 
+ /* Call when finished using the data for the current menu
+    in menu_items.  */
+ 
+ static void 
+ discard_menu_items (lpmm)
+      menu_map * lpmm;
+ {
+ #if 0
+   lpmm->menu_items = Qnil;
+ #endif
+   lpmm->menu_items_allocated = lpmm->menu_items_used = 0;
+ }
+ 
+ /* Is this item a separator? */
+ static int
+ name_is_separator (name)
+      Lisp_Object name;
+ {
+   int isseparator = (((char *)XSTRING (name)->data)[0] == 0);
+ 
+   if (!isseparator)
+     {
+       /* Check if name string consists of only dashes ('-') */
+       char *string = (char *)XSTRING (name)->data;
+       while (*string == '-') string++;
+       isseparator = (*string == 0);
+     }
+ 
+   return isseparator;
+ }
+ 
  
  /* Indicate boundary between left and right.  */
  
***************
*** 137,164 ****
     of the keyboard equivalent for this item (or nil if none).  */
  
  static void 
! add_menu_item (lpmm, hmenu, name, enable, key)
       menu_map * lpmm;
       HMENU hmenu;
       Lisp_Object name;
       UINT enable;
       Lisp_Object key;
  {
    UINT fuFlags;
    
!   if (NILP (name) 
!       || ((char *) XSTRING (name)->data)[0] == 0
!       || strcmp ((char *) XSTRING (name)->data, "--") == 0)
      fuFlags = MF_SEPARATOR;
!   else if (enable)
!     fuFlags = MF_STRING;
!   else
!     fuFlags = MF_STRING | MF_GRAYED;
!   
    AppendMenu (hmenu,
  	      fuFlags,
  	      lpmm->menu_items_used + 1,
! 	      (fuFlags == MF_SEPARATOR)?NULL: (char *) XSTRING (name)->data);
    
    lpmm->menu_items_used++;
  #if 0
--- 160,199 ----
     of the keyboard equivalent for this item (or nil if none).  */
  
  static void 
! add_menu_item (lpmm, hmenu, name, enable, key, equiv)
       menu_map * lpmm;
       HMENU hmenu;
       Lisp_Object name;
       UINT enable;
       Lisp_Object key;
+      Lisp_Object equiv;
  {
    UINT fuFlags;
+   Lisp_Object out_string;
    
!   if (NILP (name) || name_is_separator (name))
      fuFlags = MF_SEPARATOR;
!   else 
!     {
!       if (enable)
! 	fuFlags = MF_STRING;
!       else
! 	fuFlags = MF_STRING | MF_GRAYED;
! 
!       if (!NILP (equiv))
! 	{
! 	  out_string = concat2 (name, make_string ("\t", 1));
! 	  out_string = concat2 (out_string, equiv);
! 	}
!       else
! 	out_string = name;
!     }
! 
    AppendMenu (hmenu,
  	      fuFlags,
  	      lpmm->menu_items_used + 1,
! 	      (fuFlags == MF_SEPARATOR)?NULL: 
! 	      (char *) XSTRING (out_string)->data);
    
    lpmm->menu_items_used++;
  #if 0
***************
*** 316,331 ****
       int notreal;
  {
    int mapno;
!   
!   //    init_menu_items (lpmm);
!   
    if (nmaps > 1) 
      {
        HMENU hmenu;
        
        if (!notreal) 
  	{
! 	  hmenu = CreateMenu ();
  	    
  	  if (!hmenu) return (NULL);
  	} 
--- 351,368 ----
       int notreal;
  {
    int mapno;
! 
! #if 0  
!   init_menu_items (lpmm);
! #endif  
! 
    if (nmaps > 1) 
      {
        HMENU hmenu;
        
        if (!notreal) 
  	{
! 	  hmenu = CreatePopupMenu ();
  	    
  	  if (!hmenu) return (NULL);
  	} 
***************
*** 376,386 ****
    Lisp_Object pending_maps;
    Lisp_Object tail, item, item1, item_string, table;
    HMENU hmenu;
!   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
    
    if (!notreal) 
      {
!       hmenu = CreateMenu ();
        if (hmenu == NULL) return NULL;
      } 
    else 
--- 413,423 ----
    Lisp_Object pending_maps;
    Lisp_Object tail, item, item1, item_string, table;
    HMENU hmenu;
!   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
    
    if (!notreal) 
      {
!       hmenu = CreatePopupMenu ();
        if (hmenu == NULL) return NULL;
      } 
    else 
***************
*** 427,433 ****
  		  GCPRO4 (keymap, pending_maps, def, prefix);
  		  
  		  def = menu_item_equiv_key (item_string, item1, &descrip);
! 		  enabled = menu_item_enabled_p (def, notreal);
  		    
  		  UNGCPRO;
  		  
--- 464,475 ----
  		  GCPRO4 (keymap, pending_maps, def, prefix);
  		  
  		  def = menu_item_equiv_key (item_string, item1, &descrip);
! 		  {
! 		    struct gcpro gcpro1;
! 		    GCPRO1 (descrip);
! 		    enabled = menu_item_enabled_p (def, notreal);
! 		    UNGCPRO;
! 		  }
  		    
  		  UNGCPRO;
  		  
***************
*** 445,451 ****
  		    {
  		      Lisp_Object submap;
  
! 		      GCPRO4 (keymap, pending_maps, item, item_string);
  		      
  		      submap = get_keymap_1 (def, 0, 1);
  		      
--- 487,493 ----
  		    {
  		      Lisp_Object submap;
  
! 		      GCPRO5 (keymap, pending_maps, item, item_string, descrip);
  		      
  		      submap = get_keymap_1 (def, 0, 1);
  		      
***************
*** 459,465 ****
  					     hmenu,
  					     item_string,
  					     !NILP (enabled),
! 					     Fcons (XCONS (item)->car, prefix));
  			    }
  			}
  		      else
--- 501,508 ----
  					     hmenu,
  					     item_string,
  					     !NILP (enabled),
! 					     Fcons (XCONS (item)->car, prefix),
! 					     descrip);
  			    }
  			}
  		      else
***************
*** 510,520 ****
  			 aside from that, must protect whatever might be
  			 a string.  Since there's no GCPRO5, we refetch
  			 item_string instead of protecting it.  */
! 		      GCPRO4 (keymap, pending_maps, def, descrip);
  		      descrip = def = Qnil;
  		      
  		      def = menu_item_equiv_key (item_string, item1, &descrip);
! 		      enabled = menu_item_enabled_p (def, notreal);
  		      
  		      UNGCPRO;
  		      
--- 553,568 ----
  			 aside from that, must protect whatever might be
  			 a string.  Since there's no GCPRO5, we refetch
  			 item_string instead of protecting it.  */
! 		      GCPRO3 (keymap, pending_maps, def);
  		      descrip = def = Qnil;
  		      
  		      def = menu_item_equiv_key (item_string, item1, &descrip);
! 		      {
! 		        struct gcpro gcpro1;
! 		        GCPRO1 (descrip);
! 		        enabled = menu_item_enabled_p (def, notreal);
! 		        UNGCPRO;
! 		      }
  		      
  		      UNGCPRO;
  		      
***************
*** 528,534 ****
  			{
  			  Lisp_Object submap;
  			  
! 			  GCPRO4 (keymap, pending_maps, descrip, item_string);
  			    
  			  submap = get_keymap_1 (def, 0, 1);
  			  
--- 576,582 ----
  			{
  			  Lisp_Object submap;
  			  
! 			  GCPRO5 (keymap, pending_maps, descrip, item_string, descrip);
  			    
  			  submap = get_keymap_1 (def, 0, 1);
  			  
***************
*** 542,548 ****
  						 hmenu,
  						 item_string,
  						 !NILP (enabled),
! 						 character);
  				}
  			    }
  			  else
--- 590,597 ----
  						 hmenu,
  						 item_string,
  						 !NILP (enabled),
! 						 character,
! 						 descrip);
  				}
  			    }
  			  else
***************
*** 609,637 ****
    Lisp_Object tail;
    HMENU hmenu;
    
!   hmenu = CreateMenu ();
!   if (hmenu == NULL) return NULL;
    
!   //    init_menu_items (lpmm);
    
!   for (tail = menu; !NILP (tail); tail = Fcdr (tail))
      {
        Lisp_Object elt, pane_name, pane_data;
!       HMENU new_hmenu;
! 
!       elt = Fcar (tail);
        pane_name = Fcar (elt);
        CHECK_STRING (pane_name, 0);
        pane_data = Fcdr (elt);
        CHECK_CONS (pane_data, 0);
! 
!       new_hmenu = list_of_items (lpmm, pane_data);
!       if (new_hmenu == NULL) goto error;
! 
!       AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu,
! 		  (char *) XSTRING (pane_name)->data);
      }
- 
    return (hmenu);
    
   error:
--- 658,706 ----
    Lisp_Object tail;
    HMENU hmenu;
    
!   if (XFASTINT (Flength (menu)) > 1)
!     {
!       hmenu = CreatePopupMenu ();
!       if (hmenu == NULL) return NULL;
    
! /*       init_menu_items (lpmm); */
    
!       for (tail = menu; !NILP (tail); tail = Fcdr (tail))
! 	{
! 	  Lisp_Object elt, pane_name, pane_data;
! 	  HMENU new_hmenu;
! 
! 	  elt = Fcar (tail);
! 	  pane_name = Fcar (elt);
! 	  CHECK_STRING (pane_name, 0);
! 	  pane_data = Fcdr (elt);
! 	  CHECK_CONS (pane_data, 0);
! 
! 	  if (XSTRING (pane_name)->data[0] == 0)
! 	    {
! 	      list_of_items (hmenu, lpmm, pane_data);
! 	    }
! 	  else
! 	    {
! 	      new_hmenu = list_of_items (NULL, lpmm, pane_data);
! 	      if (new_hmenu == NULL) goto error;
! 
! 	      AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu,
! 		          (char *) XSTRING (pane_name)->data);
! 	    }
! 	}
!     }
!   else
      {
        Lisp_Object elt, pane_name, pane_data;
!     
!       elt = Fcar (menu);
        pane_name = Fcar (elt);
        CHECK_STRING (pane_name, 0);
        pane_data = Fcdr (elt);
        CHECK_CONS (pane_data, 0);
!       hmenu = list_of_items (NULL, lpmm, pane_data);
      }
    return (hmenu);
    
   error:
***************
*** 643,663 ****
  /* Push the items in a single pane defined by the alist PANE.  */
  
  static HMENU 
! list_of_items (lpmm, pane)
       menu_map * lpmm;
       Lisp_Object pane;
  {
    Lisp_Object tail, item, item1;
-   HMENU hmenu;
  
!   hmenu = CreateMenu ();
!   if (hmenu == NULL) return NULL;
  
    for (tail = pane; !NILP (tail); tail = Fcdr (tail))
      {
        item = Fcar (tail);
        if (STRINGP (item))
! 	add_menu_item (lpmm, hmenu, item, Qnil, Qnil);
        else if (NILP (item))
  	add_left_right_boundary ();
        else
--- 712,735 ----
  /* Push the items in a single pane defined by the alist PANE.  */
  
  static HMENU 
! list_of_items (hmenu, lpmm, pane)
!      HMENU hmenu;
       menu_map * lpmm;
       Lisp_Object pane;
  {
    Lisp_Object tail, item, item1;
  
!   if (hmenu == NULL)
!     {
!       hmenu = CreatePopupMenu ();
!       if (hmenu == NULL) return NULL;
!     }
  
    for (tail = pane; !NILP (tail); tail = Fcdr (tail))
      {
        item = Fcar (tail);
        if (STRINGP (item))
! 	add_menu_item (lpmm, hmenu, item, 0, Qnil, Qnil);
        else if (NILP (item))
  	add_left_right_boundary ();
        else
***************
*** 665,671 ****
  	  CHECK_CONS (item, 0);
  	  item1 = Fcar (item);
  	  CHECK_STRING (item1, 1);
! 	  add_menu_item (lpmm, hmenu, item1, Qt, Fcdr (item));
  	}
      }
  
--- 737,743 ----
  	  CHECK_CONS (item, 0);
  	  item1 = Fcar (item);
  	  CHECK_STRING (item1, 1);
! 	  add_menu_item (lpmm, hmenu, item1, 1, Fcdr (item), Qnil);
  	}
      }
  
***************
*** 770,776 ****
  {
    Lisp_Object pending_maps;
    Lisp_Object tail, item, item1, item_string, table;
!   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
    
    pending_maps = Qnil;
    
--- 842,848 ----
  {
    Lisp_Object pending_maps;
    Lisp_Object tail, item, item1, item_string, table;
!   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
    
    pending_maps = Qnil;
    
***************
*** 828,834 ****
  		    {
  		      Lisp_Object submap;
  		      
! 		      GCPRO4 (keymap, pending_maps, item, item_string);
  		      
  		      submap = get_keymap_1 (def, 0, 1);
  		      
--- 900,906 ----
  		    {
  		      Lisp_Object submap;
  		      
! 		      GCPRO5 (keymap, pending_maps, item, item_string, descrip);
  		      
  		      submap = get_keymap_1 (def, 0, 1);
  		      
***************
*** 887,893 ****
  			 aside from that, must protect whatever might be
  			 a string.  Since there's no GCPRO5, we refetch
  			 item_string instead of protecting it.  */
! 		      GCPRO4 (keymap, pending_maps, def, descrip);
  		      descrip = def = Qnil;
  
  		      def = menu_item_equiv_key (item_string, item1, &descrip);
--- 959,965 ----
  			 aside from that, must protect whatever might be
  			 a string.  Since there's no GCPRO5, we refetch
  			 item_string instead of protecting it.  */
! 		      GCPRO3 (keymap, pending_maps, def);
  		      descrip = def = Qnil;
  
  		      def = menu_item_equiv_key (item_string, item1, &descrip);
***************
*** 904,910 ****
  			{
  			  Lisp_Object submap;
  			  
! 			  GCPRO4 (keymap, pending_maps, descrip, item_string);
  			  
  			  submap = get_keymap_1 (def, 0, 1);
  			    
--- 976,982 ----
  			{
  			  Lisp_Object submap;
  			  
! 			  GCPRO5 (keymap, pending_maps, descrip, item_string, descrip);
  			  
  			  submap = get_keymap_1 (def, 0, 1);
  			    
***************
*** 1062,1068 ****
    Lisp_Object event;
      
    /* Decode the menu items from what was specified.  */
!     
    keymap = Fkeymapp (menu);
    tem = Qnil;
    if (XTYPE (menu) == Lisp_Cons)
--- 1134,1141 ----
    Lisp_Object event;
      
    /* Decode the menu items from what was specified.  */
! 
! 
    keymap = Fkeymapp (menu);
    tem = Qnil;
    if (XTYPE (menu) == Lisp_Cons)
***************
*** 1072,1078 ****
      {
        keymap = get_keymap (menu);
  	
!       event = get_keymap_event (menu, 1, lpnum);
      }
    else if (!NILP (tem))
      {
--- 1145,1151 ----
      {
        keymap = get_keymap (menu);
  	
!       event = get_keymap_event (&keymap, 1, lpnum);
      }
    else if (!NILP (tem))
      {
***************
*** 1161,1167 ****
  	  unsigned long time;
  	  
  	  if (mouse_position_hook)
! 	    (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
  	  if (new_f != 0)
  	    XSETFRAME (window, new_f);
  	  else
--- 1234,1241 ----
  	  unsigned long time;
  	  
  	  if (mouse_position_hook)
! 	    (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, 
! 				    &time);
  	  if (new_f != 0)
  	    XSETFRAME (window, new_f);
  	  else
***************
*** 1240,1246 ****
    /* Display them in a menu.  */
    BLOCK_INPUT;
    
!   selection = win32menu_show (f, xpos, ypos, menu, &hmenu, &error_name);
    
    UNBLOCK_INPUT;
    
--- 1314,1320 ----
    /* Display them in a menu.  */
    BLOCK_INPUT;
    
!   selection = win32menu_show (f, xpos, ypos, menu, hmenu, &error_name);
    
    UNBLOCK_INPUT;
    
***************
*** 1366,1380 ****
    
    for (i = 0; i < XVECTOR (items)->size; i += 4)
      {
!       Lisp_Object event;
! 	
!       event = get_menu_event (XVECTOR (items)->contents[i + 2], &num);
  
!       if (num <= 0)
  	{
! 	  UNGCPRO;
! 	  UNBLOCK_INPUT;
! 	  return (Fcons (XVECTOR (items)->contents[i], event));
  	}
      }
    
--- 1440,1480 ----
    
    for (i = 0; i < XVECTOR (items)->size; i += 4)
      {
!       Lisp_Object event, binding;
!       binding = XVECTOR (items)->contents[i + 2];
  
!       /* Check to see if this might be a menubar button.  It might be
!          if it is not a keymap, it is a cons cell, its car is not a
!          keymap, and its cdr is nil.  */
!       if (NILP (Fkeymapp (binding))
! 	  && CONSP (binding)
! 	  && NILP (Fkeymapp (XCONS (binding)->car))
! 	  && NILP (XCONS (binding)->cdr))
! 	{
! 	  /* The fact that we have to check that this is a string here
!              is the reason we don't do all this rigamarole in
!              get_menu_event.  */
! 	  if (XTYPE (XVECTOR (items)->contents[i + 1]) == Lisp_String)
! 	    {
! 	      /* This was a menubar button.  */
! 	      if (--num <= 0)
! 		{
! 		  UNGCPRO;
! 		  UNBLOCK_INPUT;
! 		  return (Fcons (XVECTOR (items)->contents[i], Qnil));
! 		}
! 	    }
! 	}
!       else
  	{
! 	  event = get_menu_event (binding, &num);
! 
! 	  if (num <= 0)
! 	    {
! 	      UNGCPRO;
! 	      UNBLOCK_INPUT;
! 	      return (Fcons (XVECTOR (items)->contents[i], event));
! 	    }
  	}
      }
    
***************
*** 1392,1398 ****
    Lisp_Object tail, items;
    HMENU hmenu;
    int i;
!   struct gcpro gcpro1;
    menu_map mm;
    int count = specpdl_ptr - specpdl;
  
--- 1492,1498 ----
    Lisp_Object tail, items;
    HMENU hmenu;
    int i;
!   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
    menu_map mm;
    int count = specpdl_ptr - specpdl;
  
***************
*** 1439,1445 ****
  
    for (i = 0; i < XVECTOR (items)->size; i += 4)
      {
!       Lisp_Object string;
        int keymaps;
        CHAR *error;
        HMENU new_hmenu;
--- 1539,1545 ----
  
    for (i = 0; i < XVECTOR (items)->size; i += 4)
      {
!       Lisp_Object string, binding;
        int keymaps;
        CHAR *error;
        HMENU new_hmenu;
***************
*** 1447,1466 ****
        string = XVECTOR (items)->contents[i + 1];
        if (NILP (string))
  	break;
        
!       /* Input must not be blocked here
! 	 because we call general Lisp code and internal_condition_case_1.  */
!       new_hmenu = create_menu_items (&mm,
! 				     XVECTOR (items)->contents[i + 2],
! 				     0);
!       
!       if (!new_hmenu)
! 	continue;
        
!       BLOCK_INPUT;
!       AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu,
! 		  (char *) XSTRING (string)->data);
!       UNBLOCK_INPUT;
      }
    
    BLOCK_INPUT;
--- 1547,1590 ----
        string = XVECTOR (items)->contents[i + 1];
        if (NILP (string))
  	break;
+ 
+       binding = XVECTOR (items)->contents[i + 2];
+ 
+       if (NILP (Fkeymapp (binding))
+ 	  && CONSP (binding)
+ 	  && NILP (Fkeymapp (XCONS (binding)->car))
+ 	  && NILP (XCONS (binding)->cdr))
+ 	{
+ 	  /* This is a menubar button.  */
+ 	  Lisp_Object descrip, def;
+ 	  Lisp_Object enabled, item;
+ 	  item = Fcons (string, Fcar (binding));
+ 	  descrip = def = Qnil;
+ 	  UNGCPRO;
+ 	  GCPRO4 (items, item, def, string);
+ 
+ 	  def = menu_item_equiv_key (string, item, &descrip);
+ 	  enabled = menu_item_enabled_p (def, 0);
+ 
+ 	  UNGCPRO;
+ 	  GCPRO1 (items);
+ 
+ 	  add_menu_item (&mm, hmenu, string, enabled, def, Qnil);
+ 	}
+       else
+ 	{
+ 	  /* Input must not be blocked here because we call general
+ 	     Lisp code and internal_condition_case_1.  */
+ 	  new_hmenu = create_menu_items (&mm, binding, 0);
        
! 	  if (!new_hmenu)
! 	    continue;
        
! 	  BLOCK_INPUT;
! 	  AppendMenu (hmenu, MF_POPUP, (UINT)new_hmenu,
! 		      (char *) XSTRING (string)->data);
! 	  UNBLOCK_INPUT;
! 	}
      }
    
    BLOCK_INPUT;
***************
*** 1468,1473 ****
--- 1592,1603 ----
      HMENU old = GetMenu (FRAME_WIN32_WINDOW (f));
      SetMenu (FRAME_WIN32_WINDOW (f), hmenu);
      DestroyMenu (old);
+ 
+     /* Force the window size to be recomputed so that the frame's text
+        area remains the same, if menubar has just been created.  */
+     if (old == NULL)
+       
+ x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
    }
    
   error:
***************
*** 1517,1523 ****
    Lisp_Object x, y;
    unsigned long time;
  
!   (*mouse_position_hook) (&new_f, &bar_window, &part, &x, &y, &time);
  
    if (f == new_f && other_menu_bar_item_p (f, x, y))
      {
--- 1647,1653 ----
    Lisp_Object x, y;
    unsigned long time;
  
!   (*mouse_position_hook) (&new_f, 1, &bar_window, &part, &x, &y, &time);
  
    if (f == new_f && other_menu_bar_item_p (f, x, y))
      {
***************
*** 1588,1594 ****
      
      if (!hmenu || strcmp (pane_string, ""))
        {
! 	HMENU new_hmenu = CreateMenu ();
  	
  	if (!new_hmenu) 
  	  {
--- 1718,1724 ----
      
      if (!hmenu || strcmp (pane_string, ""))
        {
! 	HMENU new_hmenu = CreatePopupMenu ();
  	
  	if (!new_hmenu) 
  	  {
***************
*** 1618,1627 ****
      enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
      //	  descrip = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
  
!     if (((char *) XSTRING (item_name)->data)[0] == 0
! 	|| strcmp ((char *) XSTRING (item_name)->data, "--") == 0)
        fuFlags = MF_SEPARATOR;
!     else if (NILP (enable) || !XUINT(enable))
        fuFlags = MF_STRING | MF_GRAYED;
      else
        fuFlags = MF_STRING;
--- 1748,1756 ----
      enable = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_ENABLE];
      //	  descrip = XVECTOR (menu_items)->contents[i + MENU_ITEMS_ITEM_EQUIV_KEY];
  
!     if (name_is_separator (item_name))
        fuFlags = MF_SEPARATOR;
!     else if (NILP (enable) || !XUINT (enable))
        fuFlags = MF_STRING | MF_GRAYED;
      else
        fuFlags = MF_STRING;
***************
*** 1699,1725 ****
        return Qnil;
      }
  #endif
!   
    /* Display the menu.  */
!   menu_selection = TrackPopupMenu (hmenu,
! 				   0x10,
! 				   pos.x, pos.y,
! 				   0,
! 				   FRAME_WIN32_WINDOW (f),
! 				   NULL);
    if (menu_selection == -1)
      {
        *error = "Invalid menu specification";
        return Qnil;
      }
!   
    /* Find the selected item, and its pane, to return
       the proper value.  */
    
  #if 1
    if (menu_selection > 0)
      {
!       return get_menu_event (menu, menu_selection);
      }
  #else
    if (menu_selection > 0 && menu_selection <= lpmm->menu_items_used)
--- 1828,1857 ----
        return Qnil;
      }
  #endif
! 
    /* Display the menu.  */
! 
!   menu_selection = SendMessage (FRAME_WIN32_WINDOW (f), 
! 				WM_EMACS_TRACKPOPUPMENU,
! 				(WPARAM)hmenu, (LPARAM)&pos);
! 
!   /* Clean up extraneous mouse events which might have been generated
!      during the call. */
!   eat_mouse_events ();
! 
    if (menu_selection == -1)
      {
        *error = "Invalid menu specification";
        return Qnil;
      }
! 
    /* Find the selected item, and its pane, to return
       the proper value.  */
    
  #if 1
    if (menu_selection > 0)
      {
!       return get_menu_event (menu, &menu_selection);
      }
  #else
    if (menu_selection > 0 && menu_selection <= lpmm->menu_items_used)
***************
*** 1727,1733 ****
        return (XVECTOR (lpmm->menu_items)->contents[menu_selection - 1]);
      }
  #endif
!   
    return Qnil;
  }
  
--- 1859,1865 ----
        return (XVECTOR (lpmm->menu_items)->contents[menu_selection - 1]);
      }
  #endif
! 
    return Qnil;
  }
  
diff -c pretest/src/w32term.c.orig pretest/src/w32term.c
*** pretest/src/w32term.c.orig	Sat Jul 20 19:04:01 1996
--- pretest/src/w32term.c	Tue Jul 22 14:59:19 1997
***************
*** 26,32 ****
  #include "lisp.h"
  #include "blockinput.h"
  
! #include <w32term.h>
  
  #include "systty.h"
  #include "systime.h"
--- 26,32 ----
  #include "lisp.h"
  #include "blockinput.h"
  
! #include "w32term.h"
  
  #include "systty.h"
  #include "systime.h"
***************
*** 94,99 ****
--- 94,131 ----
  DWORD dwMainThreadId = 0;
  HANDLE hMainThread = NULL;
  
+ #ifndef SIF_ALL
+ /* These definitions are new with Windows 95. */
+ #define SIF_RANGE           0x0001
+ #define SIF_PAGE            0x0002
+ #define SIF_POS             0x0004
+ #define SIF_DISABLENOSCROLL 0x0008
+ #define SIF_TRACKPOS        0x0010
+ #define SIF_ALL             (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS)
+ 
+ typedef struct tagSCROLLINFO
+ {
+     UINT    cbSize;
+     UINT    fMask;
+     int     nMin;
+     int     nMax;
+     UINT    nPage;
+     int     nPos;
+     int     nTrackPos;
+ }   SCROLLINFO, FAR *LPSCROLLINFO;
+ typedef SCROLLINFO CONST FAR *LPCSCROLLINFO;
+ #endif /* SIF_ALL */
+ 
+ /* Dynamic linking to new proportional scroll bar functions. */
+ int (PASCAL *pfnSetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi, BOOL fRedraw);
+ BOOL (PASCAL *pfnGetScrollInfo) (HWND hwnd, int fnBar, LPSCROLLINFO lpsi);
+ 
+ int vertical_scroll_bar_min_handle;
+ int vertical_scroll_bar_top_border;
+ int vertical_scroll_bar_bottom_border;
+ 
+ int last_scroll_bar_drag_pos;
+ 
  /* Mouse movement. */
  
  /* Where the mouse was last time we reported a mouse event.  */
***************
*** 323,328 ****
--- 355,361 ----
  win32_frame_up_to_date (f)
       FRAME_PTR f;
  {
+   BLOCK_INPUT;
    if (FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_deferred_gc
        || f == FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_mouse_frame)
      {
***************
*** 331,336 ****
--- 364,370 ----
  			    FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_mouse_y);
        FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_deferred_gc = 0;
      }
+   UNBLOCK_INPUT;
  }
  
  /* External interface to control of standout mode.
***************
*** 872,885 ****
  	i = j+1;
        }
  
-   release_frame_dc (f, hdc);
- 
    for (i = 0; i < ht; ++i)
      if (line_dance[i] == -1)
        {
  	for (j = i; j < ht && line_dance[j] == -1; ++j);
  	/* Clear [i,j) */
! 	win32_clear_area (f, NULL,
  			  intborder, 
  			  CHAR_TO_PIXEL_ROW (f, i),
  			  f->width * FONT_WIDTH (f->output_data.win32->font),
--- 906,917 ----
  	i = j+1;
        }
  
    for (i = 0; i < ht; ++i)
      if (line_dance[i] == -1)
        {
  	for (j = i; j < ht && line_dance[j] == -1; ++j);
  	/* Clear [i,j) */
! 	win32_clear_area (f, hdc,
  			  intborder, 
  			  CHAR_TO_PIXEL_ROW (f, i),
  			  f->width * FONT_WIDTH (f->output_data.win32->font),
***************
*** 887,892 ****
--- 919,926 ----
  	i = j-1;
        }
    line_dance_in_progress = 0;
+ 
+   release_frame_dc (f, hdc);
  }
  
  /* Support routines for exposure events.  */
***************
*** 1262,1267 ****
--- 1296,1320 ----
    }
  }
  
+ static void
+ construct_mouse_wheel (result, msg, f)
+      struct input_event *result;
+      Win32Msg *msg;
+      struct frame *f;
+ {
+   POINT p;
+   result->kind = mouse_wheel;
+   result->code = (short) HIWORD (msg->msg.wParam);
+   result->timestamp = msg->msg.time;
+   result->modifiers = msg->dwModifiers;
+   p.x = LOWORD (msg->msg.lParam);
+   p.y = HIWORD (msg->msg.lParam);
+   ScreenToClient(msg->msg.hwnd, &p);
+   XSETINT (result->x, p.x);
+   XSETINT (result->y, p.y);
+   XSETFRAME (result->frame_or_window, f);
+ }
+ 
  
  /* Function to report a mouse movement to the mainstream Emacs code.
     The input handler calls this.
***************
*** 1602,1609 ****
        /* If the cursor's in the text we are about to rewrite,
  	 turn the cursor off.  */
        if (i == curs_y
! 	  && curs_x >= FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_beg_col - 1
! 	  && curs_x <= FRAME_WIN32_DISPLAY_INFO (f)->mouse_face_end_col)
  	{
  	  x_display_cursor (f, 0);
  	  cursor_off = 1;
--- 1655,1662 ----
        /* If the cursor's in the text we are about to rewrite,
  	 turn the cursor off.  */
        if (i == curs_y
! 	  && curs_x >= column - 1
! 	  && curs_x <= endcolumn)
  	{
  	  x_display_cursor (f, 0);
  	  cursor_off = 1;
***************
*** 1686,1691 ****
--- 1739,1745 ----
    BLOCK_INPUT;
  
    if (! NILP (last_mouse_scroll_bar))
+     /* This is never called at the moment.  */
      x_scroll_bar_report_motion (fp, bar_window, part, x, y, time);
    else
      {
***************
*** 1799,1804 ****
--- 1853,1859 ----
       struct frame * f;
       struct scroll_bar * bar;
  {
+ #if 0
    MSG msg;
    
    PostThreadMessage (dwWinThreadId, WM_EMACS_CREATESCROLLBAR, (WPARAM) f, 
***************
*** 1806,1832 ****
    GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
    
    return ((HWND) msg.wParam);
  }
  
  //#define ATTACH_THREADS
  
! void
! my_show_window (HWND hwnd, int how)
  {
  #ifndef ATTACH_THREADS
!   SendMessage (hwnd, WM_EMACS_SHOWWINDOW, (WPARAM) how, 0);
  #else
!   ShowWindow (hwnd , how);
  #endif
  }
  
  void
  my_set_window_pos (HWND hwnd, HWND hwndAfter,
! 		   int x, int y, int cx, int cy, int flags)
  {
  #ifndef ATTACH_THREADS
!   Win32WindowPos pos;
!   pos.hwndAfter = hwndAfter;
    pos.x = x;
    pos.y = y;
    pos.cx = cx;
--- 1861,1893 ----
    GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
    
    return ((HWND) msg.wParam);
+ #else
+   return (HWND) SendMessage (FRAME_WIN32_WINDOW (f),
+ 			     WM_EMACS_CREATESCROLLBAR, (WPARAM) f, 
+ 			     (LPARAM) bar);
+ #endif
  }
  
  //#define ATTACH_THREADS
  
! BOOL
! my_show_window (FRAME_PTR f, HWND hwnd, int how)
  {
  #ifndef ATTACH_THREADS
!   return SendMessage (FRAME_WIN32_WINDOW (f), WM_EMACS_SHOWWINDOW,
! 		      (WPARAM) hwnd, (LPARAM) how);
  #else
!   return ShowWindow (hwnd , how);
  #endif
  }
  
  void
  my_set_window_pos (HWND hwnd, HWND hwndAfter,
! 		   int x, int y, int cx, int cy, UINT flags)
  {
  #ifndef ATTACH_THREADS
!   WINDOWPOS pos;
!   pos.hwndInsertAfter = hwndAfter;
    pos.x = x;
    pos.y = y;
    pos.cx = cx;
***************
*** 1874,1881 ****
  
    hwnd = my_create_scrollbar (f, bar);
  
!   SetScrollRange (hwnd, SB_CTL, 0, height, FALSE);
!   SetScrollPos (hwnd, SB_CTL, 0, TRUE);
  
    SET_SCROLL_BAR_WIN32_WINDOW (bar, hwnd);
  
--- 1935,1959 ----
  
    hwnd = my_create_scrollbar (f, bar);
  
!   if (pfnSetScrollInfo)
!     {
!       SCROLLINFO si;
! 
!       si.cbSize = sizeof (si);
!       si.fMask = SIF_ALL;
!       si.nMin = 0;
!       si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (height)
! 	+ VERTICAL_SCROLL_BAR_MIN_HANDLE;
!       si.nPage = si.nMax;
!       si.nPos = 0;
! 
!       pfnSetScrollInfo (hwnd, SB_CTL, &si, FALSE);
!     }
!   else
!     {
!       SetScrollRange (hwnd, SB_CTL, 0, VERTICAL_SCROLL_BAR_TOP_RANGE (height), FALSE);
!       SetScrollPos (hwnd, SB_CTL, 0, FALSE);
!     }
  
    SET_SCROLL_BAR_WIN32_WINDOW (bar, hwnd);
  
***************
*** 1920,1930 ****
  
    BLOCK_INPUT;
  
    /* Store the adjusted setting in the scroll bar.  */
    XSETINT (bar->start, start);
    XSETINT (bar->end, end);
  
!   SetScrollPos (w, SB_CTL, start, TRUE);
  
    UNBLOCK_INPUT;
  }
--- 1998,2045 ----
  
    BLOCK_INPUT;
  
+   {
+     int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
+ 
+     /* Make sure the values are reasonable, and try to preserve
+        the distance between start and end.  */
+     {
+       int length = end - start;
+ 
+       if (start < 0)
+ 	start = 0;
+       else if (start > top_range)
+ 	start = top_range;
+       end = start + length;
+ 
+       if (end < start)
+ 	end = start;
+       else if (end > top_range && ! dragging)
+ 	end = top_range;
+     }
+   }
+ 
    /* Store the adjusted setting in the scroll bar.  */
    XSETINT (bar->start, start);
    XSETINT (bar->end, end);
  
!   /* If being dragged, let scroll bar update itself.  */
!   if (!dragging)
!     {
!       if (pfnSetScrollInfo)
! 	{
! 	  SCROLLINFO si;
! 
! 	  si.cbSize = sizeof (si);
! 	  si.fMask = SIF_PAGE | SIF_POS;
! 	  si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
! 	  si.nPos = start;
! 
! 	  pfnSetScrollInfo (w, SB_CTL, &si, TRUE);
! 	}
!       else
! 	SetScrollPos (w, SB_CTL, start, TRUE);
!     }
  
    UNBLOCK_INPUT;
  }
***************
*** 1939,1950 ****
    Window w = SCROLL_BAR_WIN32_WINDOW (bar);
    FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
  
    BLOCK_INPUT;
  
    MoveWindow (w, left, top, width, height, TRUE);
!   SetScrollRange (w, SB_CTL, 0, height, FALSE);
!   InvalidateRect (w, NULL, FALSE);
!   my_show_window (w, SW_NORMAL);
  
    XSETINT (bar->left, left);
    XSETINT (bar->top, top);
--- 2054,2093 ----
    Window w = SCROLL_BAR_WIN32_WINDOW (bar);
    FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
  
+   /* If already correctly positioned, do nothing.  */
+   if ( XINT (bar->left) == left &&
+        XINT (bar->top) == top &&
+        XINT (bar->width) ==  width &&
+        XINT (bar->height) == height )
+     {
+       /* Redraw after clear_frame. */
+       if (!my_show_window (f, w, SW_NORMAL))
+ 	InvalidateRect (w, NULL, FALSE);
+       return;
+     }
+ 
    BLOCK_INPUT;
  
+   /* Make sure scroll bar is "visible" before moving, to ensure the
+      area of the parent window now exposed will be refreshed.  */
+   my_show_window (f, w, SW_HIDE);
    MoveWindow (w, left, top, width, height, TRUE);
!   if (pfnSetScrollInfo)
!     {
!       SCROLLINFO si;
! 
!       si.cbSize = sizeof (si);
!       si.fMask = SIF_RANGE;
!       si.nMin = 0;
!       si.nMax = VERTICAL_SCROLL_BAR_TOP_RANGE (height)
! 	+ VERTICAL_SCROLL_BAR_MIN_HANDLE;
! 
!       pfnSetScrollInfo (w, SB_CTL, &si, FALSE);
!     }
!   else
!     SetScrollRange (w, SB_CTL, 0, VERTICAL_SCROLL_BAR_TOP_RANGE (height), FALSE);
!   my_show_window (f, w, SW_NORMAL);
! //  InvalidateRect (w, NULL, FALSE);
  
    XSETINT (bar->left, left);
    XSETINT (bar->top, top);
***************
*** 2010,2031 ****
        x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
      }
  
!   /* Set the scroll bar's current state, unless we're currently being
!      dragged.  */
!   if (NILP (bar->dragging))
!     {
!       int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
  
!       if (whole == 0)
! 	x_scroll_bar_set_handle (bar, 0, top_range, 0);
!       else
! 	{
! 	  int start = (int) (((double) position * top_range) / whole);
! 	  int end = (int) (((double) (position + portion) * top_range) / whole);
  
! 	  x_scroll_bar_set_handle (bar, start, end, 0);
! 	}
!     }
  
    XSETVECTOR (window->vertical_scroll_bar, bar);
  }
--- 2153,2172 ----
        x_scroll_bar_move (bar, pixel_top, pixel_left, pixel_width, pixel_height);
      }
  
!   /* Set the scroll bar's current state.  */
!   {
!     int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (pixel_height);
  
!     if (whole == 0)
!       x_scroll_bar_set_handle (bar, 0, top_range, 0);
!     else
!       {
! 	int start = (int) (((double) position * top_range) / whole);
! 	int end = (int) (((double) (position + portion) * top_range) / whole);
  
! 	x_scroll_bar_set_handle (bar, start, end, 0);
!       }
!   }
  
    XSETVECTOR (window->vertical_scroll_bar, bar);
  }
***************
*** 2155,2173 ****
    emacs_event->timestamp = msg->msg.time;
  
    {
!     int internal_height
!       = VERTICAL_SCROLL_BAR_INSIDE_HEIGHT (XINT (bar->height));
!     int top_range
!       = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
!     int y = GetScrollPos ((HWND) msg->msg.lParam, SB_CTL);
  
      switch (LOWORD (msg->msg.wParam))
        {
-       case SB_THUMBTRACK:
- 	emacs_event->part = scroll_bar_handle;
- 	if (VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)) <= 0xffff)
- 	    y = HIWORD (msg->msg.wParam);
- 	break;
        case SB_LINEDOWN:
  	emacs_event->part = scroll_bar_down_arrow;
  	break;
--- 2296,2322 ----
    emacs_event->timestamp = msg->msg.time;
  
    {
!     int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
!     int y;
!     int dragging = !NILP (bar->dragging);
! 
!     if (pfnGetScrollInfo)
!       {
! 	SCROLLINFO si;
! 
! 	si.cbSize = sizeof (si);
! 	si.fMask = SIF_POS;
! 
! 	pfnGetScrollInfo ((HWND) msg->msg.lParam, SB_CTL, &si);
! 	y = si.nPos;
!       }
!     else
!       y = GetScrollPos ((HWND) msg->msg.lParam, SB_CTL);
! 
!     bar->dragging = Qnil;
  
      switch (LOWORD (msg->msg.wParam))
        {
        case SB_LINEDOWN:
  	emacs_event->part = scroll_bar_down_arrow;
  	break;
***************
*** 2188,2199 ****
  	emacs_event->part = scroll_bar_handle;
  	y = top_range;
  	break;
        case SB_THUMBPOSITION:
  	emacs_event->part = scroll_bar_handle;
  	break;
        case SB_ENDSCROLL:
        default:
! 	SetScrollPos (SCROLL_BAR_WIN32_WINDOW (bar), SB_CTL, y, TRUE);
  	return FALSE;
        }
  
--- 2337,2412 ----
  	emacs_event->part = scroll_bar_handle;
  	y = top_range;
  	break;
+       case SB_THUMBTRACK:
        case SB_THUMBPOSITION:
+ 	if (VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)) <= 0xffff)
+ 	    y = HIWORD (msg->msg.wParam);
+ 	bar->dragging = Qt;
  	emacs_event->part = scroll_bar_handle;
+ 
+ 	/* "Silently" update current position.  */
+ 	if (pfnSetScrollInfo)
+ 	  {
+ 	    SCROLLINFO si;
+ 
+ 	    si.cbSize = sizeof (si);
+ 	    si.fMask = SIF_POS;
+ 
+ #if 0
+ 	    /* Shrink handle if necessary to allow full range for position.  */
+ 	    {
+ 	      int start = XINT (bar->start);
+ 	      int end = XINT (bar->end);
+ 	      int len = end - start;
+ 
+ 	      /* If new end is nearly hitting bottom, we must shrink
+ 	         handle.  How much we shrink it depends on the relative
+ 	         sizes of len and top_range.  */
+ 	      if (y + len > top_range - 2)
+ 		{
+ 		  len -= min (top_range / 10, (len / 3) + 2);
+ 		  if (len < 0)
+ 		    len = 0;
+ 		}
+ 	      si.nPage = len + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+ 	      si.fMask |= SIF_PAGE;
+ 	    }
+ #endif
+ 	    si.nPos = y;
+ 	    /* Remember apparent position (we actually lag behind the real
+ 	       position, so don't set that directly.  */
+ 	    last_scroll_bar_drag_pos = y;
+ 
+ 	    pfnSetScrollInfo (SCROLL_BAR_WIN32_WINDOW (bar), SB_CTL, &si, FALSE);
+ 	  }
+ 	else
+ 	  SetScrollPos (SCROLL_BAR_WIN32_WINDOW (bar), SB_CTL, y, FALSE);
  	break;
        case SB_ENDSCROLL:
+ 	/* If this is the end of a drag sequence, then reset the scroll
+ 	   handle size to normal and do a final redraw.  Otherwise do
+ 	   nothing.  */
+ 	if (dragging)
+ 	  {
+ 	    if (pfnSetScrollInfo)
+ 	      {
+ 		SCROLLINFO si;
+ 		int start = XINT (bar->start);
+ 		int end = XINT (bar->end);
+ 
+ 		si.cbSize = sizeof (si);
+ 		si.fMask = SIF_PAGE | SIF_POS;
+ 		si.nPage = end - start + VERTICAL_SCROLL_BAR_MIN_HANDLE;
+ 		si.nPos = last_scroll_bar_drag_pos;
+ 
+ 		pfnSetScrollInfo (SCROLL_BAR_WIN32_WINDOW (bar), SB_CTL, &si, TRUE);
+ 	      }
+ 	    else
+ 	      SetScrollPos (SCROLL_BAR_WIN32_WINDOW (bar), SB_CTL, y, TRUE);
+ 	  }
+ 	/* fall through */
        default:
! 	emacs_event->kind = no_event;
  	return FALSE;
        }
  
***************
*** 2218,2230 ****
    Window w = SCROLL_BAR_WIN32_WINDOW (bar);
    FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
    int pos;
  
    BLOCK_INPUT;
  
    *fp = f;
    *bar_window = bar->window;
  
!   pos = GetScrollPos (w, SB_CTL);
  
    switch (LOWORD (last_mouse_scroll_bar_pos))
    {
--- 2431,2456 ----
    Window w = SCROLL_BAR_WIN32_WINDOW (bar);
    FRAME_PTR f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
    int pos;
+   int top_range = VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height));
  
    BLOCK_INPUT;
  
    *fp = f;
    *bar_window = bar->window;
  
!   if (pfnGetScrollInfo)
!     {
!       SCROLLINFO si;
! 
!       si.cbSize = sizeof (si);
!       si.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
! 
!       pfnGetScrollInfo (w, SB_CTL, &si);
!       pos = si.nPos;
!       top_range = si.nMax - si.nPage + 1;
!     }
!   else
!     pos = GetScrollPos (w, SB_CTL);
  
    switch (LOWORD (last_mouse_scroll_bar_pos))
    {
***************
*** 2244,2250 ****
    }
  
    XSETINT(*x, pos);
!   XSETINT(*y, VERTICAL_SCROLL_BAR_TOP_RANGE (XINT (bar->height)));
  
    f->mouse_moved = 0;
    last_mouse_scroll_bar = Qnil;
--- 2470,2476 ----
    }
  
    XSETINT(*x, pos);
!   XSETINT(*y, top_range);
  
    f->mouse_moved = 0;
    last_mouse_scroll_bar = Qnil;
***************
*** 2271,2281 ****
        HDC hdc = GetDC (window);
        RECT rect;
  
!       my_show_window (window, SW_HIDE);
        GetClientRect (window, &rect);
        select_palette (f, hdc);
        win32_clear_rect (f, hdc, &rect);
        deselect_palette (f, hdc);
      }
  }
  
--- 2497,2512 ----
        HDC hdc = GetDC (window);
        RECT rect;
  
!       /* Hide scroll bar until ready to repaint.  x_scroll_bar_move
!          arranges to refresh the scroll bar if hidden.  */
!       my_show_window (f, window, SW_HIDE);
! 
        GetClientRect (window, &rect);
        select_palette (f, hdc);
        win32_clear_rect (f, hdc, &rect);
        deselect_palette (f, hdc);
+ 
+       ReleaseDC (window, hdc);
      }
  }
  
***************
*** 2289,2295 ****
         bar = XSCROLL_BAR (bar)->next)
      {
        HWND window = SCROLL_BAR_WIN32_WINDOW (XSCROLL_BAR (bar));
!       my_show_window (window, how);
      }
  }
  
--- 2520,2526 ----
         bar = XSCROLL_BAR (bar)->next)
      {
        HWND window = SCROLL_BAR_WIN32_WINDOW (XSCROLL_BAR (bar));
!       my_show_window (f, window, how);
      }
  }
  
***************
*** 2306,2312 ****
  int temp_index;
  short temp_buffer[100];
  
! extern int key_event (KEY_EVENT_RECORD *, struct input_event *);
  
  /* Map a Win32 WM_CHAR message into a KEY_EVENT_RECORD so that
     we can use the same routines to handle input in both console
--- 2537,2543 ----
  int temp_index;
  short temp_buffer[100];
  
! extern int key_event (KEY_EVENT_RECORD *, struct input_event *, int *isdead);
  
  /* Map a Win32 WM_CHAR message into a KEY_EVENT_RECORD so that
     we can use the same routines to handle input in both console
***************
*** 2367,2378 ****
       int expected;
  {
    int count = 0;
!   int nbytes = 0;
!   int items_pending;            /* How many items are in the X queue. */
    Win32Msg msg;
    struct frame *f;
-   int event_found = 0;
-   int prefix;
    Lisp_Object part;
    struct win32_display_info *dpyinfo = &one_win32_display_info;
  
--- 2598,2606 ----
       int expected;
  {
    int count = 0;
!   int check_visibility = 0;
    Win32Msg msg;
    struct frame *f;
    Lisp_Object part;
    struct win32_display_info *dpyinfo = &one_win32_display_info;
  
***************
*** 2401,2411 ****
  
  	    if (f) 
  	      {
! 		if (f->async_visible == 0)
  		  {
  		    f->async_visible = 1;
  		    f->async_iconified = 0;
  		    SET_FRAME_GARBAGED (f);
  		  }
  		else
  		  {
--- 2629,2655 ----
  
  	    if (f) 
  	      {
! 		if (! f->async_visible)
  		  {
  		    f->async_visible = 1;
  		    f->async_iconified = 0;
  		    SET_FRAME_GARBAGED (f);
+ 
+ 		    /* WM_PAINT serves as MapNotify as well, so report
+                        visibility changes properly.  */
+ 		    if (f->iconified)
+ 		      {
+ 			bufp->kind = deiconify_event;
+ 			XSETFRAME (bufp->frame_or_window, f);
+ 			bufp++;
+ 			count++;
+ 			numchars--;
+ 		      }
+ 		    else if (! NILP(Vframe_list)
+ 			     && ! NILP (XCONS (Vframe_list)->cdr))
+ 		      /* Force a redisplay sooner or later to update the
+ 			 frame titles in case this is the second frame.  */
+ 		      record_asynch_buffer_change ();
  		  }
  		else
  		  {
***************
*** 2414,2421 ****
  		    dumprectangle (f,
  				   msg.rect.left,
  				   msg.rect.top,
! 				   msg.rect.right-msg.rect.left+1,
! 				   msg.rect.bottom-msg.rect.top+1);
  		  }
  	      }
  	  }
--- 2658,2665 ----
  		    dumprectangle (f,
  				   msg.rect.left,
  				   msg.rect.top,
! 				   msg.rect.right - msg.rect.left,
! 				   msg.rect.bottom - msg.rect.top);
  		  }
  	      }
  	  }
***************
*** 2438,2443 ****
--- 2682,2688 ----
  	      numchars--;
  	      count++;
  	    }
+ 
  	  break;
  	case WM_SYSCHAR:
  	case WM_CHAR:
***************
*** 2448,2460 ****
  	      if (numchars > 1) 
  		{
  		  int add;
  		  KEY_EVENT_RECORD key, *keyp = &key;
  
  		  if (temp_index == sizeof temp_buffer / sizeof (short))
  		    temp_index = 0;
  		  
  		  convert_to_key_event (&msg, keyp);
! 		  add = key_event (keyp, bufp);
  		  XSETFRAME (bufp->frame_or_window, f);
  		  if (add == -1)
  		    {
--- 2693,2706 ----
  	      if (numchars > 1) 
  		{
  		  int add;
+ 		  int isdead = 0;
  		  KEY_EVENT_RECORD key, *keyp = &key;
  
  		  if (temp_index == sizeof temp_buffer / sizeof (short))
  		    temp_index = 0;
  		  
  		  convert_to_key_event (&msg, keyp);
! 		  add = key_event (keyp, bufp, &isdead);
  		  XSETFRAME (bufp->frame_or_window, f);
  		  if (add == -1)
  		    {
***************
*** 2468,2479 ****
  		      add = 1;
  		    }
  
! 		  /* Throw dead keys away.  However, be sure not to
! 		     throw away the dead key if it was produced using
! 		     AltGr and there is a valid AltGr scan code for
! 		     this key.  */
! 		  if (is_dead_key (msg.msg.wParam) 
! 		      && !((VkKeyScan ((char) bufp->code) & 0xff00) == 0x600))
  		    break;
  
  		  bufp += add;
--- 2714,2720 ----
  		      add = 1;
  		    }
  
! 		  if (isdead)
  		    break;
  
  		  bufp += add;
***************
*** 2540,2545 ****
--- 2781,2808 ----
  	      }
  	  }
  	  
+         break;
+       case WM_MOUSEWHEEL:
+         {
+           if (dpyinfo->grabbed && last_mouse_frame
+               && FRAME_LIVE_P (last_mouse_frame))
+             f = last_mouse_frame;
+           else
+             f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+ 
+           if (f)
+             {
+               if ((!dpyinfo->win32_focus_frame 
+                    || f == dpyinfo->win32_focus_frame)
+                   && (numchars >= 1))
+                 {
+                   construct_mouse_wheel (bufp, &msg, f);
+                   bufp++;
+                   count++;
+                   numchars--;
+                 }
+             }
+         }
  	  break;
  	case WM_VSCROLL:
  	  {
***************
*** 2562,2571 ****
  	  
  	  if (f && !f->async_iconified)
  	    {
! 	      f->output_data.win32->left_pos = LOWORD (msg.msg.lParam);
! 	      f->output_data.win32->top_pos = HIWORD (msg.msg.lParam);
  	    }
! 	  
  	  break;
  	case WM_SIZE:
  	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
--- 2825,2853 ----
  	  
  	  if (f && !f->async_iconified)
  	    {
! 	      int x, y;
! 
! 	      x_real_positions (f, &x, &y);
! 	      f->output_data.win32->left_pos = x;
! 	      f->output_data.win32->top_pos = y;
  	    }
! 
! 	  check_visibility = 1;
! 
! 	  break;
! 	case WM_SHOWWINDOW:
! 	  /* If window has been obscured or exposed by another window
! 	     being maximised or minimised/restored, then recheck
! 	     visibility of all frames.  Direct changes to our own
! 	     windows get handled by WM_SIZE.  */
! 	  if (msg.msg.lParam != 0)
! 	    check_visibility = 1;
! 	  else
! 	    {
! 	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
! 	      f->async_visible = msg.msg.wParam;
! 	    }
! 
  	  break;
  	case WM_SIZE:
  	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
***************
*** 2580,2587 ****
  	      
  	      GetClientRect(msg.msg.hwnd, &rect);
  	      
! 	      height = rect.bottom - rect.top + 1;
! 	      width = rect.right - rect.left + 1;
  	      
  	      rows = PIXEL_TO_CHAR_HEIGHT (f, height);
  	      columns = PIXEL_TO_CHAR_WIDTH (f, width);
--- 2862,2869 ----
  	      
  	      GetClientRect(msg.msg.hwnd, &rect);
  	      
! 	      height = rect.bottom - rect.top;
! 	      width = rect.right - rect.left;
  	      
  	      rows = PIXEL_TO_CHAR_HEIGHT (f, height);
  	      columns = PIXEL_TO_CHAR_WIDTH (f, width);
***************
*** 2605,2649 ****
  		  f->output_data.win32->win_gravity = NorthWestGravity;
  		}
  	    }
! 	  
! 	  break;
! 	case WM_SETFOCUS:
! 	case WM_KILLFOCUS:
! 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
! 	  
! 	  if (msg.msg.message == WM_SETFOCUS)
! 	    {
! 	      x_new_focus_frame (dpyinfo, f);
! 	    }
! 	  else if (f == dpyinfo->win32_focus_frame)
! 	    x_new_focus_frame (dpyinfo, 0);
! 	  
! 	  break;
! 	case WM_SYSCOMMAND:
! 	  switch (msg.msg.wParam & 0xfff0)  /* Lower 4 bits used by Windows. */
  	    {
! 	    case SC_CLOSE:
! 	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
! 	      
! 	      if (f)
! 		{
! 		  if (numchars == 0)
! 		    abort ();
! 		  
! 		  bufp->kind = delete_window_event;
! 		  XSETFRAME (bufp->frame_or_window, f);
! 		  bufp++;
! 		  count++;
! 		  numchars--;
! 		}
! 	      
! 	      break;
! 	    case SC_MINIMIZE:
! 	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
! 	      
! 	      if (f)
  		{
! 		  f->async_visible = 1;
  		  f->async_iconified = 1;
  		  
  		  bufp->kind = iconify_event;
--- 2887,2900 ----
  		  f->output_data.win32->win_gravity = NorthWestGravity;
  		}
  	    }
! 
! 	  /* Inform lisp of whether frame has been iconified etc. */
! 	  if (f)
  	    {
! 	      switch (msg.msg.wParam)
  		{
! 		case SIZE_MINIMIZED:
! 		  f->async_visible = 0;
  		  f->async_iconified = 1;
  		  
  		  bufp->kind = iconify_event;
***************
*** 2651,2665 ****
  		  bufp++;
  		  count++;
  		  numchars--;
! 		}
! 	      
! 	      break;
! 	    case SC_MAXIMIZE:
! 	    case SC_RESTORE:
! 	      f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
! 	      
! 	      if (f)
! 		{
  		  f->async_visible = 1;
  		  f->async_iconified = 0;
  		  
--- 2902,2911 ----
  		  bufp++;
  		  count++;
  		  numchars--;
! 		  break;
! 
! 		case SIZE_MAXIMIZED:
! 		case SIZE_RESTORED:
  		  f->async_visible = 1;
  		  f->async_iconified = 0;
  		  
***************
*** 2680,2689 ****
  		       to update the frame titles
  		       in case this is the second frame.  */
  		    record_asynch_buffer_change ();
  		}
- 	      
- 	      break;
  	    }
  	  
  	  break;
  	case WM_CLOSE:
--- 2926,2952 ----
  		       to update the frame titles
  		       in case this is the second frame.  */
  		    record_asynch_buffer_change ();
+ 		  break;
  		}
  	    }
+ 
+ 	  check_visibility = 1;
+ 	  
+ 	  break;
+ 	case WM_SETFOCUS:
+ 	case WM_KILLFOCUS:
+ 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+ 	  
+ 	  if (msg.msg.message == WM_SETFOCUS)
+ 	    {
+ 	      x_new_focus_frame (dpyinfo, f);
+ 	    }
+ 	  else if (f == dpyinfo->win32_focus_frame)
+ 	    {
+ 	      x_new_focus_frame (dpyinfo, 0);
+ 	    }
+ 
+ 	  check_visibility = 1;
  	  
  	  break;
  	case WM_CLOSE:
***************
*** 2741,2746 ****
--- 3004,3026 ----
  		  /* Came from popup menu */
  		}
  	    }
+ 
+ 	  check_visibility = 1;
+ 
+ 	  break;
+ 	case WM_DISPLAYCHANGE:
+ 	  f = x_window_to_frame (dpyinfo, msg.msg.hwnd);
+ 
+ 	  if (f) 
+ 	    {
+ 	      dpyinfo->width = (short) LOWORD (msg.msg.lParam);
+ 	      dpyinfo->height = (short) HIWORD (msg.msg.lParam);
+ 	      dpyinfo->n_cbits = msg.msg.wParam;
+ 	      printf ("display change: %d %d\n", dpyinfo->width,
+ 		      dpyinfo->height);
+ 	    }
+ 	  
+ 	  check_visibility = 1;
  	  break;
  	}
      }
***************
*** 2754,2759 ****
--- 3034,3077 ----
        pending_autoraise_frame = 0;
      }
  
+   /* Check whether visible frames are still visisble, if we have
+      enqueued any user events or been notified of events that may affect
+      visibility.  We do this here because there doesn't seem to be any
+      direct notification from Windows that the visibility of a window
+      has changed (at least, not in all cases).  */
+   if (count > 0 || check_visibility)
+     {
+       Lisp_Object tail, frame;
+ 
+       FOR_EACH_FRAME (tail, frame)
+ 	{
+ 	  FRAME_PTR f = XFRAME (frame);
+ 	  if (FRAME_WIN32_P (f) && (FRAME_VISIBLE_P (f) || f->async_visible))
+ 	    {
+ 	      RECT clipbox;
+ 	      HDC  hdc = get_frame_dc (f);
+ 	      GetClipBox (hdc, &clipbox);
+ 	      release_frame_dc (f, hdc);
+ 
+ 	      if (clipbox.right == clipbox.left ||
+ 		  clipbox.bottom == clipbox.top)
+ 		{
+ 		  /* Frame is completely obscured so mark as invisible;
+ 		     in order to keep frame title we pretend the frame
+ 		     has been iconified.  */
+ 		  f->async_visible = 0;
+ 		  f->async_iconified = 1;
+ 
+ 		  bufp->kind = iconify_event;
+ 		  XSETFRAME (bufp->frame_or_window, f);
+ 		  bufp++;
+ 		  count++;
+ 		  numchars--;
+ 		}
+ 	    }
+ 	}
+     }
+ 
    UNBLOCK_INPUT;
    return count;
  }
***************
*** 2836,2849 ****
    if (! on && f->phys_cursor_x < 0)
      return;
  
-   /* If we're not updating, then we want to use the current frame's
-      cursor position, not our local idea of where the cursor ought to be.  */
-   if (f != updating_frame)
-     {
-       curs_x = FRAME_CURSOR_X (f);
-       curs_y = FRAME_CURSOR_Y (f);
-     }
- 
    /* If there is anything wrong with the current cursor state, remove it.  */
    if (f->phys_cursor_x >= 0
        && (!on
--- 3154,3159 ----
***************
*** 2903,2916 ****
    if (!on && f->phys_cursor_x < 0)
      return;
  
-   /* If we're not updating, then we want to use the current frame's
-      cursor position, not our local idea of where the cursor ought to be.  */
-   if (f != updating_frame)
-     {
-       curs_x = FRAME_CURSOR_X (f);
-       curs_y = FRAME_CURSOR_Y (f);
-     }
- 
    /* If cursor is currently being shown and we don't want it to be
       or it is in the wrong place,
       or we want a hollow box and it's not so, (pout!)
--- 3213,3218 ----
***************
*** 2989,3000 ****
--- 3291,3316 ----
      }
  }
  
+ /* Display the cursor on frame F, or clear it, according to ON.
+    Use the position specified by curs_x and curs_y
+    if we are doing an update of frame F now.
+    Otherwise use the position in the FRAME_CURSOR_X and FRAME_CURSOR_Y fields
+    of F.  */
+ 
  x_display_cursor (f, on)
       struct frame *f;
       int on;
  {
    BLOCK_INPUT;
  
+   /* If we're not updating, then we want to use the current frame's
+      cursor position, not our local idea of where the cursor ought to be.  */
+   if (f != updating_frame)
+     {
+       curs_x = FRAME_CURSOR_X (f);
+       curs_y = FRAME_CURSOR_Y (f);
+     }
+ 
    if (FRAME_DESIRED_CURSOR (f) == filled_box_cursor)
      x_display_box_cursor (f, on);
    else if (FRAME_DESIRED_CURSOR (f) == bar_cursor)
***************
*** 3120,3125 ****
--- 3436,3444 ----
    }
  }
  
+ /* Calculate the absolute position in frame F
+    from its current recorded position values and gravity.  */
+ 
  x_calc_absolute_position (f)
       struct frame *f;
  {
***************
*** 3205,3221 ****
       when the frame is already visible, but experiment says we do.  */
    modified_left = f->output_data.win32->left_pos;
    modified_top = f->output_data.win32->top_pos;
    if (change_gravity != 0)
      {
        modified_left += f->output_data.win32->border_width;
        modified_top += f->output_data.win32->border_width;
      }
  
    my_set_window_pos (FRAME_WIN32_WINDOW (f),
  		     NULL,
  		     modified_left, modified_top,
  		     0,0,
! 		     SWP_NOZORDER | SWP_NOSIZE);
    UNBLOCK_INPUT;
  }
  
--- 3524,3543 ----
       when the frame is already visible, but experiment says we do.  */
    modified_left = f->output_data.win32->left_pos;
    modified_top = f->output_data.win32->top_pos;
+ #ifndef HAVE_NTGUI
+   /* Do not add in border widths under W32.  */
    if (change_gravity != 0)
      {
        modified_left += f->output_data.win32->border_width;
        modified_top += f->output_data.win32->border_width;
      }
+ #endif
  
    my_set_window_pos (FRAME_WIN32_WINDOW (f),
  		     NULL,
  		     modified_left, modified_top,
  		     0,0,
! 		     SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
    UNBLOCK_INPUT;
  }
  
***************
*** 3230,3235 ****
--- 3552,3559 ----
       int cols, rows;
  {
    int pixelwidth, pixelheight;
+   Lisp_Object window;
+   struct win32_display_info *dpyinfo = &one_win32_display_info;
    
    BLOCK_INPUT;
    
***************
*** 3256,3269 ****
      AdjustWindowRect(&rect, f->output_data.win32->dwStyle,
  		     FRAME_EXTERNAL_MENU_BAR (f));
        
-     /* All windows have an extra pixel */
- 
      my_set_window_pos (FRAME_WIN32_WINDOW (f),
  		       NULL, 
  		       0, 0,
! 		       rect.right - rect.left + 1,
! 		       rect.bottom - rect.top + 1,
! 		       SWP_NOZORDER | SWP_NOMOVE);
    }
    
    /* Now, strictly speaking, we can't be sure that this is accurate,
--- 3580,3591 ----
      AdjustWindowRect(&rect, f->output_data.win32->dwStyle,
  		     FRAME_EXTERNAL_MENU_BAR (f));
        
      my_set_window_pos (FRAME_WIN32_WINDOW (f),
  		       NULL, 
  		       0, 0,
! 		       rect.right - rect.left,
! 		       rect.bottom - rect.top,
! 		       SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
    }
    
    /* Now, strictly speaking, we can't be sure that this is accurate,
***************
*** 3280,3285 ****
--- 3602,3613 ----
    PIXEL_WIDTH (f) = pixelwidth;
    PIXEL_HEIGHT (f) = pixelheight;
  
+   /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
+      receive in the ConfigureNotify event; if we get what we asked
+      for, then the event won't cause the screen to become garbaged, so
+      we have to make sure to do it here.  */
+   SET_FRAME_GARBAGED (f);
+ 
    /* If cursor was outside the new size, mark it as off.  */
    if (f->phys_cursor_y >= rows
        || f->phys_cursor_x >= cols)
***************
*** 3288,3298 ****
        f->phys_cursor_y = -1;
      }
  
!   /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to
!      receive in the ConfigureNotify event; if we get what we asked
!      for, then the event won't cause the screen to become garbaged, so
!      we have to make sure to do it here.  */
!   SET_FRAME_GARBAGED (f);
    
    UNBLOCK_INPUT;
  }
--- 3616,3632 ----
        f->phys_cursor_y = -1;
      }
  
!   /* Clear out any recollection of where the mouse highlighting was,
!      since it might be in a place that's outside the new frame size. 
!      Actually checking whether it is outside is a pain in the neck,
!      so don't try--just let the highlighting be done afresh with new size.  */
!   window = dpyinfo->mouse_face_window;
!   if (! NILP (window) && XFRAME (window) == f)
!     {
!       dpyinfo->mouse_face_beg_row = dpyinfo->mouse_face_beg_col = -1;
!       dpyinfo->mouse_face_end_row = dpyinfo->mouse_face_end_col = -1;
!       dpyinfo->mouse_face_window = Qnil;
!     }
    
    UNBLOCK_INPUT;
  }
***************
*** 3350,3364 ****
  x_raise_frame (f)
       struct frame *f;
  {
! //  if (f->async_visible)
!     {
!       BLOCK_INPUT;
!       my_set_window_pos (FRAME_WIN32_WINDOW (f),
! 		         HWND_TOP,
! 		         0, 0, 0, 0,
! 		         SWP_NOSIZE | SWP_NOMOVE);
!       UNBLOCK_INPUT;
!     }
  }
  
  /* Lower frame F.  */
--- 3684,3695 ----
  x_raise_frame (f)
       struct frame *f;
  {
!   BLOCK_INPUT;
!   my_set_window_pos (FRAME_WIN32_WINDOW (f),
! 		     HWND_TOP,
! 		     0, 0, 0, 0,
! 		     SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
!   UNBLOCK_INPUT;
  }
  
  /* Lower frame F.  */
***************
*** 3366,3380 ****
  x_lower_frame (f)
       struct frame *f;
  {
! //  if (f->async_visible)
!     {
!       BLOCK_INPUT;
!       my_set_window_pos (FRAME_WIN32_WINDOW (f),
! 		         HWND_BOTTOM,
! 		         0, 0, 0, 0,
! 		         SWP_NOSIZE | SWP_NOMOVE);
!       UNBLOCK_INPUT;
!     }
  }
  
  static void
--- 3697,3708 ----
  x_lower_frame (f)
       struct frame *f;
  {
!   BLOCK_INPUT;
!   my_set_window_pos (FRAME_WIN32_WINDOW (f),
! 		     HWND_BOTTOM,
! 		     0, 0, 0, 0,
! 		     SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
!   UNBLOCK_INPUT;
  }
  
  static void
***************
*** 3410,3423 ****
  	 before the window gets really visible.  */
        if (! FRAME_ICONIFIED_P (f)
  	  && ! f->output_data.win32->asked_for_visible)
-       {
  	x_set_offset (f, f->output_data.win32->left_pos, f->output_data.win32->top_pos, 0);
- //	SetForegroundWindow (FRAME_WIN32_WINDOW (f));
-       }
  
        f->output_data.win32->asked_for_visible = 1;
  
!       my_show_window (FRAME_WIN32_WINDOW (f), SW_SHOWNORMAL);
      }
  
    /* Synchronize to ensure Emacs knows the frame is visible
--- 3738,3749 ----
  	 before the window gets really visible.  */
        if (! FRAME_ICONIFIED_P (f)
  	  && ! f->output_data.win32->asked_for_visible)
  	x_set_offset (f, f->output_data.win32->left_pos, f->output_data.win32->top_pos, 0);
  
        f->output_data.win32->asked_for_visible = 1;
  
! //      my_show_window (f, FRAME_WIN32_WINDOW (f), f->async_iconified ? SW_RESTORE : SW_SHOW);
!       my_show_window (f, FRAME_WIN32_WINDOW (f), SW_SHOWNORMAL);
      }
  
    /* Synchronize to ensure Emacs knows the frame is visible
***************
*** 3480,3486 ****
    
    BLOCK_INPUT;
    
!   my_show_window (FRAME_WIN32_WINDOW (f), SW_HIDE);
    
    /* We can't distinguish this from iconification
       just by the event that we get from the server.
--- 3806,3812 ----
    
    BLOCK_INPUT;
    
!   my_show_window (f, FRAME_WIN32_WINDOW (f), SW_HIDE);
    
    /* We can't distinguish this from iconification
       just by the event that we get from the server.
***************
*** 3512,3520 ****
  
    BLOCK_INPUT;
  
!   my_show_window (FRAME_WIN32_WINDOW (f), SW_SHOWMINIMIZED);
!   /* The frame doesn't seem to be lowered automatically. */
!   x_lower_frame (f);
  
    f->async_iconified = 1;
  
--- 3838,3845 ----
  
    BLOCK_INPUT;
  
!   /* Simulate the user minimizing the frame.  */
!   PostMessage (FRAME_WIN32_WINDOW (f), WM_SYSCOMMAND, SC_MINIMIZE, 0);
  
    f->async_iconified = 1;
  
***************
*** 3576,3583 ****
  
    enter_crit ();
  
!   SetWindowLong (window, WND_X_UNITS_INDEX, FONT_WIDTH (f->output_data.win32->font));
!   SetWindowLong (window, WND_Y_UNITS_INDEX, f->output_data.win32->line_height);
  
    leave_crit ();
  }
--- 3901,3910 ----
  
    enter_crit ();
  
!   SetWindowLong (window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.win32->font));
!   SetWindowLong (window, WND_LINEHEIGHT_INDEX, f->output_data.win32->line_height);
!   SetWindowLong (window, WND_BORDER_INDEX, f->output_data.win32->internal_border_width);
!   SetWindowLong (window, WND_SCROLLBAR_INDEX, f->output_data.win32->vertical_scroll_bar_extra);
  
    leave_crit ();
  }
***************
*** 3829,3836 ****
  				   off the bottom */
    baud_rate = 19200;
  
!   /* Try to use interrupt input; if we can't, then start polling.  */
!   Fset_input_mode (Qt, Qnil, Qt, Qnil);
  
    /* Create the window thread - it will terminate itself or when the app terminates */
  
--- 4156,4164 ----
  				   off the bottom */
    baud_rate = 19200;
  
!   /* Initialize input mode: interrupt_input off, no flow control, allow
!      8 bit character input, standard quit char.  */
!   Fset_input_mode (Qnil, Qnil, make_number (2), Qnil);
  
    /* Create the window thread - it will terminate itself or when the app terminates */
  
***************
*** 3865,3870 ****
--- 4193,4223 ----
  #ifdef ATTACH_THREADS
    AttachThreadInput (dwMainThreadId, dwWinThreadId, TRUE);
  #endif
+ 
+   /* Dynamically link to optional system components. */
+   {
+     HANDLE user_lib = LoadLibrary ("user32.dll");
+ 
+ #define LOAD_PROC(fn) pfn##fn = (void *) GetProcAddress (user_lib, #fn)
+ 
+     /* New proportional scroll bar functions. */
+     LOAD_PROC( SetScrollInfo );
+     LOAD_PROC( GetScrollInfo );
+ 
+ #undef LOAD_PROC
+ 
+     FreeLibrary (user_lib);
+ 
+     /* If using proportional scroll bars, ensure handle is at least 5 pixels;
+        otherwise use the fixed height.  */
+     vertical_scroll_bar_min_handle = (pfnSetScrollInfo != NULL) ? 5 :
+       GetSystemMetrics (SM_CYVTHUMB);
+ 
+     /* For either kind of scroll bar, take account of the arrows; these
+        effectively form the border of the main scroll bar range.  */
+     vertical_scroll_bar_top_border = vertical_scroll_bar_bottom_border
+       = GetSystemMetrics (SM_CYVSCROLL);
+   }
  }
  
  void
diff -c pretest/src/w32term.h.orig pretest/src/w32term.h
*** pretest/src/w32term.h.orig	Fri May  3 19:31:34 1996
--- pretest/src/w32term.h	Mon Jul 14 14:12:14 1997
***************
*** 462,472 ****
     inset the handle boundaries from the scroll bar edges.  */
  #define VERTICAL_SCROLL_BAR_LEFT_BORDER (0)
  #define VERTICAL_SCROLL_BAR_RIGHT_BORDER (0)
! #define VERTICAL_SCROLL_BAR_TOP_BORDER (0)
! #define VERTICAL_SCROLL_BAR_BOTTOM_BORDER (0)
  
  /* Minimum lengths for scroll bar handles, in pixels.  */
! #define VERTICAL_SCROLL_BAR_MIN_HANDLE (0)
  
  
  /* Manipulating pixel sizes and character sizes.
--- 462,472 ----
     inset the handle boundaries from the scroll bar edges.  */
  #define VERTICAL_SCROLL_BAR_LEFT_BORDER (0)
  #define VERTICAL_SCROLL_BAR_RIGHT_BORDER (0)
! #define VERTICAL_SCROLL_BAR_TOP_BORDER (vertical_scroll_bar_top_border)
! #define VERTICAL_SCROLL_BAR_BOTTOM_BORDER (vertical_scroll_bar_bottom_border)
  
  /* Minimum lengths for scroll bar handles, in pixels.  */
! #define VERTICAL_SCROLL_BAR_MIN_HANDLE (vertical_scroll_bar_min_handle)
  
  
  /* Manipulating pixel sizes and character sizes.
***************
*** 577,582 ****
--- 577,587 ----
  extern XFontStruct *win32_load_font ();
  extern void win32_unload_font ();
  
+ /* Define for earlier versions of Visual C */
+ #ifndef WM_MOUSEWHEEL
+ #define WM_MOUSEWHEEL                  (0x020A)
+ #endif /* WM_MOUSEWHEEL */
+ 
  #define WM_EMACS_START                 (WM_USER + 1)
  #define WM_EMACS_KILL                  (WM_EMACS_START + 0x00)
  #define WM_EMACS_CREATEWINDOW          (WM_EMACS_START + 0x01)
***************
*** 585,606 ****
  #define WM_EMACS_SHOWWINDOW            (WM_EMACS_START + 0x04)
  #define WM_EMACS_SETWINDOWPOS          (WM_EMACS_START + 0x05)
  #define WM_EMACS_DESTROYWINDOW         (WM_EMACS_START + 0x06)
  #define WM_EMACS_END                   (WM_EMACS_START + 0x10)
  
! typedef struct {
!   HWND hwndAfter;
!   int x;
!   int y;
!   int cx;
!   int cy;
!   int flags;
! } Win32WindowPos;
! 
! #define WND_X_UNITS_INDEX      (0) 
! #define WND_Y_UNITS_INDEX      (4) 
! #define WND_BACKGROUND_INDEX   (8) 
  
- #define WND_LAST_INDEX      (16)
  #define WND_EXTRA_BYTES     (WND_LAST_INDEX)
  
  extern DWORD dwWinThreadId;
--- 590,605 ----
  #define WM_EMACS_SHOWWINDOW            (WM_EMACS_START + 0x04)
  #define WM_EMACS_SETWINDOWPOS          (WM_EMACS_START + 0x05)
  #define WM_EMACS_DESTROYWINDOW         (WM_EMACS_START + 0x06)
+ #define WM_EMACS_TRACKPOPUPMENU        (WM_EMACS_START + 0x07)
  #define WM_EMACS_END                   (WM_EMACS_START + 0x10)
  
! #define WND_FONTWIDTH_INDEX    (0) 
! #define WND_LINEHEIGHT_INDEX   (4) 
! #define WND_BORDER_INDEX       (8) 
! #define WND_SCROLLBAR_INDEX    (12) 
! #define WND_BACKGROUND_INDEX   (16) 
! #define WND_LAST_INDEX         (20)
  
  #define WND_EXTRA_BYTES     (WND_LAST_INDEX)
  
  extern DWORD dwWinThreadId;
diff -c pretest/src/s/windowsnt.h.orig pretest/src/s/windowsnt.h
*** pretest/src/s/windowsnt.h.orig	Tue May 14 18:44:35 1996
--- pretest/src/s/windowsnt.h	Tue Jul 22 12:34:37 1997
***************
*** 85,91 ****
     to read the input and send it to the true Emacs process
     through a pipe. */
  
! #define INTERRUPT_INPUT
  
  /* Letter to use in finding device name of first pty,
    if system supports pty's.  'a' means it is /dev/ptya0  */
--- 85,91 ----
     to read the input and send it to the true Emacs process
     through a pipe. */
  
! /* #define INTERRUPT_INPUT */
  
  /* Letter to use in finding device name of first pty,
    if system supports pty's.  'a' means it is /dev/ptya0  */
***************
*** 140,148 ****
  
  #define BSTRING
  #define bzero(b, l) memset(b, 0, l)
! #define bcopy(s, d, l) memcpy(d, s, l)
  #define bcmp(a, b, l) memcmp(a, b, l)
  
  /* subprocesses should be defined if you want to
     have code for asynchronous subprocesses
     (as used in M-x compile and M-x shell).
--- 140,153 ----
  
  #define BSTRING
  #define bzero(b, l) memset(b, 0, l)
! #define bcopy(s, d, l) memmove(d, s, l)
  #define bcmp(a, b, l) memcmp(a, b, l)
  
+ /* bcopy (aka memmove aka memcpy at least on x86) under MSVC is quite safe */
+ #define GAP_USE_BCOPY
+ #define BCOPY_UPWARD_SAFE 1
+ #define BCOPY_DOWNWARD_SAFE 1
+ 
  /* subprocesses should be defined if you want to
     have code for asynchronous subprocesses
     (as used in M-x compile and M-x shell).
***************
*** 253,294 ****
  /* get some redefinitions in place */
  
  /* IO calls that are emulated or shadowed */
  #define access  sys_access
  #define chdir   sys_chdir
  #define chmod   sys_chmod
  #define close   sys_close
  #define creat   sys_creat
  #define ctime	sys_ctime
  #define dup     sys_dup
  #define dup2    sys_dup2
  #define fopen   sys_fopen
  #define link    sys_link
  #define mkdir   sys_mkdir
  #define mktemp  sys_mktemp
  #define open    sys_open
  #define pipe    sys_pipe
  #define read    sys_read
  #define rename  sys_rename
  #define rmdir   sys_rmdir
  #define select  sys_select
  #define sleep   sys_sleep
  #define unlink  sys_unlink
  #define write   sys_write
  
- /* this is hacky, but is necessary to avoid warnings about macro
-    redefinitions using the SDK compilers */
- #ifndef __STDC__
- #define __STDC__ 1
- #define MUST_UNDEF__STDC__
- #endif
- #include <direct.h>
- #include <io.h>
- #include <stdio.h>
- #ifdef MUST_UNDEF__STDC__
- #undef __STDC__
- #undef MUST_UNDEF__STDC__
- #endif
- 
  /* subprocess calls that are emulated */
  #define spawnve sys_spawnve
  #define wait    sys_wait
--- 258,297 ----
  /* get some redefinitions in place */
  
  /* IO calls that are emulated or shadowed */
+ #undef access
  #define access  sys_access
+ #undef chdir
  #define chdir   sys_chdir
+ #undef chmod
  #define chmod   sys_chmod
+ #undef close
  #define close   sys_close
+ #undef creat
  #define creat   sys_creat
  #define ctime	sys_ctime
+ #undef dup
  #define dup     sys_dup
+ #undef dup2
  #define dup2    sys_dup2
  #define fopen   sys_fopen
  #define link    sys_link
  #define mkdir   sys_mkdir
+ #undef mktemp
  #define mktemp  sys_mktemp
+ #undef open
  #define open    sys_open
  #define pipe    sys_pipe
+ #undef read
  #define read    sys_read
  #define rename  sys_rename
  #define rmdir   sys_rmdir
  #define select  sys_select
  #define sleep   sys_sleep
+ #undef unlink
  #define unlink  sys_unlink
+ #undef write
  #define write   sys_write
  
  /* subprocess calls that are emulated */
  #define spawnve sys_spawnve
  #define wait    sys_wait
***************
*** 304,309 ****
--- 307,313 ----
  #define fileno	  _fileno
  #define flushall  _flushall
  #define fputchar  _fputchar
+ #define getcwd	  _getcwd
  #define getw	  _getw
  #define getpid    _getpid
  #define isatty    _isatty
***************
*** 322,327 ****
--- 326,345 ----
  #define abort	win32_abort
  #endif
  
+ /* this is hacky, but is necessary to avoid warnings about macro
+    redefinitions using the SDK compilers */
+ #ifndef __STDC__
+ #define __STDC__ 1
+ #define MUST_UNDEF__STDC__
+ #endif
+ #include <direct.h>
+ #include <io.h>
+ #include <stdio.h>
+ #ifdef MUST_UNDEF__STDC__
+ #undef __STDC__
+ #undef MUST_UNDEF__STDC__
+ #endif
+ 
  /* Defines that we need that aren't in the standard signal.h  */
  #define SIGHUP  1               /* Hang up */
  #define SIGQUIT 3               /* Quit process */
***************
*** 370,374 ****
--- 388,415 ----
  
  /* We need a little extra space, see ../../lisp/loadup.el */
  #define SYSTEM_PURESIZE_EXTRA 15000
+ 
+ /* For unexec to work on Alpha systems, we need to put Emacs'
+    initialized data into a separate section from the CRT initialized
+    data (because the Alpha linker freely reorders data variables, even
+    across libraries, so our data and the CRT data get intermingled).
+ 
+    Note that unexnt.c relies on this fact, and must be modified
+    accordingly if this section name is changed, or if this pragma is
+    removed.  Also, obviously, all files that define initialized data
+    must include config.h to pick up this pragma.  */
+ 
+ #pragma data_seg("APPDATA")
+ 
+ /* #define FULL_DEBUG */
+ /* #define EMACSDEBUG */
+ 
+ #ifdef EMACSDEBUG
+ extern void _DebPrint (const char *fmt, ...);
+ #define DebPrint(stuff) _DebPrint stuff
+ #else
+ #define DebPrint(stuff)
+ #endif
+ 
  
  /* ============================================================ */
