diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index a04dda6..a9bce5a 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -595,13 +595,6 @@ decode_options (int argc, char **argv)
       display = NULL;
       tty = 1;
     }
-
-  if (alternate_editor && alternate_editor[0] == '\0')
-    {
-      message (true, "--alternate-editor argument or ALTERNATE_EDITOR variable cannot be\n\
-an empty string");
-      exit (EXIT_FAILURE);
-    }
 #endif /* WINDOWSNT */
 }
 
@@ -642,10 +635,8 @@ The following OPTIONS are accepted:\n\
 			Set filename of the TCP authentication file\n\
 -a EDITOR, --alternate-editor=EDITOR\n\
 			Editor to fallback to if the server is not running\n"
-#ifndef WINDOWSNT
 "			If EDITOR is the empty string, start Emacs in daemon\n\
 			mode and try connecting again\n"
-#endif /* not WINDOWSNT */
 "\n\
 Report bugs with M-x report-emacs-bug.\n");
   exit (EXIT_SUCCESS);
@@ -1459,9 +1450,65 @@ w32_give_focus (void)
 /* Start the emacs daemon and try to connect to it.  */
 
 static void
+connect_to_emacs_socket (void)
+{
+#ifdef WINDOWSNT
+  /* It's just a progress message, so don't pop a dialog if this is
+     emacsclientw.  */
+  if (!w32_window_app ())
+#endif
+  message (true, "Emacs daemon should have started, trying to connect again\n");
+  if ((emacs_socket = set_socket (1)) == INVALID_SOCKET)
+    {
+      message (true, "Error: Cannot connect even after starting the Emacs daemon\n");
+      exit (EXIT_FAILURE);
+    }
+}
+
+static void
 start_daemon_and_retry_set_socket (void)
 {
-#ifndef WINDOWSNT
+#ifdef WINDOWSNT
+  DWORD wait_result;
+  HANDLE w32_daemon_event;
+  STARTUPINFO si;
+  PROCESS_INFORMATION pi;
+  SECURITY_ATTRIBUTES sa;
+  char execstr[64];
+
+  ZeroMemory (&si, sizeof si);
+  si.cb = sizeof si;
+  ZeroMemory (&pi, sizeof pi);
+
+  sa.nLength = sizeof sa;
+  sa.lpSecurityDescriptor = NULL;
+  sa.bInheritHandle = TRUE;
+
+  w32_daemon_event = CreateEvent (&sa, TRUE, FALSE, NULL);
+  if (w32_daemon_event == NULL)
+    {
+      message (true, "Couldn't create Windows daemon event");
+      exit (EXIT_FAILURE);
+    }
+
+  snprintf (execstr, sizeof execstr, "emacs --daemon=*%p", w32_daemon_event);
+  if (!CreateProcess (NULL, execstr, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL,
+                      NULL, &si, &pi))
+    {
+      message (true, "%s: error starting emacs daemon\n", progname);
+      exit (EXIT_FAILURE);
+    }
+
+  if (WaitForSingleObject (w32_daemon_event, INFINITE) != WAIT_OBJECT_0)
+    {
+      message (true, "Error while waiting for Windows daemon event");
+      exit (EXIT_FAILURE);
+    }
+  CloseHandle (w32_daemon_event);
+
+  /* Try connecting, the daemon should have started by now.  */
+  connect_to_emacs_socket ();
+#elif !defined(WINDOWSNT)
   pid_t dpid;
   int status;
 
@@ -1479,12 +1526,7 @@ start_daemon_and_retry_set_socket (void)
 	}
 
       /* Try connecting, the daemon should have started by now.  */
-      message (true, "Emacs daemon should have started, trying to connect again\n");
-      if ((emacs_socket = set_socket (1)) == INVALID_SOCKET)
-	{
-	  message (true, "Error: Cannot connect even after starting the Emacs daemon\n");
-	  exit (EXIT_FAILURE);
-	}
+      connect_to_emacs_socket ();
     }
   else if (dpid < 0)
     {
@@ -1511,7 +1553,7 @@ start_daemon_and_retry_set_socket (void)
       execvp ("emacs", d_argv);
       message (true, "%s: error starting emacs daemon\n", progname);
     }
