Bug 1518639: Implement windows remoting server and client. r=jimm
authorDave Townsend <dtownsend@oxymoronical.com>
Wed, 06 Feb 2019 14:18:35 -0800
changeset 462624 fe3cd9f0d12bae82190bd17ea474d1a2f4bb80a2
parent 462623 61ed2a0798487c50c5faf70241aa637d01da6b10
child 462625 19d1f6485a134fa0ede7677a4a7ea7e5cee40a1b
push id112320
push userdtownsend@mozilla.com
push dateWed, 06 Mar 2019 20:45:57 +0000
treeherdermozilla-inbound@fe3cd9f0d12b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1518639
milestone67.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1518639: Implement windows remoting server and client. r=jimm Implements the windows remove client and server based on the current remoting code in nsNativeAppSupportWin.cpp. Makes the hidden window classname encode both program name and profile name. nsNativeAppSupportWin is now just used for setting up the console. Differential Revision: https://phabricator.services.mozilla.com/D19076
ipc/glue/WindowsMessageLoop.cpp
toolkit/components/remote/nsWinRemoteClient.cpp
toolkit/components/remote/nsWinRemoteServer.cpp
toolkit/components/remote/nsWinRemoteServer.h
toolkit/components/remote/nsWinRemoteUtils.h
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsNativeAppSupportWin.cpp
--- a/ipc/glue/WindowsMessageLoop.cpp
+++ b/ipc/glue/WindowsMessageLoop.cpp
@@ -86,19 +86,16 @@ extern UINT sAppShellGeckoMsgId;
 namespace {
 
 const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc";
 const wchar_t k3rdPartyWindowProp[] = L"Mozilla3rdPartyWindow";
 
 // This isn't defined before Windows XP.
 enum { WM_XP_THEMECHANGED = 0x031A };
 
-char16_t gAppMessageWindowName[256] = {0};
-int32_t gAppMessageWindowNameLength = 0;
-
 nsTArray<HWND>* gNeuteredWindows = nullptr;
 
 typedef nsTArray<nsAutoPtr<DeferredMessage> > DeferredMessageArray;
 DeferredMessageArray* gDeferredMessages = nullptr;
 
 HHOOK gDeferredGetMsgHook = nullptr;
 HHOOK gDeferredCallWndProcHook = nullptr;
 
@@ -469,44 +466,16 @@ static bool WindowIsDeferredWindow(HWND 
 
   // Plugin windows that can trigger ipc calls in child:
   // 'ShockwaveFlashFullScreen' - flash fullscreen window
   if (className.EqualsLiteral("ShockwaveFlashFullScreen")) {
     SetPropW(hWnd, k3rdPartyWindowProp, (HANDLE)1);
     return true;
   }
 
-  // nsNativeAppSupport makes a window like "FirefoxMessageWindow" based on the
-  // toolkit app's name. It's pretty expensive to calculate this so we only try
-  // once.
-  if (gAppMessageWindowNameLength == 0) {
-    nsCOMPtr<nsIXULAppInfo> appInfo =
-        do_GetService("@mozilla.org/xre/app-info;1");
-    if (appInfo) {
-      nsAutoCString appName;
-      if (NS_SUCCEEDED(appInfo->GetName(appName))) {
-        appName.AppendLiteral("MessageWindow");
-        nsDependentString windowName(gAppMessageWindowName);
-        CopyUTF8toUTF16(appName, windowName);
-        gAppMessageWindowNameLength = windowName.Length();
-      }
-    }
-
-    // Don't try again if that failed.
-    if (gAppMessageWindowNameLength == 0) {
-      gAppMessageWindowNameLength = -1;
-    }
-  }
-
-  if (gAppMessageWindowNameLength != -1 &&
-      className.Equals(nsDependentString(gAppMessageWindowName,
-                                         gAppMessageWindowNameLength))) {
-    return true;
-  }
-
   return false;
 }
 
 bool NeuterWindowProcedure(HWND hWnd) {
   if (!WindowIsDeferredWindow(hWnd)) {
     // Some other kind of window, skip.
     return false;
   }
--- a/toolkit/components/remote/nsWinRemoteClient.cpp
+++ b/toolkit/components/remote/nsWinRemoteClient.cpp
@@ -1,20 +1,57 @@
 /* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=4:tabstop=4:
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsWinRemoteClient.h"
+#include "nsWinRemoteUtils.h"
+
+#include <windows.h>
+
+using namespace mozilla;
 
 nsresult nsWinRemoteClient::Init() {
   return NS_OK;
 }
 
 nsresult nsWinRemoteClient::SendCommandLine(const char *aProgram, const char *aProfile,
                                             int32_t argc, char **argv,
                                             const char *aDesktopStartupID,
                                             char **aResponse, bool *aSucceeded) {
   *aSucceeded = false;
+
+  nsString className;
+  BuildClassName(aProgram, aProfile, className);
+
+  HWND handle = ::FindWindowW(className.get(), 0);
+
+  if (!handle) {
+    return NS_OK;
+  }
+
+  WCHAR *cmd = ::GetCommandLineW();
+  WCHAR cwd[MAX_PATH];
+  _wgetcwd(cwd, MAX_PATH);
+
+  // Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
+  NS_ConvertUTF16toUTF8 utf8buffer(cmd);
+  utf8buffer.Append('\0');
+  WCHAR *cwdPtr = cwd;
+  AppendUTF16toUTF8(MakeStringSpan(reinterpret_cast<char16_t *>(cwdPtr)),
+                    utf8buffer);
+  utf8buffer.Append('\0');
+
+  // We used to set dwData to zero, when we didn't send the working dir.
+  // Now we're using it as a version number.
+  COPYDATASTRUCT cds = {1, utf8buffer.Length(), (void *)utf8buffer.get()};
+  // Bring the already running Mozilla process to the foreground.
+  // nsWindow will restore the window (if minimized) and raise it.
+  ::SetForegroundWindow(handle);
+  ::SendMessage(handle, WM_COPYDATA, 0, (LPARAM)&cds);
+
+  *aSucceeded = true;
+
   return NS_OK;
 }
--- a/toolkit/components/remote/nsWinRemoteServer.cpp
+++ b/toolkit/components/remote/nsWinRemoteServer.cpp
@@ -1,16 +1,271 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim:expandtab:shiftwidth=2:tabstop=2:
  */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsWinRemoteServer.h"
+#include "nsWinRemoteUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIComponentManager.h"
+#include "nsIServiceManager.h"
+#include "nsIDOMChromeWindow.h"
+#include "nsXPCOM.h"
+#include "nsPIDOMWindow.h"
+#include "nsIWindowMediator.h"
+#include "nsIBaseWindow.h"
+#include "nsIWidget.h"
+#include "nsICommandLineRunner.h"
+#include "nsICommandLine.h"
+#include "nsCommandLine.h"
+#include "nsIDocShell.h"
+
+HWND hwndForDOMWindow(mozIDOMWindowProxy *window) {
+  if (!window) {
+    return 0;
+  }
+  nsCOMPtr<nsPIDOMWindowOuter> pidomwindow = nsPIDOMWindowOuter::From(window);
+
+  nsCOMPtr<nsIBaseWindow> ppBaseWindow =
+      do_QueryInterface(pidomwindow->GetDocShell());
+  if (!ppBaseWindow) {
+    return 0;
+  }
+
+  nsCOMPtr<nsIWidget> ppWidget;
+  ppBaseWindow->GetMainWidget(getter_AddRefs(ppWidget));
+
+  return (HWND)(ppWidget->GetNativeData(NS_NATIVE_WIDGET));
+}
+
+static nsresult GetMostRecentWindow(mozIDOMWindowProxy **aWindow) {
+  nsresult rv;
+  nsCOMPtr<nsIWindowMediator> med(
+      do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
+  if (NS_FAILED(rv)) return rv;
+
+  if (med) return med->GetMostRecentWindow(nullptr, aWindow);
+
+  return NS_ERROR_FAILURE;
+}
+
+void HandleCommandLine(const char *aCmdLineString, nsIFile *aWorkingDir,
+                       uint32_t aState) {
+  nsresult rv;
+
+  int justCounting = 1;
+  char **argv = 0;
+  // Flags, etc.
+  int init = 1;
+  int between, quoted, bSlashCount;
+  int argc;
+  const char *p;
+  nsAutoCString arg;
+
+  nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
+
+  // Parse command line args according to MS spec
+  // (see "Parsing C++ Command-Line Arguments" at
+  // http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
+  // We loop if we've not finished the second pass through.
+  while (1) {
+    // Initialize if required.
+    if (init) {
+      p = aCmdLineString;
+      between = 1;
+      argc = quoted = bSlashCount = 0;
+
+      init = 0;
+    }
+    if (between) {
+      // We are traversing whitespace between args.
+      // Check for start of next arg.
+      if (*p != 0 && !isspace(*p)) {
+        // Start of another arg.
+        between = 0;
+        arg = "";
+        switch (*p) {
+          case '\\':
+            // Count the backslash.
+            bSlashCount = 1;
+            break;
+          case '"':
+            // Remember we're inside quotes.
+            quoted = 1;
+            break;
+          default:
+            // Add character to arg.
+            arg += *p;
+            break;
+        }
+      } else {
+        // Another space between args, ignore it.
+      }
+    } else {
+      // We are processing the contents of an argument.
+      // Check for whitespace or end.
+      if (*p == 0 || (!quoted && isspace(*p))) {
+        // Process pending backslashes (interpret them
+        // literally since they're not followed by a ").
+        while (bSlashCount) {
+          arg += '\\';
+          bSlashCount--;
+        }
+        // End current arg.
+        if (!justCounting) {
+          argv[argc] = new char[arg.Length() + 1];
+          strcpy(argv[argc], arg.get());
+        }
+        argc++;
+        // We're now between args.
+        between = 1;
+      } else {
+        // Still inside argument, process the character.
+        switch (*p) {
+          case '"':
+            // First, digest preceding backslashes (if any).
+            while (bSlashCount > 1) {
+              // Put one backsplash in arg for each pair.
+              arg += '\\';
+              bSlashCount -= 2;
+            }
+            if (bSlashCount) {
+              // Quote is literal.
+              arg += '"';
+              bSlashCount = 0;
+            } else {
+              // Quote starts or ends a quoted section.
+              if (quoted) {
+                // Check for special case of consecutive double
+                // quotes inside a quoted section.
+                if (*(p + 1) == '"') {
+                  // This implies a literal double-quote.  Fake that
+                  // out by causing next double-quote to look as
+                  // if it was preceded by a backslash.
+                  bSlashCount = 1;
+                } else {
+                  quoted = 0;
+                }
+              } else {
+                quoted = 1;
+              }
+            }
+            break;
+          case '\\':
+            // Add to count.
+            bSlashCount++;
+            break;
+          default:
+            // Accept any preceding backslashes literally.
+            while (bSlashCount) {
+              arg += '\\';
+              bSlashCount--;
+            }
+            // Just add next char to the current arg.
+            arg += *p;
+            break;
+        }
+      }
+    }
+    // Check for end of input.
+    if (*p) {
+      // Go to next character.
+      p++;
+    } else {
+      // If on first pass, go on to second.
+      if (justCounting) {
+        // Allocate argv array.
+        argv = new char *[argc];
+
+        // Start second pass
+        justCounting = 0;
+        init = 1;
+      } else {
+        // Quit.
+        break;
+      }
+    }
+  }
+
+  rv = cmdLine->Init(argc, argv, aWorkingDir, aState);
+
+  // Cleanup.
+  while (argc) {
+    delete[] argv[--argc];
+  }
+  delete[] argv;
+
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Error initializing command line.");
+    return;
+  }
+
+  cmdLine->Run();
+}
+
+LRESULT CALLBACK WindowProc(HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp) {
+  if (msg == WM_COPYDATA) {
+    // This is an incoming request.
+    COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lp;
+    nsCOMPtr<nsIFile> workingDir;
+
+    if (1 >= cds->dwData) {
+      char *wdpath = (char *)cds->lpData;
+      // skip the command line, and get the working dir of the
+      // other process, which is after the first null char
+      while (*wdpath) ++wdpath;
+
+      ++wdpath;
+
+      NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath), false,
+                      getter_AddRefs(workingDir));
+    }
+    HandleCommandLine((char *)cds->lpData, workingDir,
+                      nsICommandLine::STATE_REMOTE_AUTO);
+
+    // Get current window and return its window handle.
+    nsCOMPtr<mozIDOMWindowProxy> win;
+    GetMostRecentWindow(getter_AddRefs(win));
+    return win ? (LRESULT)hwndForDOMWindow(win) : 0;
+  }
+  return DefWindowProc(msgWindow, msg, wp, lp);
+}
 
 nsresult nsWinRemoteServer::Startup(const char* aAppName,
     const char* aProfileName) {
-  return NS_OK;
+
+  nsString className;
+  BuildClassName(aAppName, aProfileName, className);
+
+  WNDCLASSW classStruct = {0,                           // style
+                           &WindowProc,                 // lpfnWndProc
+                           0,                           // cbClsExtra
+                           0,                           // cbWndExtra
+                           0,                           // hInstance
+                           0,                           // hIcon
+                           0,                           // hCursor
+                           0,                           // hbrBackground
+                           0,                           // lpszMenuName
+                           className.get()};            // lpszClassName
+
+  // Register the window class.
+  NS_ENSURE_TRUE(::RegisterClassW(&classStruct), NS_ERROR_FAILURE);
+
+  // Create the window.
+  mHandle = ::CreateWindowW(className.get(),
+                            0,           // title
+                            WS_CAPTION,  // style
+                            0, 0, 0, 0,  // x, y, cx, cy
+                            0,           // parent
+                            0,           // menu
+                            0,           // instance
+                            0);          // create struct
+
+  return mHandle ? NS_OK : NS_ERROR_FAILURE;
 }
 
 void nsWinRemoteServer::Shutdown() {
+  DestroyWindow(mHandle);
+  mHandle = nullptr;
 }