-#endif /* WINDOWSNT */
+#endif /* !WINDOWSNT */
 }
 
 int
diff --git a/lisp/frame.el b/lisp/frame.el
index 1d5bbf2..23bbc0d 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -536,7 +536,8 @@ is not considered (see `next-frame')."
 Return nil if we don't know how to interpret DISPLAY."
   ;; MS-Windows doesn't know how to create a GUI frame in a -nw session.
   (if (and (eq system-type 'windows-nt)
-	   (null (window-system)))
+	   (null (window-system))
+	   (not (daemonp)))
       nil
     (cl-loop for descriptor in display-format-alist
 	     for pattern = (car descriptor)
diff --git a/lisp/frameset.el b/lisp/frameset.el
index 4a06374..17fe39b 100644
--- a/lisp/frameset.el
+++ b/lisp/frameset.el
@@ -1022,8 +1022,8 @@ Internal use only."
 (defun frameset-keep-original-display-p (force-display)
   "True if saved frames' displays should be honored.
 For the meaning of FORCE-DISPLAY, see `frameset-restore'."
-  (cond ((daemonp) t)
-	((eq system-type 'windows-nt) nil) ;; Does ns support more than one display?
+  (cond ((eq system-type 'windows-nt) nil) ;; Does ns support more than one display?
+	((daemonp) t)
 	(t (not force-display))))
 
 (defun frameset-minibufferless-first-p (frame1 _frame2)
diff --git a/lisp/server.el b/lisp/server.el
index 166cd44..9585b17 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -1139,9 +1139,12 @@ The following commands are accepted by the client:
                  ;; frame.  If running a GUI server, force the frame
                  ;; type to GUI.  (Cygwin is perfectly happy with
                  ;; multi-tty support, so don't override the user's
-                 ;; choice there.)
+                 ;; choice there.)  In daemon mode on Windows, we can't
+                 ;; make tty frames, so force the frame type to GUI
+                 ;; there too.
                  (when (and (eq system-type 'windows-nt)
-                            (eq window-system 'w32))
+                            (or (daemonp)
+                                (eq window-system 'w32)))
                    (push "-window-system" args-left)))
 
                 ;; -position LINE[:COLUMN]:  Set point to the given
@@ -1215,7 +1218,10 @@ The following commands are accepted by the client:
 					   terminal-frame)))))
 		    (setq tty-name nil tty-type nil)
 		    (if display (server-select-display display)))
-		   ((eq tty-name 'window-system)
+		   ((or (and (eq system-type 'windows-nt)
+			     (daemonp)
+			     (setq display "w32"))
+		        (eq tty-name 'window-system))
 		    (server-create-window-system-frame display nowait proc
 						       parent-id
 						       frame-parameters))
diff --git a/src/dispnew.c b/src/dispnew.c
index 3c8117e..e86fbb8 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -5974,9 +5974,12 @@ init_display (void)
     }
 #endif /* SIGWINCH */
 
-  /* If running as a daemon, no need to initialize any frames/terminal. */
+  /* If running as a daemon, no need to initialize any frames/terminal,
+     except on Windows, where we at least want to initialize it.  */
+#ifndef WINDOWSNT
   if (IS_DAEMON)
       return;
+#endif
 
   /* If the user wants to use a window system, we shouldn't bother
      initializing the terminal.  This is especially important when the
diff --git a/src/emacs.c b/src/emacs.c
index 345fe3e..d54643e 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -195,9 +195,13 @@ bool no_site_lisp;
 /* Name for the server started by the daemon.*/
 static char *daemon_name;
 
+#ifndef WINDOWSNT
 /* Pipe used to send exit notification to the daemon parent at
    startup.  */
 int daemon_pipe[2];
+#else
+HANDLE w32_daemon_event;
+#endif
 
 /* Save argv and argc.  */
 char **initial_argv;
@@ -687,6 +691,43 @@ close_output_streams (void)
      _exit (EXIT_FAILURE);
 }
 
+static void
+handle_dname_arg (char **dname_arg, char *dname_arg2, int sep)
+{
+  int has_dname = *dname_arg != NULL;
+  /* Were we called by emacsclient or did the user start the daemon?  */
+#ifdef WINDOWSNT
+  int user_started_daemon = has_dname && !strchr (*dname_arg, sep);
+  if (!has_dname || user_started_daemon)
+    {
+      w32_daemon_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+      if (user_started_daemon)
+        /* We already have a name in dname_arg or none was given.  */
+        return;
+      else
+        goto process_dname;
+    }
+#endif
+  if (!has_dname || !strchr (*dname_arg, sep)
+      || strlen (*dname_arg) < 1 || strlen (*dname_arg) > 70)
+    {
+      fprintf (stderr, "emacs daemon: daemon name absent or too long\n");
+      exit (EXIT_CANNOT_INVOKE);
+    }
+
+process_dname:
+  dname_arg2[0] = '\0';
+#ifdef DAEMON_MUST_EXEC
+  sscanf (*dname_arg, "\n%d,%d\n%s", &(daemon_pipe[0]), &(daemon_pipe[1]),
+          dname_arg2);
+#elif defined(WINDOWSNT)
+  sscanf (*dname_arg, "*%p", &w32_daemon_event);
+#endif
+  /* On Windows, emacsclient will never pass a daemon name, so this will always
+     be NULL.  */
+  *dname_arg = *dname_arg2 ? dname_arg2 : NULL;
+}
+
 /* ARGSUSED */
 int
 main (int argc, char **argv)
@@ -704,9 +745,7 @@ main (int argc, char **argv)
   bool no_loadup = 0;
   char *junk = 0;
   char *dname_arg = 0;
-#ifdef DAEMON_MUST_EXEC
   char dname_arg2[80];
-#endif
   char *ch_to_dir = 0;
 
   /* If we use --chdir, this records the original directory.  */
@@ -980,8 +1019,12 @@ main (int argc, char **argv)
       exit (0);
     }
 
+#ifndef WINDOWSNT
   /* Make sure IS_DAEMON starts up as false.  */
   daemon_pipe[1] = 0;
+#else
+  w32_daemon_event = NULL;
+#endif
 
   if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args)
       || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg, &skip_args))
@@ -1090,17 +1133,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
 	    exit (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
           }
 
-        /* In exec'd: parse special dname into pipe and name info. */
-        if (!dname_arg || !strchr (dname_arg, '\n')
-            || strlen (dname_arg) < 1 || strlen (dname_arg) > 70)
-          {
-            fprintf (stderr, "emacs daemon: daemon name absent or too long\n");
-            exit (EXIT_CANNOT_INVOKE);
-          }
-        dname_arg2[0] = '\0';
-        sscanf (dname_arg, "\n%d,%d\n%s", &(daemon_pipe[0]), &(daemon_pipe[1]),
-                dname_arg2);
-        dname_arg = *dname_arg2 ? dname_arg2 : NULL;
+        handle_dname_arg (&dname_arg, dname_arg2, '\n');
 	fcntl (daemon_pipe[1], F_SETFD, FD_CLOEXEC);
       }
 #endif /* DAEMON_MUST_EXEC */
@@ -1111,10 +1144,21 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
       emacs_close (daemon_pipe[0]);
 
       setsid ();
-#else /* DOS_NT */
+#elif defined(WINDOWSNT)
+      handle_dname_arg (&dname_arg, dname_arg2, '*');
+
+      if (w32_daemon_event == NULL)
+        {
+          fprintf (stderr, "Couldn't create or get event handle for daemon\n");
+          exit (1);
+        }
+
+      if (dname_arg)
+        daemon_name = xstrdup (dname_arg);
+#else /* MSDOS */
       fprintf (stderr, "This platform does not support the -daemon flag.\n");
       exit (1);
-#endif /* DOS_NT */
+#endif /* MSDOS */
     }
 
 #if defined HAVE_PTHREAD && !defined SYSTEM_MALLOC \
@@ -2310,23 +2354,40 @@ If the daemon was given a name argument, return that name. */)
     return Qnil;
 }
 
-DEFUN ("daemon-initialized", Fdaemon_initialized, Sdaemon_initialized, 0, 0, 0,
-       doc: /* Mark the Emacs daemon as being initialized.
-This finishes the daemonization process by doing the other half of detaching
-from the parent process and its tty file descriptors.  */)
-  (void)
+static void
+daemon_check_preconditions (void)
 {
-  int nfd;
-  bool err = 0;
-
   if (!IS_DAEMON)
     error ("This function can only be called if emacs is run as a daemon");
 
-  if (daemon_pipe[1] < 0)
+#ifdef WINDOWSNT
+  /* IS_DAEMON above already checks that w32_daemon_event != NULL, so only
+     check that we successfully started the daemon here.  */
+  if (w32_daemon_event == INVALID_HANDLE_VALUE)
+#else
+  if (daemon_pipe[1] < 0 )
+#endif
     error ("The daemon has already been initialized");
 
   if (NILP (Vafter_init_time))
     error ("This function can only be called after loading the init files");
+}
+
+DEFUN ("daemon-initialized", Fdaemon_initialized, Sdaemon_initialized, 0, 0, 0,
+       doc: /* Mark the Emacs daemon as being initialized.
+This finishes the daemonization process by doing the other half of detaching
+from the parent process and its tty file descriptors.  */)
+  (void)
+{
+  daemon_check_preconditions ();
+#ifdef WINDOWSNT
+  /* Signal the waiting emacsclient process.  */
+  SetEvent (w32_daemon_event);
+  CloseHandle (w32_daemon_event);
+  w32_daemon_event = INVALID_HANDLE_VALUE;
+#else
+  int nfd;
+  bool err = 0;
 
   /* Get rid of stdin, stdout and stderr.  */
   nfd = emacs_open ("/dev/null", O_RDWR, 0);
@@ -2350,6 +2411,7 @@ from the parent process and its tty file descriptors.  */)
 
   if (err)
     error ("I/O error during daemon initialization");