--- a/toolkit/components/remote/nsWinRemoteServer.h
+++ b/toolkit/components/remote/nsWinRemoteServer.h
@@ -5,18 +5,23 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __nsWinRemoteServer_h__
 #define __nsWinRemoteServer_h__
 
 #include "nsRemoteServer.h"
 
+#include <windows.h>
+
 class nsWinRemoteServer final : public nsRemoteServer {
  public:
   nsWinRemoteServer() = default;
   ~nsWinRemoteServer() override = default;
 
   nsresult Startup(const char* aAppName, const char* aProfileName) override;
   void Shutdown() override;
+
+ private:
+  HWND mHandle;
 };
 
 #endif  // __nsWinRemoteService_h__
new file mode 100644
--- /dev/null
+++ b/toolkit/components/remote/nsWinRemoteUtils.h
@@ -0,0 +1,18 @@
+/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsWinRemoteUtils_h__
+#define nsWinRemoteUtils_h__
+
+#include "nsString.h"
+
+static void BuildClassName(const char *aProgram, const char *aProfile,
+                           nsString& aClassName) {
+  aClassName.AppendPrintf("Mozilla_%s_%s_RemoteWindow", aProgram, aProfile);
+}
+
+#endif  // nsWinRemoteUtils_h__
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1411,20 +1411,22 @@ static void DumpHelp() {
 
   printf(
       "  -h or --help       Print this message.\n"
       "  -v or --version    Print %s version.\n"
       "  -P <profile>       Start with <profile>.\n"
       "  --profile <path>   Start with profile at <path>.\n"
       "  --migration        Start with migration wizard.\n"
       "  --ProfileManager   Start with ProfileManager.\n"
+#ifdef MOZ_HAS_REMOTE
       "  --no-remote        Do not accept or send remote commands; implies\n"
       "                     --new-instance.\n"
       "  --new-instance     Open new instance, not a new window in running "
       "instance.\n"
+#endif
       "  --UILocale <locale> Start with <locale> resources as UI Locale.\n"
       "  --safe-mode        Disables extensions and themes for this session.\n"
 #ifdef MOZ_BLOCK_PROFILE_DOWNGRADE
       "  --allow-downgrade  Allows downgrading a profile.\n"
 #endif
       "  -MOZ_LOG=<modules> Treated as MOZ_LOG=<modules> environment variable, "
       "overrides it.\n"
       "  -MOZ_LOG_FILE=<file> Treated as MOZ_LOG_FILE=<file> environment "
@@ -3317,48 +3319,51 @@ int XREMain::XRE_mainInit(bool* aExitFla
           nsPrintfCString("0x%x", cpuUpdateRevision));
     }
   }
 #endif
 
   CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::SafeMode,
                                      gSafeMode);
 