+#endif
   return Qt;
 }
 
diff --git a/src/keyboard.c b/src/keyboard.c
index 383c109..8f0e18f 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -3829,7 +3829,11 @@ kbd_buffer_get_event (KBOARD **kbp,
   if (noninteractive
       /* In case we are running as a daemon, only do this before
 	 detaching from the terminal.  */
+#ifdef WINDOWSNT
+      || (IS_DAEMON && w32_daemon_event != INVALID_HANDLE_VALUE))
+#else
       || (IS_DAEMON && daemon_pipe[1] >= 0))
+#endif
     {
       int c = getchar ();
       XSETINT (obj, c);
diff --git a/src/lisp.h b/src/lisp.h
index f5242ab..0b85817 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4215,9 +4215,14 @@ extern bool noninteractive;
 extern bool no_site_lisp;
 
 /* Pipe used to send exit notification to the daemon parent at
-   startup.  */
+   startup.  On Windows, we use a kernel event instead.  */
+#ifndef WINDOWSNT
 extern int daemon_pipe[2];
 #define IS_DAEMON (daemon_pipe[1] != 0)
+#elif defined(WINDOWSNT)
+extern void *w32_daemon_event;
+#define IS_DAEMON (w32_daemon_event != NULL)
+#endif
 
 /* True if handling a fatal error already.  */
 extern bool fatal_error_in_progress;
diff --git a/src/minibuf.c b/src/minibuf.c
index 3408bb9..dee7ce8 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -459,7 +459,11 @@ read_minibuf (Lisp_Object map, Lisp_Object initial, Lisp_Object prompt,
   if ((noninteractive
        /* In case we are running as a daemon, only do this before
 	  detaching from the terminal.  */
+#ifdef WINDOWSNT
+       || (IS_DAEMON && w32_daemon_event != INVALID_HANDLE_VALUE))
+#else
        || (IS_DAEMON && (daemon_pipe[1] >= 0)))
+#endif
       && NILP (Vexecuting_kbd_macro))
     {
       val = read_minibuf_noninteractive (map, initial, prompt,