+#if defined(MOZ_HAS_REMOTE)
   // Handle --no-remote and --new-instance command line arguments. Setup
   // the environment to better accommodate other components and various
   // restart scenarios.
   ar = CheckArg("no-remote", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --no-remote is invalid when argument --osint "
                "is specified\n");
     return 1;
   }
   if (ar == ARG_FOUND) {
     SaveToEnv("MOZ_NO_REMOTE=1");
-#if defined(MOZ_HAS_REMOTE)
     mDisableRemote = true;
   } else if (EnvHasValue("MOZ_NO_REMOTE")) {
     mDisableRemote = true;
-#endif
-  }
-
-#if defined(MOZ_HAS_REMOTE)
+  }
+
   ar = CheckArg("new-instance", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --new-instance is invalid when argument "
                "--osint is specified\n");
     return 1;
   }
   if (ar == ARG_FOUND || EnvHasValue("MOZ_NEW_INSTANCE")) {
     mDisableRemote = true;
   }
+#else
+  // These arguments do nothing in platforms with no remoting support but we
+  // should remove them from the command line anyway.
+  CheckArg("no-remote");
+  CheckArg("new-instance");
 #endif
 
   ar = CheckArg("offline", nullptr,
                 CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
   if (ar == ARG_BAD) {
     PR_fprintf(PR_STDERR,
                "Error: argument --offline is invalid when argument --osint is "
                "specified\n");
--- a/toolkit/xre/nsNativeAppSupportWin.cpp
+++ b/toolkit/xre/nsNativeAppSupportWin.cpp
@@ -1,154 +1,36 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsNativeAppSupportBase.h"
 #include "nsNativeAppSupportWin.h"
-#include "nsAppRunner.h"
-#include "nsContentUtils.h"
-#include "nsXULAppAPI.h"
-#include "nsString.h"
-#include "nsIBrowserDOMWindow.h"
-#include "nsCommandLine.h"
-#include "nsCOMPtr.h"
-#include "nsIComponentManager.h"
-#include "nsIServiceManager.h"
-#include "nsIDOMChromeWindow.h"
-#include "nsXPCOM.h"
-#include "nsISupportsPrimitives.h"
-#include "nsIWindowWatcher.h"
-#include "nsPIDOMWindow.h"
-#include "nsGlobalWindow.h"
-#include "nsIDocShell.h"
-#include "nsIDocShellTreeItem.h"
-#include "nsIBaseWindow.h"
-#include "nsIWidget.h"
-#include "nsIAppShellService.h"
-#include "nsIXULWindow.h"
-#include "nsIInterfaceRequestor.h"
-#include "nsIInterfaceRequestorUtils.h"
-#include "nsIPromptService.h"
-#include "nsNetCID.h"
-#include "nsNetUtil.h"
-#include "mozilla/Services.h"
-#include "nsIFile.h"
-#include "nsIObserver.h"
-#include "nsIObserverService.h"
-#include "nsIWebNavigation.h"
-#include "nsIWindowMediator.h"
-#include "nsNativeCharsetUtils.h"
-#include "nsIAppStartup.h"
-#include "mozilla/Assertions.h"
-#include "mozilla/dom/Location.h"
 
 #include <windows.h>
-#include <shellapi.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <io.h>
-#include <direct.h>
 #include <fcntl.h>
 
 using namespace mozilla;
 
-static HWND hwndForDOMWindow(mozIDOMWindowProxy *);
-
-static nsresult GetMostRecentWindow(const char16_t *aType,
-                                    mozIDOMWindowProxy **aWindow) {
-  nsresult rv;
-  nsCOMPtr<nsIWindowMediator> med(
-      do_GetService(NS_WINDOWMEDIATOR_CONTRACTID, &rv));
-  if (NS_FAILED(rv)) return rv;
-
-  if (med) return med->GetMostRecentWindow(aType, aWindow);
-
-  return NS_ERROR_FAILURE;
-}
-
-// Simple Win32 mutex wrapper.
-struct Win32Mutex {
-  explicit Win32Mutex(const char16_t *name)
-      : mName(name), mHandle(0), mState(-1) {
-    mHandle = CreateMutexW(0, FALSE, mName.get());
-  }
-  ~Win32Mutex() {
-    if (mHandle) {
-      // Make sure we release it if we own it.
-      Unlock();
-
-      BOOL rc MOZ_MAYBE_UNUSED = CloseHandle(mHandle);
-    }
-  }
-  BOOL Lock(DWORD timeout) {
-    if (mHandle) {
-      mState = WaitForSingleObject(mHandle, timeout);
-      return mState == WAIT_OBJECT_0 || mState == WAIT_ABANDONED;
-    } else {
-      return FALSE;
-    }
-  }
-  void Unlock() {
-    if (mHandle && mState == WAIT_OBJECT_0) {
-      ReleaseMutex(mHandle);
-      mState = -1;
-    }
-  }
-
- private:
-  nsString mName;
-  HANDLE mHandle;
-  DWORD mState;
-};
-
-class MessageWindow;
-
 /*
- * This code implements remoting a command line to an existing instance. It uses
- * a "message window" to detect that Mozilla is already running and to pass
- * the command line of a new instance to the already running instance.
- * We use the mutex semaphore to protect the code that detects whether Mozilla
- * is already running.
+ * This code attaches the process to the appropriate console.
  */
 
-class nsNativeAppSupportWin : public nsNativeAppSupportBase,
-                              public nsIObserver {
+class nsNativeAppSupportWin : public nsNativeAppSupportBase {
  public:
-  NS_DECL_NSIOBSERVER
-  NS_DECL_ISUPPORTS_INHERITED
-
-  // Overrides of base implementation.
-  NS_IMETHOD Start(bool *aResult) override;
-  NS_IMETHOD Quit() override;
-  NS_IMETHOD Enable() override;
   // Utility function to handle a Win32-specific command line
   // option: "--console", which dynamically creates a Windows
   // console.
   void CheckConsole();
 
  private:
   ~nsNativeAppSupportWin() {}
-  static void HandleCommandLine(const char *aCmdLineString,
-                                nsIFile *aWorkingDir, uint32_t aState);
-
-  static bool mCanHandleRequests;
-  static char16_t mMutexName[];
-  friend class MessageWindow;
-  static MessageWindow *mMsgWindow;
 };  // nsNativeAppSupportWin
 
-NS_INTERFACE_MAP_BEGIN(nsNativeAppSupportWin)
-  NS_INTERFACE_MAP_ENTRY(nsIObserver)
-NS_INTERFACE_MAP_END_INHERITING(nsNativeAppSupportBase)
-
-NS_IMPL_ADDREF_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
-NS_IMPL_RELEASE_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
-
 void UseParentConsole() {
   if (AttachConsole(ATTACH_PARENT_PROCESS)) {
     // Redirect the standard streams to the existing console, but
     // only if they haven't been redirected to a valid file.
     // Visual Studio's _fileno() returns -2 for the standard
     // streams if they aren't associated with an output stream.
     if (_fileno(stdout) == -2) {
       freopen("CONOUT$", "w", stdout);
@@ -200,430 +82,8 @@ nsresult NS_CreateNativeAppSupport(nsINa
   // Check for dynamic console creation request.
   pNative->CheckConsole();
 
   *aResult = pNative;
   NS_ADDREF(*aResult);
 
   return NS_OK;
 }
-
-// Constants
-#define MOZ_MUTEX_NAMESPACE L"Local\\"
-#define MOZ_STARTUP_MUTEX_NAME L"StartupMutex"
-#define MOZ_MUTEX_START_TIMEOUT 30000
-
-// Static member definitions.
-char16_t nsNativeAppSupportWin::mMutexName[128] = {0};
-bool nsNativeAppSupportWin::mCanHandleRequests = false;
-MessageWindow *nsNativeAppSupportWin::mMsgWindow = nullptr;
-
-// Message window encapsulation.
-class MessageWindow final {
- public:
-  // ctor/dtor are simplistic
-  MessageWindow() {
-    // Try to find window.
-    mHandle = ::FindWindowW(className(), 0);
-  }
-
-  ~MessageWindow() = default;
-
-  // Act like an HWND.
-  HWND handle() { return mHandle; }
-
-  // Class name: appName + "MessageWindow"
-  static const wchar_t *className() {
-    static wchar_t classNameBuffer[128];
-    static wchar_t *mClassName = 0;
-    if (!mClassName) {
-      ::_snwprintf(classNameBuffer,
-                   128,  // size of classNameBuffer in PRUnichars
-                   L"%s%s",
-                   static_cast<const wchar_t *>(
-                       NS_ConvertUTF8toUTF16(gAppData->remotingName).get()),
-                   L"MessageWindow");
-      mClassName = classNameBuffer;
-    }
-    return mClassName;
-  }
-
-  // Create: Register class and create window.
-  NS_IMETHOD Create() {
-    WNDCLASSW classStruct = {0,                           // style
-                             &MessageWindow::WindowProc,  // lpfnWndProc
-                             0,                           // cbClsExtra
-                             0,                           // cbWndExtra
-                             0,                           // hInstance
-                             0,                           // hIcon
-                             0,                           // hCursor
-                             0,                           // hbrBackground
-                             0,                           // lpszMenuName
-                             className()};                // lpszClassName
-
-    // Register the window class.
-    NS_ENSURE_TRUE(::RegisterClassW(&classStruct), NS_ERROR_FAILURE);
-
-    // Create the window.
-    NS_ENSURE_TRUE((mHandle = ::CreateWindowW(className(),
-                                              0,           // title
-                                              WS_CAPTION,  // style
-                                              0, 0, 0, 0,  // x, y, cx, cy
-                                              0,           // parent
-                                              0,           // menu
-                                              0,           // instance
-                                              0)),         // create struct
-                   NS_ERROR_FAILURE);
-
-    return NS_OK;
-  }
-
-  // Destory:  Get rid of window and reset mHandle.
-  NS_IMETHOD Destroy() {
-    nsresult retval = NS_OK;
-
-    if (mHandle) {
-      // DestroyWindow can only destroy windows created from
-      //  the same thread.
-      BOOL desRes = DestroyWindow(mHandle);
-      if (FALSE != desRes) {
-        mHandle = nullptr;
-      } else {
-        retval = NS_ERROR_FAILURE;
-      }
-    }
-
-    return retval;
-  }
-
-  // SendRequest: Pass the command line via WM_COPYDATA to message window.
-  NS_IMETHOD SendRequest() {
-    WCHAR *cmd = ::GetCommandLineW();
-    WCHAR cwd[MAX_PATH];
-    _wgetcwd(cwd, MAX_PATH);
-
-    // Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
-    NS_ConvertUTF16toUTF8 utf8buffer(cmd);
-    utf8buffer.Append('\0');
-    WCHAR *cwdPtr = cwd;
-    AppendUTF16toUTF8(MakeStringSpan(reinterpret_cast<char16_t *>(cwdPtr)),
-                      utf8buffer);
-    utf8buffer.Append('\0');
-
-    // We used to set dwData to zero, when we didn't send the working dir.
-    // Now we're using it as a version number.
-    COPYDATASTRUCT cds = {1, utf8buffer.Length(), (void *)utf8buffer.get()};
-    // Bring the already running Mozilla process to the foreground.
-    // nsWindow will restore the window (if minimized) and raise it.
-    ::SetForegroundWindow(mHandle);
-    ::SendMessage(mHandle, WM_COPYDATA, 0, (LPARAM)&cds);
-    return NS_OK;
-  }
-
-  // Window proc.
-  static LRESULT CALLBACK WindowProc(HWND msgWindow, UINT msg, WPARAM wp,
-                                     LPARAM lp) {
-    if (msg == WM_COPYDATA) {
-      if (!nsNativeAppSupportWin::mCanHandleRequests) return FALSE;
-
-      // This is an incoming request.
-      COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lp;
-      nsCOMPtr<nsIFile> workingDir;
-
-      if (1 >= cds->dwData) {
-        char *wdpath = (char *)cds->lpData;
-        // skip the command line, and get the working dir of the
-        // other process, which is after the first null char
-        while (*wdpath) ++wdpath;
-
-        ++wdpath;
-
-        NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath), false,
-                        getter_AddRefs(workingDir));
-      }
-      (void)nsNativeAppSupportWin::HandleCommandLine(
-          (char *)cds->lpData, workingDir, nsICommandLine::STATE_REMOTE_AUTO);
-
-      // Get current window and return its window handle.
-      nsCOMPtr<mozIDOMWindowProxy> win;
-      GetMostRecentWindow(0, getter_AddRefs(win));
-      return win ? (LRESULT)hwndForDOMWindow(win) : 0;
-    }
-    return DefWindowProc(msgWindow, msg, wp, lp);
-  }
-
- private:
-  HWND mHandle;
-};  // class MessageWindow
-
-/* Start: Tries to find the "message window" to determine if it
- *        exists.  If so, then Mozilla is already running.  In that
- *        case, we use the handle to the "message" window and send
- *        a request corresponding to this process's command line
- *        options.
- *
- *        If not, then this is the first instance of Mozilla.  In
- *        that case, we create and set up the message window.
- *
- *        The checking for existence of the message window must
- *        be protected by use of a mutex semaphore.
- */
-NS_IMETHODIMP
-nsNativeAppSupportWin::Start(bool *aResult) {
-  NS_ENSURE_ARG(aResult);
-  NS_ENSURE_STATE(gAppData);
-
-  if (getenv("MOZ_NO_REMOTE")) {
-    *aResult = true;
-    return NS_OK;
-  }
-
-  nsresult rv = NS_ERROR_FAILURE;
-  *aResult = false;
-
-  // Grab mutex first.
-
-  // Build mutex name from app name.
-  ::_snwprintf(
-      reinterpret_cast<wchar_t *>(mMutexName),
-      sizeof mMutexName / sizeof(char16_t), L"%s%s%s", MOZ_MUTEX_NAMESPACE,
-      static_cast<const wchar_t *>(NS_ConvertUTF8toUTF16(gAppData->name).get()),
-      MOZ_STARTUP_MUTEX_NAME);
-  Win32Mutex startupLock = Win32Mutex(mMutexName);
-
-  NS_ENSURE_TRUE(startupLock.Lock(MOZ_MUTEX_START_TIMEOUT), NS_ERROR_FAILURE);
-
-  // Search for existing message window.
-  mMsgWindow = new MessageWindow();
-  if (mMsgWindow->handle()) {
-    // We are a client process.  Pass request to message window.
-    rv = mMsgWindow->SendRequest();
-  } else {
-    // We will be server.
-    rv = mMsgWindow->Create();
-    if (NS_SUCCEEDED(rv)) {
-      // Tell caller to spin message loop.
-      *aResult = true;
-    }
-  }
-
-  startupLock.Unlock();
-
-  return rv;
-}
-
-NS_IMETHODIMP
-nsNativeAppSupportWin::Observe(nsISupports *aSubject, const char *aTopic,
-                               const char16_t *aData) {
-  if (strcmp(aTopic, "quit-application") == 0) {
-    Quit();
-  } else {
-    NS_ERROR("Unexpected observer topic.");
-  }
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNativeAppSupportWin::Quit() {
-  if (!mMsgWindow) {
-    return NS_OK;
-  }
-
-  // If another process wants to look for the message window, they need
-  // to wait to hold the lock, in which case they will not find the
-  // window as we will destroy ours under our lock.
-  // When the mutex goes off the stack, it is unlocked via destructor.
-  Win32Mutex mutexLock(mMutexName);
-  NS_ENSURE_TRUE(mutexLock.Lock(MOZ_MUTEX_START_TIMEOUT), NS_ERROR_FAILURE);
-
-  mMsgWindow->Destroy();
-  delete mMsgWindow;
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsNativeAppSupportWin::Enable() {
-  mCanHandleRequests = true;
-
-  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
-  if (obs) {
-    obs->AddObserver(this, "quit-application", false);
-  } else {
-    NS_ERROR("No observer service?");
-  }
-
-  return NS_OK;
-}
-
-void nsNativeAppSupportWin::HandleCommandLine(const char *aCmdLineString,
-                                              nsIFile *aWorkingDir,
-                                              uint32_t aState) {
-  nsresult rv;
-
-  int justCounting = 1;
-  char **argv = 0;
-  // Flags, etc.
-  int init = 1;
-  int between, quoted, bSlashCount;
-  int argc;
-  const char *p;
-  nsAutoCString arg;
-
-  nsCOMPtr<nsICommandLineRunner> cmdLine(new nsCommandLine());
-
-  // Parse command line args according to MS spec
-  // (see "Parsing C++ Command-Line Arguments" at
-  // http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
-  // We loop if we've not finished the second pass through.
-  while (1) {
-    // Initialize if required.
-    if (init) {
-      p = aCmdLineString;
-      between = 1;
-      argc = quoted = bSlashCount = 0;
-
-      init = 0;
-    }
-    if (between) {
-      // We are traversing whitespace between args.
-      // Check for start of next arg.
-      if (*p != 0 && !isspace(*p)) {
-        // Start of another arg.
-        between = 0;
-        arg = "";
-        switch (*p) {
-          case '\\':
-            // Count the backslash.
-            bSlashCount = 1;
-            break;
-          case '"':
-            // Remember we're inside quotes.
-            quoted = 1;
-            break;
-          default:
-            // Add character to arg.
-            arg += *p;
-            break;
-        }
-      } else {
-        // Another space between args, ignore it.
-      }
-    } else {
-      // We are processing the contents of an argument.
-      // Check for whitespace or end.
-      if (*p == 0 || (!quoted && isspace(*p))) {
-        // Process pending backslashes (interpret them
-        // literally since they're not followed by a ").
-        while (bSlashCount) {
-          arg += '\\';
-          bSlashCount--;
-        }
-        // End current arg.
-        if (!justCounting) {
-          argv[argc] = new char[arg.Length() + 1];
-          strcpy(argv[argc], arg.get());
-        }
-        argc++;
-        // We're now between args.
-        between = 1;
-      } else {
-        // Still inside argument, process the character.
-        switch (*p) {
-          case '"':
-            // First, digest preceding backslashes (if any).
-            while (bSlashCount > 1) {
-              // Put one backsplash in arg for each pair.
-              arg += '\\';
-              bSlashCount -= 2;
-            }
-            if (bSlashCount) {
-              // Quote is literal.
-              arg += '"';
-              bSlashCount = 0;
-            } else {
-              // Quote starts or ends a quoted section.
-              if (quoted) {
-                // Check for special case of consecutive double
-                // quotes inside a quoted section.
-                if (*(p + 1) == '"') {
-                  // This implies a literal double-quote.  Fake that
-                  // out by causing next double-quote to look as
-                  // if it was preceded by a backslash.
-                  bSlashCount = 1;
-                } else {
-                  quoted = 0;
-                }
-              } else {
-                quoted = 1;
-              }
-            }
-            break;
-          case '\\':
-            // Add to count.
-            bSlashCount++;
-            break;
-          default:
-            // Accept any preceding backslashes literally.
-            while (bSlashCount) {
-              arg += '\\';
-              bSlashCount--;
-            }
-            // Just add next char to the current arg.
-            arg += *p;
-            break;
-        }
-      }
-    }
-    // Check for end of input.
-    if (*p) {
-      // Go to next character.
-      p++;
-    } else {
-      // If on first pass, go on to second.
-      if (justCounting) {
-        // Allocate argv array.
-        argv = new char *[argc];
-
-        // Start second pass
-        justCounting = 0;
-        init = 1;
-      } else {
-        // Quit.
-        break;
-      }
-    }
-  }
-
-  rv = cmdLine->Init(argc, argv, aWorkingDir, aState);
-
-  // Cleanup.
-  while (argc) {
-    delete[] argv[--argc];
-  }
-  delete[] argv;
-
-  if (NS_FAILED(rv)) {
-    NS_ERROR("Error initializing command line.");
-    return;
-  }
-
-  cmdLine->Run();
-}
-
-HWND hwndForDOMWindow(mozIDOMWindowProxy *window) {
-  if (!window) {
-    return 0;
-  }
-  nsCOMPtr<nsPIDOMWindowOuter> pidomwindow = nsPIDOMWindowOuter::From(window);
-
-  nsCOMPtr<nsIBaseWindow> ppBaseWindow =
-      do_QueryInterface(pidomwindow->GetDocShell());
-  if (!ppBaseWindow) {
-    return 0;
-  }
-
-  nsCOMPtr<nsIWidget> ppWidget;
-  ppBaseWindow->GetMainWidget(getter_AddRefs(ppWidget));
-
-  return (HWND)(ppWidget->GetNativeData(NS_NATIVE_WIDGET));
-}