Bug 396052 - Firefox fails to start when run from a directory with non-native characters, r=luser sr=neil
authorbenjamin@smedbergs.us
Mon, 31 Dec 2007 07:15:43 -0800
changeset 9738 f5cd1cb9419e70d88cf67aca2ff249ee62ba2847
parent 9737 31a72b175f977f7929a0f14df75cdaeb391081fb
child 9739 0df85748ba3ec7a21231abae21c8992ace4359c6
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-esr52@a95d42642281 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluser, neil
bugs396052
milestone1.9b3pre
Bug 396052 - Firefox fails to start when run from a directory with non-native characters, r=luser sr=neil
browser/app/Makefile.in
browser/app/nsBrowserApp.cpp
toolkit/components/commandlines/public/nsICommandLineRunner.idl
toolkit/components/commandlines/src/nsCommandLine.cpp
toolkit/mozapps/update/src/updater/Makefile.in
toolkit/mozapps/update/src/updater/archivereader.cpp
toolkit/mozapps/update/src/updater/archivereader.h
toolkit/mozapps/update/src/updater/progressui.h
toolkit/mozapps/update/src/updater/progressui_win.cpp
toolkit/mozapps/update/src/updater/updater.cpp
toolkit/profile/src/nsToolkitProfileService.cpp
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsAppRunner.h
toolkit/xre/nsNativeAppSupportWin.cpp
toolkit/xre/nsUpdateDriver.cpp
toolkit/xre/nsWindowsRestart.cpp
toolkit/xre/nsWindowsWMain.cpp
toolkit/xre/nsXULAppAPI.h
uriloader/exthandler/win/nsMIMEInfoWin.cpp
uriloader/exthandler/win/nsMIMEInfoWin.h
xpcom/string/public/nsCharTraits.h
xpcom/string/public/nsUTF8Utils.h
xulrunner/app/Makefile.in
xulrunner/app/nsXULRunnerApp.cpp
xulrunner/stub/Makefile.in
xulrunner/stub/nsXULStub.cpp
--- a/browser/app/Makefile.in
+++ b/browser/app/Makefile.in
@@ -146,16 +146,23 @@ MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
 
 NSDISTMODE = copy
 
 include $(topsrcdir)/config/config.mk
+
+ifdef _MSC_VER
+# Always enter a Windows program through wmain, whether or not we're
+# a console application.
+WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
+endif
+
 ifndef BUILD_STATIC_LIBS
 
 ifdef NS_TRACE_MALLOC
 # when libxul is enabled, trace-malloc is part of it
 ifndef MOZ_ENABLE_LIBXUL
 EXTRA_DSO_LIBS += tracemalloc
 endif
 endif
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -48,16 +48,21 @@
 #include "plstr.h"
 #include "prprf.h"
 #include "prenv.h"
 
 #include "nsCOMPtr.h"
 #include "nsILocalFile.h"
 #include "nsStringGlue.h"
 
+#ifdef XP_WIN
+// we want a wmain entry point
+#include "nsWindowsWMain.cpp"
+#endif
+
 static void Output(const char *fmt, ... )
 {
   va_list ap;
   va_start(ap, fmt);
 
 #if defined(XP_WIN) && !MOZ_WINCONSOLE
   char msg[2048];
 
@@ -151,18 +156,8 @@ int main(int argc, char* argv[])
   }
 
   int result = XRE_main(argc, argv, appData);
   XRE_FreeAppData(appData);
   if (appEnv)
     PR_smprintf_free(appEnv);
   return result;
 }
-
-#if defined( XP_WIN ) && defined( WIN32 ) && !defined(__GNUC__)
-// We need WinMain in order to not be a console app.  This function is
-// unused if we are a console application.
-int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
-{
-    // Do the real work.
-    return main( __argc, __argv );
-}
-#endif
--- a/toolkit/components/commandlines/public/nsICommandLineRunner.idl
+++ b/toolkit/components/commandlines/public/nsICommandLineRunner.idl
@@ -54,16 +54,18 @@
 interface nsICommandLineRunner : nsICommandLine
 {
   /**
    * This method assumes a native character set, and is meant to be called
    * with the argc/argv passed to main(). Talk to bsmedberg if you need to
    * create a command line using other data. argv will not be altered in any
    * way.
    *
+   * On Windows, the "native" character set is UTF-8, not the native codepage.
+   *
    * @param workingDir The working directory for resolving file and URI paths.
    * @param state      The nsICommandLine.state flag.
    */
   void init(in long argc, in nsCharPtrArray argv,
             in nsIFile workingDir, in unsigned long state);
 
   /**
    * Set the windowContext parameter.
--- a/toolkit/components/commandlines/src/nsCommandLine.cpp
+++ b/toolkit/components/commandlines/src/nsCommandLine.cpp
@@ -379,30 +379,27 @@ nsCommandLine::ResolveFile(const nsAStri
 
   rv = lf->InitWithPath(aArgument);
   if (NS_FAILED(rv)) {
     // If it's a relative path, the Init is *going* to fail. We use string magic and
     // win32 _fullpath. Note that paths of the form "\Relative\To\CurDrive" are
     // going to fail, and I haven't figured out a way to work around this without
     // the PathCombine() function, which is not available in plain win95/nt4
 
-    nsCAutoString fullPath;
-    mWorkingDir->GetNativePath(fullPath);
-
-    nsCAutoString carg;
-    NS_CopyUnicodeToNative(aArgument, carg);
+    nsAutoString fullPath;
+    mWorkingDir->GetPath(fullPath);
 
     fullPath.Append('\\');
-    fullPath.Append(carg);
+    fullPath.Append(aArgument);
 
-    char pathBuf[MAX_PATH];
-    if (!_fullpath(pathBuf, fullPath.get(), MAX_PATH))
+    WCHAR pathBuf[MAX_PATH];
+    if (!_wfullpath(pathBuf, fullPath.get(), MAX_PATH))
       return NS_ERROR_FAILURE;
 
-    rv = lf->InitWithNativePath(nsDependentCString(pathBuf));
+    rv = lf->InitWithPath(nsDependentString(pathBuf));
     if (NS_FAILED(rv)) return rv;
   }
   NS_ADDREF(*aResult = lf);
   return NS_OK;
 
 #elif defined(XP_OS2)
   nsCOMPtr<nsILocalFile> lf (do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
   NS_ENSURE_TRUE(lf, NS_ERROR_OUT_OF_MEMORY);
@@ -466,17 +463,21 @@ nsCommandLine::ResolveURI(const nsAStrin
 void
 nsCommandLine::appendArg(const char* arg)
 {
 #ifdef DEBUG_COMMANDLINE
   printf("Adding XP arg: %s\n", arg);
 #endif
 
   nsAutoString warg;
+#ifdef XP_WIN
+  CopyUTF8toUTF16(nsDependentCString(arg), warg);
+#else
   NS_CopyNativeToUnicode(nsDependentCString(arg), warg);
+#endif
 
   mArgs.AppendString(warg);
 }
 
 NS_IMETHODIMP
 nsCommandLine::Init(PRInt32 argc, char** argv, nsIFile* aWorkingDir,
                     PRUint32 aState)
 {
--- a/toolkit/mozapps/update/src/updater/Makefile.in
+++ b/toolkit/mozapps/update/src/updater/Makefile.in
@@ -47,29 +47,30 @@ include $(DEPTH)/config/autoconf.mk
 CPPSRCS = \
 	updater.cpp \
 	bspatch.cpp \
 	archivereader.cpp \
 	$(NULL)
 
 PROGRAM = updater$(BIN_SUFFIX)
 
-REQUIRES = libmar libbz2
+REQUIRES = libmar libbz2 string
 
 LIBS += \
 	$(DEPTH)/modules/libmar/src/$(LIB_PREFIX)mar.$(LIB_SUFFIX) \
 	$(DEPTH)/modules/libbz2/src/$(LIB_PREFIX)bz2.$(LIB_SUFFIX) \
 	$(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
 USE_STATIC_LIBS = 1
 HAVE_PROGRESSUI = 1
 RCINCLUDE = updater.rc
 CPPSRCS += progressui_win.cpp
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 ws2_32 shell32)
+DEFINES += -DUNICODE -D_UNICODE
 ifndef GNU_CC
 RCFLAGS += -I$(srcdir)
 else
 RCFLAGS += --include-dir $(srcdir)
 DEFINES += -D_WIN32_IE=0x300
 endif
 endif
 
@@ -99,16 +100,22 @@ ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
 
 include $(topsrcdir)/config/rules.mk
 
+DEFINES += -DNS_NO_XPCOM
+
+ifdef _MSC_VER
+WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
+endif
+
 ifneq (,$(filter mac cocoa,$(MOZ_WIDGET_TOOLKIT)))
 libs::
 	$(NSINSTALL) -D $(DIST)/bin/updater.app
 	rsync -a -C --exclude "*.in" $(srcdir)/macbuild/Contents $(DIST)/bin/updater.app 
 	sed -e "s/@APP_NAME@/$(MOZ_APP_DISPLAYNAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
 	  iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/updater.app/Contents/Resources/English.lproj/InfoPlist.strings
 	$(NSINSTALL) -D $(DIST)/bin/updater.app/Contents/MacOS
 	$(NSINSTALL) $(DIST)/bin/updater $(DIST)/bin/updater.app/Contents/MacOS
--- a/toolkit/mozapps/update/src/updater/archivereader.cpp
+++ b/toolkit/mozapps/update/src/updater/archivereader.cpp
@@ -91,16 +91,26 @@ ArchiveReader::ExtractFile(const char *n
 
   int rv = ExtractItemToStream(item, fp);
 
   fclose(fp);
   return rv;
 }
 
 int
+ArchiveReader::ExtractFileToStream(const char *name, FILE *fp)
+{
+  const MarItem *item = mar_find_item(mArchive, name);
+  if (!item)
+    return READ_ERROR;
+
+  return ExtractItemToStream(item, fp);
+}
+
+int
 ArchiveReader::ExtractItemToStream(const MarItem *item, FILE *fp)
 {
   /* decompress the data chunk by chunk */
 
   char inbuf[BUFSIZ], outbuf[BUFSIZ];
   bz_stream strm;
   int offset, inlen, ret = OK;
 
--- a/toolkit/mozapps/update/src/updater/archivereader.h
+++ b/toolkit/mozapps/update/src/updater/archivereader.h
@@ -48,16 +48,17 @@ class ArchiveReader
 public:
   ArchiveReader() : mArchive(NULL) {}
   ~ArchiveReader() { Close(); }
 
   int Open(const char *path);
   void Close();
 
   int ExtractFile(const char *item, const char *destination);
+  int ExtractFileToStream(const char *item, FILE *fp);
 
 private:
   int ExtractItemToStream(const MarItem *item, FILE *fp);
 
   MarFile *mArchive;
 };
 
 #endif  // ArchiveReader_h__
--- a/toolkit/mozapps/update/src/updater/progressui.h
+++ b/toolkit/mozapps/update/src/updater/progressui.h
@@ -34,18 +34,26 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef PROGRESSUI_H__
 #define PROGRESSUI_H__
 
+#if defined(XP_WIN)
+  typedef WCHAR NS_tchar;
+  #define NS_main wmain
+#else
+  typedef char NS_tchar;
+  #define NS_main main
+#endif
+
 // Called to perform any initialization of the widget toolkit
-int InitProgressUI(int *argc, char ***argv);
+int InitProgressUI(int *argc, NS_tchar ***argv);
 
 // Called on the main thread at startup
 int ShowProgressUI();
 
 // May be called from any thread
 void QuitProgressUI();
 
 // May be called from any thread: progress is a number between 0 and 100
--- a/toolkit/mozapps/update/src/updater/progressui_win.cpp
+++ b/toolkit/mozapps/update/src/updater/progressui_win.cpp
@@ -38,16 +38,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include <stdio.h>
 #include <windows.h>
 #include <commctrl.h>
 #include <process.h>
 #include <io.h>
 #include "resource.h"
+#include "progressui.h"
 
 #define TIMER_ID 1
 #define TIMER_INTERVAL 100
 
 #define MAX_INFO_LENGTH 512
 
 #define RESIZE_WINDOW(hwnd, extrax, extray) \
   { \
@@ -67,40 +68,40 @@
                  SWP_NOSIZE | SWP_NOZORDER); \
   }
 
 static float sProgress;  // between 0 and 100
 static BOOL  sQuit = FALSE;
 static HFONT sSystemFont = 0;
 
 static BOOL
-GetStringsFile(char filename[MAX_PATH])
+GetStringsFile(WCHAR filename[MAX_PATH])
 {
-  if (!GetModuleFileName(NULL, filename, MAX_PATH))
+  if (!GetModuleFileNameW(NULL, filename, MAX_PATH))
+    return FALSE;
+ 
+  WCHAR *dot = wcsrchr(filename, '.');
+  if (!dot || wcsicmp(dot + 1, L"exe"))
     return FALSE;
 
-  char *dot = strrchr(filename, '.');
-  if (!dot || stricmp(dot + 1, "exe"))
-    return FALSE;
-
-  strcpy(dot + 1, "ini");
+  wcscpy(dot + 1, L"ini");
   return TRUE;
 }
 
 static void
 UpdateDialog(HWND hDlg)
 {
   int pos = int(sProgress + 0.5f);
   SendDlgItemMessage(hDlg, IDC_PROGRESS, PBM_SETPOS, pos, 0L);
 }
 
 static void
 ResizeDialogToFit(HWND hDlg)
 {
-  char text[MAX_INFO_LENGTH];
+  WCHAR text[MAX_INFO_LENGTH];
   RECT infoSize, textSize;
   HFONT hInfoFont, hOldFont;
 
   HWND hWndInfo = GetDlgItem(hDlg, IDC_INFO);
   HWND hWndPro  = GetDlgItem(hDlg, IDC_PROGRESS);
 
   // Get the text that is displayed - this is what we're going to make fit.
   if (!GetWindowText(hWndInfo, text, sizeof(text)))
@@ -168,33 +169,33 @@ CenterDialog(HWND hDlg)
                HWND_TOP, 
                rcOwner.left + (rc.right / 2), 
                rcOwner.top + (rc.bottom / 2), 
                0, 0,          // ignores size arguments 
                SWP_NOSIZE); 
 }
 
 static void
-SetItemText(HWND hwnd, const char *key, const char *ini)
+SetItemText(HWND hwnd, const WCHAR *key, const WCHAR *ini)
 {
-  char text[MAX_INFO_LENGTH];
-  if (!GetPrivateProfileString("Strings", key, NULL, text, sizeof(text), ini))
+  WCHAR text[MAX_INFO_LENGTH];
+  if (!GetPrivateProfileStringW(L"Strings", key, NULL, text, sizeof(text), ini))
     return;
-  SetWindowText(hwnd, text);
+  SetWindowTextW(hwnd, text);
 }
 
 static void
 InitDialog(HWND hDlg)
 {
-  char filename[MAX_PATH];
+  WCHAR filename[MAX_PATH];
   if (!GetStringsFile(filename))
     return;
 
-  SetItemText(hDlg, "Title", filename);
-  SetItemText(GetDlgItem(hDlg, IDC_INFO), "Info", filename);
+  SetItemText(hDlg, L"Title", filename);
+  SetItemText(GetDlgItem(hDlg, IDC_INFO), L"Info", filename);
 
   // On Win9x, we need to send WM_SETFONT for l10n builds.  Yes, we shouldn't
   // use the system font.  For example, if the text has Japanese characters on
   // Win98-en, then the text may not be displayed correctly.  We should perhaps
   // support loading a font named in updater.ini; however, even then there are
   // cases where it might not work properly.
   if (!sSystemFont) {
     NONCLIENTMETRICS ncm;
@@ -245,37 +246,37 @@ DialogProc(HWND hDlg, UINT message, WPAR
 
   case WM_COMMAND:
     return TRUE;
   }
   return FALSE;
 }
 
 int
-InitProgressUI(int *argc, char ***argv)
+InitProgressUI(int *argc, NS_tchar ***argv)
 {
   return 0;
 }
 
 int
 ShowProgressUI()
 {
   // Only show the Progress UI if the process is taking significant time.
   // Here we measure significant time as taking more than one second.
 
   Sleep(500);
 
   if (sQuit || sProgress > 50.0f)
     return 0;
 
   // If we do not have updater.ini, then we should not bother showing UI.
-  char filename[MAX_PATH];
+  WCHAR filename[MAX_PATH];
   if (!GetStringsFile(filename))
     return -1;
-  if (_access(filename, 04))
+  if (_waccess(filename, 04))
     return -1;
 
   INITCOMMONCONTROLSEX icc = {
     sizeof(INITCOMMONCONTROLSEX),
     ICC_PROGRESS_CLASS
   };
   InitCommonControlsEx(&icc);
 
--- a/toolkit/mozapps/update/src/updater/updater.cpp
+++ b/toolkit/mozapps/update/src/updater/updater.cpp
@@ -42,16 +42,51 @@
  *
  *  contents = 1*( line )
  *  line     = method LWS *( param LWS ) CRLF
  *  method   = "add" | "remove" | "patch"
  *  CRLF     = "\r\n"
  *  LWS      = 1*( " " | "\t" )
  */
 
+#if defined(XP_WIN)
+# include <windows.h>
+# include <direct.h>
+# include <io.h>
+# define F_OK 00
+# define W_OK 02
+# define R_OK 04
+# define access _access
+# define putenv _putenv
+# define snprintf _snprintf
+# define fchmod(a,b)
+# define mkdir(path, perms) _mkdir(path)
+
+# define NS_T(str) L ## str
+# define NS_tsnprintf _snwprintf
+# define NS_tstrrchr wcsrchr
+# define NS_tchdir _wchdir
+# define NS_tremove _wremove
+# define NS_topen _wopen
+# define NS_tfopen _wfopen
+# define NS_tatoi _wtoi64
+#else
+# include <sys/wait.h>
+# include <unistd.h>
+
+# define NS_T(str) str
+# define NS_tsnprintf snprintf
+# define NS_tstrrchr strrchr
+# define NS_tchdir chdir
+# define NS_tremove remove
+# define NS_topen open
+# define NS_tfopen fopen
+# define NS_tatoi atoi
+#endif
+
 #include "bspatch.h"
 #include "progressui.h"
 #include "archivereader.h"
 #include "errors.h"
 #include "bzlib.h"
 
 #include <stdio.h>
 #include <string.h>
@@ -59,34 +94,16 @@
 #include <stdarg.h>
 
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <limits.h>
 #include <errno.h>
 
-#if defined(XP_WIN)
-# include <windows.h>
-# include <direct.h>
-# include <io.h>
-# define F_OK 00
-# define W_OK 02
-# define R_OK 04
-# define access _access
-# define snprintf _snprintf
-# define putenv _putenv
-# define fchmod(a,b)
-# define mkdir(path, perm) _mkdir(path)
-# define chdir(path) _chdir(path)
-#else
-# include <sys/wait.h>
-# include <unistd.h>
-#endif
-
 #if defined(XP_MACOSX)
 // This function is defined in launchchild_osx.mm
 void LaunchChild(int argc, char **argv);
 #endif
 
 #ifndef _O_BINARY
 # define _O_BINARY 0
 #endif
@@ -256,17 +273,17 @@ private:
 };
 
 #else
 #error "Unsupported platform"
 #endif
 
 //-----------------------------------------------------------------------------
 
-static char* gSourcePath;
+static NS_tchar* gSourcePath;
 static ArchiveReader gArchiveReader;
 #ifdef XP_WIN
 static bool gSucceeded = FALSE;
 #endif
 
 static const char kWhitespace[] = " \t";
 static const char kNL[] = "\r\n";
 static const char kQuote[] = "\"";
@@ -276,20 +293,20 @@ static const char kQuote[] = "\"";
 
 static FILE *gLogFP = NULL;
 
 static void LogInit()
 {
   if (gLogFP)
     return;
 
-  char logFile[MAXPATHLEN];
-  snprintf(logFile, MAXPATHLEN, "%s/update.log", gSourcePath);
+  NS_tchar logFile[MAXPATHLEN];
+  NS_tsnprintf(logFile, MAXPATHLEN, NS_T("%s/update.log"), gSourcePath);
 
-  gLogFP = fopen(logFile, "w");
+  gLogFP = NS_tfopen(logFile, NS_T("w"));
 }
 
 static void LogFinish()
 {
   if (!gLogFP)
     return;
 
   fclose(gLogFP);
@@ -354,17 +371,17 @@ mstrtok(const char *delims, char **str)
 
   *str = NULL;
   return ret;
 }
 
 static void ensure_write_permissions(const char *path)
 {
 #ifdef XP_WIN
-  (void)_chmod(path, _S_IREAD | _S_IWRITE);
+  (void) chmod(path, _S_IREAD | _S_IWRITE);
 #else
   struct stat fs;
   if (!stat(path, &fs) && !(fs.st_mode & S_IWUSR)) {
     (void)chmod(path, fs.st_mode | S_IWUSR);
   }
 #endif
 }
 
@@ -736,19 +753,21 @@ private:
 int PatchFile::sPatchIndex = 0;
 
 PatchFile::~PatchFile()
 {
   if (pfd >= 0)
     close(pfd);
 
   // delete the temporary patch file
-  char spath[MAXPATHLEN];
-  snprintf(spath, MAXPATHLEN, "%s/%d.patch", gSourcePath, mPatchIndex);
-  ensure_remove(spath);
+  NS_tchar spath[MAXPATHLEN];
+  NS_tsnprintf(spath, MAXPATHLEN, NS_T("%s/%d.patch"),
+               gSourcePath, mPatchIndex);
+
+  NS_tremove(spath);
 
   free(buf);
 }
 
 int
 PatchFile::LoadSourceFile(int ofd)
 {
   struct stat os;
@@ -813,30 +832,36 @@ PatchFile::Parse(char *line)
 int
 PatchFile::Prepare()
 {
   LOG(("PREPARE PATCH %s\n", mFile));
 
   // extract the patch to a temporary file
   mPatchIndex = sPatchIndex++;
 
-  char spath[MAXPATHLEN];
-  snprintf(spath, MAXPATHLEN, "%s/%d.patch", gSourcePath, mPatchIndex);
+  NS_tchar spath[MAXPATHLEN];
+  NS_tsnprintf(spath, MAXPATHLEN, NS_T("%s/%d.patch"),
+               gSourcePath, mPatchIndex);
+
+  NS_tremove(spath);
 
-  ensure_remove(spath);
+  FILE *fp = NS_tfopen(spath, NS_T("wb"));
+  if (!fp)
+    return WRITE_ERROR;
 
-  int rv = gArchiveReader.ExtractFile(mPatchFile, spath);
+  int rv = gArchiveReader.ExtractFileToStream(mPatchFile, fp);
+  fclose(fp);
   if (rv)
     return rv;
 
   // XXXdarin from here down should be moved into the Execute command.
   //          no need to open all of the patch files and read all of 
   //          the source files before applying any patches.
 
-  pfd = open(spath, O_RDONLY | _O_BINARY);
+  pfd = NS_topen(spath, O_RDONLY | _O_BINARY);
   if (pfd < 0)
     return READ_ERROR;
 
   rv = MBS_ReadHeader(pfd, &header);
   if (rv)
     return rv;
 
   AutoFD ofd = open(mFile, O_RDONLY | _O_BINARY);
@@ -1006,79 +1031,90 @@ PatchIfFile::Finish(int status)
 }
 
 //-----------------------------------------------------------------------------
 
 #ifdef XP_WIN
 #include "nsWindowsRestart.cpp"
 
 static void
-LaunchWinPostProcess(const char *appExe)
+copyASCIItoWCHAR(WCHAR *dest, const char *src)
+{
+  while (*src) {
+    *dest = *src;
+    ++src; ++dest;
+  }
+}
+
+static void
+LaunchWinPostProcess(const WCHAR *appExe)
 {
   // Launch helper.exe to perform post processing (e.g. registry and log file
   // modifications) for the update.
-  char inifile[MAXPATHLEN];
-  strcpy(inifile, appExe);
+  WCHAR inifile[MAXPATHLEN];
+  wcscpy(inifile, appExe);
 
-  char *slash = strrchr(inifile, '\\');
+  WCHAR *slash = wcsrchr(inifile, '\\');
   if (!slash)
     return;
 
-  strcpy(slash + 1, "updater.ini");
+  wcscpy(slash + 1, L"updater.ini");
 
-  char exefile[MAXPATHLEN];
-  char exearg[MAXPATHLEN];
-  if (!GetPrivateProfileString("PostUpdateWin", "ExeRelPath", NULL, exefile,
-      sizeof(exefile), inifile))
+  WCHAR exefile[MAXPATHLEN];
+  WCHAR exearg[MAXPATHLEN];
+
+  if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeRelPath", NULL, exefile,
+                                MAXPATHLEN, inifile))
     return;
 
-  if (!GetPrivateProfileString("PostUpdateWin", "ExeArg", NULL, exearg,
-      sizeof(exearg), inifile))
+  if (!GetPrivateProfileStringW(L"PostUpdateWin", L"ExeArg", NULL, exearg,
+                                MAXPATHLEN, inifile))
     return;
 
-  char exefullpath[MAXPATHLEN];
-  strcpy(exefullpath, appExe);
+  WCHAR exefullpath[MAXPATHLEN];
+  wcscpy(exefullpath, appExe);
 
-  slash = strrchr(exefullpath, '\\');
-  strcpy(slash + 1, exefile);
+  slash = wcsrchr(exefullpath, '\\');
+  wcscpy(slash + 1, exefile);
 
-  char dlogFile[MAXPATHLEN];
-  strcpy(dlogFile, exefullpath);
+  WCHAR dlogFile[MAXPATHLEN];
+  wcscpy(dlogFile, exefullpath);
 
-  slash = strrchr(dlogFile, '\\');
-  strcpy(slash + 1, "uninstall.update");
+  slash = wcsrchr(dlogFile, '\\');
+  wcscpy(slash + 1, L"uninstall.update");
 
-  char slogFile[MAXPATHLEN];
-  snprintf(slogFile, MAXPATHLEN, "%s/update.log", gSourcePath);
+  WCHAR slogFile[MAXPATHLEN];
+  _snwprintf(slogFile, MAXPATHLEN, L"%s/update.log", gSourcePath);
 
   // We want to launch the post update helper app to update the Windows
   // registry even if there is a failure with removing the uninstall.update
   // file or copying the update.log file.
-  ensure_remove(dlogFile);
-  copy_file(slogFile, dlogFile);
+  NS_tremove(dlogFile);
+  CopyFile(slogFile, dlogFile, FALSE);
 
   static int    argc = 2;
-  static char **argv = (char**) malloc(sizeof(char*) * (argc + 1));
-  argv[0] = "argv0ignoredbywinlaunchchild";
-  argv[1] = exearg;
-  argv[2] = "\0";
+  static WCHAR* argv[3] = {
+    L"argv0ignoredbywinlaunchchild",
+    exearg,
+    L"\0"
+  };
 
   WinLaunchChild(exefullpath, argc, argv, 1);
   free(argv);
 }
 #endif
 
 static void
-LaunchCallbackApp(const char *workingDir, int argc, char **argv)
+LaunchCallbackApp(const NS_tchar *workingDir, int argc, NS_tchar **argv)
 {
   putenv("NO_EM_RESTART=");
   putenv("MOZ_LAUNCHED_CHILD=1");
 
   // Run from the specified working directory (see bug 312360).
-  chdir(workingDir);
+  NS_tchdir(workingDir);
 
 #if defined(USE_EXECV)
   execv(argv[0], argv);
 #elif defined(XP_MACOSX)
   LaunchChild(argc, argv);
 #elif defined(XP_WIN)
   WinLaunchChild(argv[0], argc, argv, -1);
 #else
@@ -1129,33 +1165,33 @@ UpdateThreadFunc(void *param)
   else
     LOG(("succeeded\n"));
   WriteStatusFile(rv);
 
   LOG(("calling QuitProgressUI\n"));
   QuitProgressUI();
 }
 
-int main(int argc, char **argv)
+int NS_main(int argc, NS_tchar **argv)
 {
   InitProgressUI(&argc, &argv);
 
   // The updater command line consists of the directory path containing the
   // updater.mar file to process followed by the PID of the calling process.
   // The updater will wait on the parent process to exit if the PID is non-
   // zero.  This is leveraged on platforms such as Windows where it is
   // necessary for the parent process to exit before its executable image may
   // be altered.
 
   if (argc < 3) {
     fprintf(stderr, "Usage: updater <dir-path> <parent-pid> [working-dir callback args...]\n");
     return 1;
   }
 
-  int pid = atoi(argv[2]);
+  int pid = NS_tatoi(argv[2]);
   if (pid) {
 #ifdef XP_WIN
     HANDLE parent = OpenProcess(SYNCHRONIZE, FALSE, (DWORD) pid);
     // May return NULL if the parent process has already gone away.
     // Otherwise, wait for the parent process to exit before starting the
     // update.
     if (parent) {
       DWORD result = WaitForSingleObject(parent, 5000);
@@ -1301,25 +1337,30 @@ ActionList::Finish(int status)
     gSucceeded = TRUE;
 #endif
 
   UpdateProgressUI(100.0f);
 }
 
 int DoUpdate()
 {
-  char manifest[MAXPATHLEN];
-  snprintf(manifest, MAXPATHLEN, "%s/update.manifest", gSourcePath);
+  NS_tchar manifest[MAXPATHLEN];
+  NS_tsnprintf(manifest, MAXPATHLEN, NS_T("%s/update.manifest"), gSourcePath);
 
   // extract the manifest
-  int rv = gArchiveReader.ExtractFile("update.manifest", manifest);
+  FILE *fp = NS_tfopen(manifest, NS_T("wb"));
+  if (!fp)
+    return READ_ERROR;
+
+  int rv = gArchiveReader.ExtractFileToStream("update.manifest", fp);
+  fclose(fp);
   if (rv)
     return rv;
 
-  AutoFD mfd = open(manifest, O_RDONLY | _O_BINARY);
+  AutoFD mfd = NS_topen(manifest, O_RDONLY | _O_BINARY);
   if (mfd < 0)
     return READ_ERROR;
 
   struct stat ms;
   rv = fstat(mfd, &ms);
   if (rv)
     return READ_ERROR;
 
@@ -1389,18 +1430,8 @@ int DoUpdate()
   if (rv)
     return rv;
 
   rv = list.Execute();
 
   list.Finish(rv);
   return rv;
 }
-
-#if defined(XP_WIN) && !defined(DEBUG) && !defined(__GNUC__)
-// We need WinMain in order to not be a console app.  This function is unused
-// if we are a console application.
-int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
-{
-  // Do the real work.
-  return main(__argc, __argv);
-}
-#endif
--- a/toolkit/profile/src/nsToolkitProfileService.cpp
+++ b/toolkit/profile/src/nsToolkitProfileService.cpp
@@ -924,23 +924,23 @@ XRE_GetFileFromPath(const char *aPath, n
     // realpath on OS/2 returns a unix-ized path, so re-native-ize
     for (char* ptr = strchr(fullPath, '/'); ptr; ptr = strchr(ptr, '/'))
         *ptr = '\\';
 
     return NS_NewNativeLocalFile(nsDependentCString(fullPath), PR_TRUE,
                                  aResult);
 
 #elif defined(XP_WIN)
-    char fullPath[MAXPATHLEN];
+    WCHAR fullPath[MAXPATHLEN];
 
-    if (!_fullpath(fullPath, aPath, MAXPATHLEN))
+    if (!_wfullpath(fullPath, NS_ConvertUTF8toUTF16(aPath).get(), MAXPATHLEN))
         return NS_ERROR_FAILURE;
 
-    return NS_NewNativeLocalFile(nsDependentCString(fullPath), PR_TRUE,
-                                 aResult);
+    return NS_NewLocalFile(nsDependentString(fullPath), PR_TRUE,
+                           aResult);
 
 #elif defined(XP_BEOS)
     BPath fullPath;
     if (fullPath.SetTo(aPath, NULL, true))
         return NS_ERROR_FAILURE;
 
     return NS_NewNativeLocalFile(nsDependentCString(fullPath.Leaf()), PR_TRUE,
                                  aResult);
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -286,19 +286,56 @@ SaveWordToEnv(const char *name, const ns
     PR_SetEnv(expr);
   // We intentionally leak |expr| here since it is required by PR_SetEnv.
 }
 
 // Save the path of the given file to the specified environment variable.
 static void
 SaveFileToEnv(const char *name, nsIFile *file)
 {
+#ifdef XP_WIN
+  nsAutoString path;
+  file->GetPath(path);
+  SetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(), path.get());
+#else
   nsCAutoString path;
   file->GetNativePath(path);
   SaveWordToEnv(name, path);
+#endif
+}
+
+// Load the path of a file saved with SaveFileToEnv
+static already_AddRefed<nsILocalFile>
+GetFileFromEnv(const char *name)
+{
+  nsresult rv;
+  nsILocalFile *file = nsnull;
+
+#ifdef XP_WIN
+  WCHAR path[_MAX_PATH];
+  if (!GetEnvironmentVariableW(NS_ConvertASCIItoUTF16(name).get(),
+                               path, _MAX_PATH))
+    return nsnull;
+
+  rv = NS_NewLocalFile(nsDependentString(path), PR_TRUE, &file);
+  if (NS_FAILED(rv))
+    return nsnull;
+
+  return file;
+#else
+  const char *arg = PR_GetEnv(name);
+  if (!arg || !*arg)
+    return nsnull;
+
+  rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE, &file);
+  if (NS_FAILED(rv))
+    return nsnull;
+
+  return file;
+#endif
 }
 
 // Save the path of the given word to the specified environment variable
 // provided the environment variable does not have a value.
 static void
 SaveWordToEnvIfUnset(const char *name, const nsACString & word)
 {
   const char *val = PR_GetEnv(name);
@@ -686,18 +723,18 @@ nsXULAppInfo::LaunchAppHelperWithArgs(in
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = appHelper->AppendNative(NS_LITERAL_CSTRING("uninstall"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = appHelper->AppendNative(NS_LITERAL_CSTRING("helper.exe"));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCAutoString appHelperPath;
-  rv = appHelper->GetNativePath(appHelperPath);
+  nsAutoString appHelperPath;
+  rv = appHelper->GetPath(appHelperPath);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!WinLaunchChild(appHelperPath.get(), aArgc, aArgv, 1))
     return NS_ERROR_FAILURE;
   else
     return NS_OK;
 }
 
@@ -1320,23 +1357,23 @@ XRE_GetBinaryPath(const char* argv0, nsI
   nsresult rv;
   nsCOMPtr<nsILocalFile> lf;
 
   // We need to use platform-specific hackery to find the
   // path of this executable. This is copied, with some modifications, from
   // nsGREDirServiceProvider.cpp
 
 #ifdef XP_WIN
-  char exePath[MAXPATHLEN];
-
-  if (!::GetModuleFileName(0, exePath, MAXPATHLEN))
+  PRUnichar exePath[MAXPATHLEN];
+
+  if (!::GetModuleFileNameW(0, exePath, MAXPATHLEN))
     return NS_ERROR_FAILURE;
 
-  rv = NS_NewNativeLocalFile(nsDependentCString(exePath), PR_TRUE,
-                             getter_AddRefs(lf));
+  rv = NS_NewLocalFile(nsDependentString(exePath), PR_TRUE,
+                       getter_AddRefs(lf));
   if (NS_FAILED(rv))
     return rv;
 
 #elif defined(XP_MACOSX)
   if (gBinaryPath)
     return NS_NewNativeLocalFile(nsDependentCString(gBinaryPath), PR_FALSE,
                                  aResult);
 
@@ -1574,25 +1611,32 @@ static nsresult LaunchChild(nsINativeApp
 #if defined(XP_MACOSX)
   LaunchChildMac(gRestartArgc, gRestartArgv);
 #else
   nsCOMPtr<nsILocalFile> lf;
   nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
   if (NS_FAILED(rv))
     return rv;
 
+#if defined(XP_WIN)
+  nsAutoString exePath;
+  rv = lf->GetPath(exePath);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, needElevation))
+    return NS_ERROR_FAILURE;
+
+#else
   nsCAutoString exePath;
   rv = lf->GetNativePath(exePath);
   if (NS_FAILED(rv))
     return rv;
 
-#if defined(XP_WIN)
-  if (!WinLaunchChild(exePath.get(), gRestartArgc, gRestartArgv, needElevation))
-    return NS_ERROR_FAILURE;
-#elif defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3)
+#if defined(XP_OS2) && (__GNUC__ == 3 && __GNUC_MINOR__ == 3)
   // implementation of _execv() is broken with GCC 3.3.x on OS/2
   if (OS2LaunchChild(exePath.get(), gRestartArgc, gRestartArgv) == -1)
     return NS_ERROR_FAILURE;
 #elif defined(XP_OS2)
   if (_execv(exePath.get(), gRestartArgv) == -1)
     return NS_ERROR_FAILURE;
 #elif defined(XP_UNIX)
   if (execv(exePath.get(), gRestartArgv) == -1)
@@ -1607,18 +1651,19 @@ static nsresult LaunchChild(nsINativeApp
   PRProcess* process = PR_CreateProcess(exePath.get(), gRestartArgv,
                                         nsnull, nsnull);
   if (!process) return NS_ERROR_FAILURE;
 
   PRInt32 exitCode;
   PRStatus failed = PR_WaitProcess(process, &exitCode);
   if (failed || exitCode)
     return NS_ERROR_FAILURE;
-#endif
-#endif
+#endif // XP_OS2 series
+#endif // WP_WIN
+#endif // WP_MACOSX
 
   return NS_ERROR_LAUNCHED_CHILD_PROCESS;
 }
 
 static const char kProfileProperties[] =
   "chrome://mozapps/locale/profile/profileSelection.properties";
 
 static nsresult
@@ -1850,38 +1895,28 @@ SelectProfile(nsIProfileLock* *aResult, 
     return NS_ERROR_FAILURE;
   }
 
   arg = PR_GetEnv("XRE_START_OFFLINE");
   if ((arg && *arg) || ar)
     *aStartOffline = PR_TRUE;
 
 
-  arg = PR_GetEnv("XRE_PROFILE_PATH");
-  if (arg && *arg) {
-    nsCOMPtr<nsILocalFile> lf;
-    rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE,
-                               getter_AddRefs(lf));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    nsCOMPtr<nsILocalFile> localDir;
-    arg = PR_GetEnv("XRE_PROFILE_LOCAL_PATH");
-    if (arg && *arg) {
-      rv = NS_NewNativeLocalFile(nsDependentCString(arg), PR_TRUE,
-                                 getter_AddRefs(localDir));
-      NS_ENSURE_SUCCESS(rv, rv);
-    } else {
+  nsCOMPtr<nsILocalFile> lf = GetFileFromEnv("XRE_PROFILE_PATH");
+  if (lf) {
+    nsCOMPtr<nsILocalFile> localDir =
+      GetFileFromEnv("XRE_PROFILE_LOCAL_PATH");
+    if (!localDir) {
       localDir = lf;
     }
 
     arg = PR_GetEnv("XRE_PROFILE_NAME");
     if (arg && *arg && aProfileName)
       aProfileName->Assign(nsDependentCString(arg));
 
-
     // Clear out flags that we handled (or should have handled!) last startup.
     const char *dummy;
     CheckArg("p", PR_FALSE, &dummy);
     CheckArg("profile", PR_FALSE, &dummy);
     CheckArg("profilemanager");
 
     return NS_LockProfilePath(lf, localDir, nsnull, aResult);
   }
--- a/toolkit/xre/nsAppRunner.h
+++ b/toolkit/xre/nsAppRunner.h
@@ -128,17 +128,17 @@ NS_HIDDEN_(nsresult)
 NS_LockProfilePath(nsILocalFile* aPath, nsILocalFile* aTempPath,
                    nsIProfileUnlocker* *aUnlocker, nsIProfileLock* *aResult);
 
 NS_HIDDEN_(void)
 WriteConsoleLog();
 
 #ifdef XP_WIN
 BOOL
-WinLaunchChild(const char *exePath, int argc, char **argv, int needElevation);
+WinLaunchChild(const PRUnichar *exePath, int argc, char **argv, int needElevation);
 #endif
 
 #define NS_NATIVEAPPSUPPORT_CONTRACTID "@mozilla.org/toolkit/native-app-support;1"
 
 // Like nsXREAppData, but releases all strong refs/allocated memory
 // in the destructor.
 class ScopedAppData : public nsXREAppData
 {
--- a/toolkit/xre/nsNativeAppSupportWin.cpp
+++ b/toolkit/xre/nsNativeAppSupportWin.cpp
@@ -558,39 +558,39 @@ struct MessageWindow {
             else {
                 retval = NS_ERROR_FAILURE;
             }
         }
 
         return retval;
     }
 
-    // SendRequest: Pass string via WM_COPYDATA to message window.
-    NS_IMETHOD SendRequest( const char *cmd ) {
-        // Construct a data buffer <commandline>\0<workingdir>\0
-        int cmdlen = strlen(cmd);
-        char* cmdbuf = (char*) malloc(cmdlen + MAX_PATH + 1);
-        if (!cmdbuf)
-            return NS_ERROR_OUT_OF_MEMORY;
+    // 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);
 
-        strcpy(cmdbuf, cmd);
-        _getcwd(cmdbuf + cmdlen + 1, MAX_PATH);
+        // Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
+        NS_ConvertUTF16toUTF8 utf8buffer(cmd);
+        utf8buffer.Append('\0');
+        AppendUTF16toUTF8(cwd, 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,
-            cmdlen + strlen(cmdbuf + cmdlen + 1) + 2,
-            (void*) cmdbuf
+            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 );
-        free (cmdbuf);
         return NS_OK;
     }
 
     // Window proc.
     static long CALLBACK WindowProc( HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp ) {
         if ( msg == WM_COPYDATA ) {
             if (!nsNativeAppSupportWin::mCanHandleRequests)
                 return FALSE;
@@ -610,19 +610,19 @@ struct MessageWindow {
                     ++wdpath;
 
                 ++wdpath;
 
 #ifdef MOZ_DEBUG_DDE
                 printf( "Working dir: %s\n", wdpath);
 #endif
 
-                NS_NewNativeLocalFile(nsDependentCString(wdpath),
-                                      PR_FALSE,
-                                      getter_AddRefs(workingDir));
+                NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath),
+                                PR_FALSE,
+                                getter_AddRefs(workingDir));
             }
             (void)nsNativeAppSupportWin::HandleCommandLine((char*)cds->lpData, workingDir, nsICommandLine::STATE_REMOTE_AUTO);
 
             // Get current window and return its window handle.
             nsCOMPtr<nsIDOMWindowInternal> win;
             GetMostRecentWindow( 0, getter_AddRefs( win ) );
             return win ? (long)hwndForDOMWindow( win ) : 0;
         } else if ( msg == WM_QUERYENDSESSION ) {
@@ -696,18 +696,17 @@ nsNativeAppSupportWin::Start( PRBool *aR
     Mutex startupLock = Mutex( mMutexName );
 
     NS_ENSURE_TRUE( startupLock.Lock( MOZ_DDE_START_TIMEOUT ), NS_ERROR_FAILURE );
 
     // Search for existing message window.
     MessageWindow msgWindow;
     if ( (HWND)msgWindow ) {
         // We are a client process.  Pass request to message window.
-        LPTSTR cmd = ::GetCommandLine();
-        rv = msgWindow.SendRequest( cmd );
+        rv = msgWindow.SendRequest();
     } else {
         // We will be server.
         rv = msgWindow.Create();
         if ( NS_SUCCEEDED( rv ) ) {
             // Start up DDE server.
             this->StartDDE();
             // Tell caller to spin message loop.
             *aResult = PR_TRUE;
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -358,16 +358,21 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
   if (NS_FAILED(rv))
     return;
   
   nsCAutoString updaterPath;
   rv = updater->GetNativePath(updaterPath);
   if (NS_FAILED(rv))
     return;
 
+  nsAutoString updaterPathW;
+  rv = updater->GetPath(updaterPathW);
+  if (NS_FAILED(rv))
+    return;
+
   // Get the directory to which the update will be applied. On Mac OSX we need
   // to apply the update to the Foo.app directory which is the parent of the
   // parent of the appDir. On other platforms we will just apply to the appDir.
   nsCAutoString applyToDir;
 #if defined(XP_MACOSX)
   {
     nsCOMPtr<nsIFile> parentDir1, parentDir2;
     rv = appDir->GetParent(getter_AddRefs(parentDir1));
@@ -430,17 +435,17 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
   LOG(("spawning updater process [%s]\n", updaterPath.get()));
 
 #if defined(USE_EXECV)
   chdir(applyToDir.get());
   execv(updaterPath.get(), argv);
 #elif defined(XP_WIN)
   _chdir(applyToDir.get());
 
-  if (!WinLaunchChild(updaterPath.get(), appArgc + 4, argv, 1))
+  if (!WinLaunchChild(updaterPathW.get(), appArgc + 4, argv, 1))
     return;
   _exit(0);
 #else
   PRStatus status;
   PRProcessAttr *attr;
   
   attr = PR_NewProcessAttr();
   if (!attr)
--- a/toolkit/xre/nsWindowsRestart.cpp
+++ b/toolkit/xre/nsWindowsRestart.cpp
@@ -39,16 +39,18 @@
 // shared objects.
 
 #ifdef nsWindowsRestart_cpp
 #error "nsWindowsRestart.cpp is not a header file, and must only be included once."
 #else
 #define nsWindowsRestart_cpp
 #endif
 
+#include "nsUTF8Utils.h"
+
 #include <shellapi.h>
 
 #ifndef ERROR_ELEVATION_REQUIRED
 #define ERROR_ELEVATION_REQUIRED 740L
 #endif
 
 BOOL (WINAPI *pCreateProcessWithTokenW)(HANDLE,
                                         DWORD,
@@ -60,37 +62,37 @@ BOOL (WINAPI *pCreateProcessWithTokenW)(
                                         LPSTARTUPINFOW,
                                         LPPROCESS_INFORMATION);
 
 BOOL (WINAPI *pIsUserAnAdmin)(VOID);
 
 /**
  * Get the length that the string will take when it is quoted.
  */
-static int QuotedStrLen(const char *s)
+static int QuotedStrLen(const PRUnichar *s)
 {
   int i = 2; // initial and final quote
   while (*s) {
     if (*s == '"') {
       ++i;
     }
 
-    ++i; ++s;
+    ++i, ++s;
   }
   return i;
 }
 
 /**
  * Copy string "s" to string "d", quoting and escaping all double quotes.
  * The CRT parses this to retrieve the original argc/argv that we meant,
  * see STDARGV.C in the MSVC6 CRT sources.
  *
  * @return the end of the string
  */
-static char* QuoteString(char *d, const char *s)
+static PRUnichar* QuoteString(PRUnichar *d, const PRUnichar *s)
 {
   *d = '"';
   ++d;
 
   while (*s) {
     *d = *s;
     if (*s == '"') {
       ++d;
@@ -104,85 +106,70 @@ static char* QuoteString(char *d, const 
   ++d;
 
   return d;
 }
 
 /**
  * Create a quoted command from a list of arguments. The returned string
  * is allocated with "malloc" and should be "free"d.
+ *
+ * argv is UTF8
  */
-static char*
-MakeCommandLine(int argc, char **argv)
+static PRUnichar*
+MakeCommandLine(int argc, PRUnichar **argv)
 {
   int i;
   int len = 1; // null-termination
 
   for (i = 0; i < argc; ++i)
     len += QuotedStrLen(argv[i]) + 1;
 
-  char *s = (char*) malloc(len);
+  PRUnichar *s = (PRUnichar*) malloc(len * sizeof(PRUnichar));
   if (!s)
     return NULL;
 
-  char *c = s;
+  PRUnichar *c = s;
   for (i = 0; i < argc; ++i) {
     c = QuoteString(c, argv[i]);
     *c = ' ';
     ++c;
   }
 
   *c = '\0';
 
   return s;
 }
 
 /**
- * alloc and convert multibyte char to unicode char
- */
-static PRUnichar *
-AllocConvertAToW(const char *buf)
-{
-  PRUint32 inputLen = strlen(buf) + 1;
-  int n = MultiByteToWideChar(CP_ACP, 0, buf, inputLen, NULL, 0);
-  if (n <= 0)
-    return NULL;
-  PRUnichar *result = (PRUnichar *)malloc(n * sizeof(PRUnichar));
-  if (!result)
-    return NULL;
-  MultiByteToWideChar(CP_ACP, 0, buf, inputLen, result, n);
-  return result;
-}
-
-/**
  * Launch a child process without elevated privilege.
  */
 static BOOL
-LaunchAsNormalUser(const char *exePath, char *cl)
+LaunchAsNormalUser(const PRUnichar *exePath, PRUnichar *cl)
 {
   if (!pCreateProcessWithTokenW) {
     // IsUserAnAdmin is not present on Win9x and not exported by name on Win2k
     *(FARPROC *)&pIsUserAnAdmin =
-        GetProcAddress(GetModuleHandle("shell32.dll"), "IsUserAnAdmin");
+        GetProcAddress(GetModuleHandleA("shell32.dll"), "IsUserAnAdmin");
 
     // CreateProcessWithTokenW is not present on WinXP or earlier
     *(FARPROC *)&pCreateProcessWithTokenW =
-        GetProcAddress(GetModuleHandle("advapi32.dll"),
+        GetProcAddress(GetModuleHandleA("advapi32.dll"),
                        "CreateProcessWithTokenW");
 
     if (!pCreateProcessWithTokenW)
       return FALSE;
   }
 
   // do nothing here if we are not elevated or IsUserAnAdmin is not present.
   if (!pIsUserAnAdmin || pIsUserAnAdmin && !pIsUserAnAdmin())
     return FALSE;
 
   // borrow the shell token to drop the privilege
-  HWND hwndShell = FindWindow("Progman", NULL);
+  HWND hwndShell = FindWindowA("Progman", NULL);
   DWORD dwProcessId;
   GetWindowThreadProcessId(hwndShell, &dwProcessId);
 
   HANDLE hProcessShell = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcessId);
   if (!hProcessShell)
     return FALSE;
 
   HANDLE hTokenShell;
@@ -200,91 +187,147 @@ LaunchAsNormalUser(const char *exePath, 
                         &hNewToken);
   CloseHandle(hTokenShell);
   if (!ok)
     return FALSE;
 
   STARTUPINFOW si = {sizeof(si), 0};
   PROCESS_INFORMATION pi = {0};
 
-  PRUnichar *exePathW = AllocConvertAToW(exePath);
-  PRUnichar *clW = AllocConvertAToW(cl);
-  ok = exePathW && clW;
-  if (ok) {
-    ok = pCreateProcessWithTokenW(hNewToken,
-                                  0,    // profile is already loaded
-                                  exePathW,
-                                  clW,
-                                  0,    // No special process creation flags
-                                  NULL, // inherit my environment
-                                  NULL, // use my current directory
-                                  &si,
-                                  &pi);
-  }
-  free(exePathW);
-  free(clW);
+  // When launching with reduced privileges, environment inheritance
+  // (passing NULL as lpEnvironment) doesn't work correctly. Pass our
+  // current environment block explicitly
+  WCHAR* myenv = GetEnvironmentStringsW();
+
+  ok = pCreateProcessWithTokenW(hNewToken,
+                                0,    // profile is already loaded
+                                exePath,
+                                cl,
+                                CREATE_UNICODE_ENVIRONMENT,
+                                myenv, // inherit my environment
+                                NULL, // use my current directory
+                                &si,
+                                &pi);
+
+  if (myenv)
+    FreeEnvironmentStringsW(myenv);
+
   CloseHandle(hNewToken);
   if (!ok)
     return FALSE;
 
   CloseHandle(pi.hProcess);
   CloseHandle(pi.hThread);
 
   return TRUE;
 }
 
 /**
+ * Convert UTF8 to UTF16 without using the normal XPCOM goop, which we
+ * can't link to updater.exe.
+ */
+static PRUnichar*
+AllocConvertUTF8toUTF16(const char *arg)
+{
+  // UTF16 can't be longer in units than UTF8
+  int len = strlen(arg);
+  PRUnichar *s = new PRUnichar[(len + 1) * sizeof(PRUnichar)];
+  if (!s)
+    return NULL;
+
+  ConvertUTF8toUTF16 convert(s);
+  len = convert.write(arg, len);
+  s[len] = '\0';
+  return s;
+}
+
+static void
+FreeAllocStrings(int argc, PRUnichar **argv)
+{
+  while (argc) {
+    --argc;
+    delete [] argv[argc];
+  }
+
+  delete [] argv;
+}
+
+/**
  * Launch a child process with the specified arguments.
  * @param needElevation 1:need elevation, -1:want to drop priv, 0:don't care
  * @note argv[0] is ignored
+ * @note The form of this function that takes char **argv expects UTF-8
  */
+
+BOOL
+WinLaunchChild(const PRUnichar *exePath, int argc, PRUnichar **argv, int needElevation);
+
 BOOL
-WinLaunchChild(const char *exePath, int argc, char **argv, int needElevation)
+WinLaunchChild(const PRUnichar *exePath, int argc, char **argv, int needElevation)
 {
-  char *cl;
+  PRUnichar** argvConverted = new PRUnichar*[argc];
+  if (!argvConverted)
+    return FALSE;
+
+  for (int i = 0; i < argc; ++i) {
+    argvConverted[i] = AllocConvertUTF8toUTF16(argv[i]);
+    if (!argvConverted[i]) {
+      return FALSE;
+    }
+  }
+
+  BOOL ok = WinLaunchChild(exePath, argc, argvConverted, needElevation);
+  FreeAllocStrings(argc, argvConverted);
+  return ok;
+}
+
+BOOL
+WinLaunchChild(const PRUnichar *exePath, int argc, PRUnichar **argv, int needElevation)
+{
+  PRUnichar *cl;
   BOOL ok;
   if (needElevation > 0) {
     cl = MakeCommandLine(argc - 1, argv + 1);
     if (!cl)
       return FALSE;
-    ok = ShellExecute(NULL, // no special UI window
-                      NULL, // use default verb
-                      exePath,
-                      cl,
-                      NULL, // use my current directory
-                      SW_SHOWDEFAULT) > (HINSTANCE)32;
+    ok = ShellExecuteW(NULL, // no special UI window
+                       NULL, // use default verb
+                       exePath,
+                       cl,
+                       NULL, // use my current directory
+                       SW_SHOWDEFAULT) > (HINSTANCE)32;
     free(cl);
     return ok;
   }
 
   cl = MakeCommandLine(argc, argv);
   if (!cl)
     return FALSE;
 
   if (needElevation < 0) {
     // try to launch as a normal user first
     ok = LaunchAsNormalUser(exePath, cl);
     // if it fails, fallback to normal launching
     if (!ok)
       needElevation = 0;
   }
   if (needElevation == 0) {
-    STARTUPINFO si = {sizeof(si), 0};
+    STARTUPINFOW si = {sizeof(si), 0};
     PROCESS_INFORMATION pi = {0};
 
-    ok = CreateProcess(exePath,
-                       cl,
-                       NULL,  // no special security attributes
-                       NULL,  // no special thread attributes
-                       FALSE, // don't inherit filehandles
-                       0,     // No special process creation flags
-                       NULL,  // inherit my environment
-                       NULL,  // use my current directory
-                       &si,
-                       &pi);
+    ok = CreateProcessW(exePath,
+                        cl,
+                        NULL,  // no special security attributes
+                        NULL,  // no special thread attributes
+                        FALSE, // don't inherit filehandles
+                        0,     // No special process creation flags
+                        NULL,  // inherit my environment
+                        NULL,  // use my current directory
+                        &si,
+                        &pi);
 
     if (ok) {
       CloseHandle(pi.hProcess);
       CloseHandle(pi.hThread);
     }
   }
 
   free(cl);
new file mode 100644
--- /dev/null
+++ b/toolkit/xre/nsWindowsWMain.cpp
@@ -0,0 +1,58 @@
+// This file is a .cpp file meant to be included in nsBrowserApp.cpp and other
+// similar bootstrap code. It converts wide-character windows wmain into UTF-8
+// narrow-character strings.
+
+#ifndef XP_WIN
+#error This file only makes sense on Windows.
+#endif
+
+#include "nsUTF8Utils.h"
+
+#define main NS_internal_main
+
+int main(int argc, char **argv);
+
+static char*
+AllocConvertUTF16toUTF8(const WCHAR *arg)
+{
+  // be generous... UTF16 units can expand up to 3 UTF8 units
+  int len = wcslen(arg);
+  char *s = new char[len * 3 + 1];
+  if (!s)
+    return NULL;
+
+  ConvertUTF16toUTF8 convert(s);
+  len = convert.write(arg, len);
+  s[len] = '\0';
+  return s;
+}
+
+static void
+FreeAllocStrings(int argc, char **argv)
+{
+  while (argc) {
+    --argc;
+    delete [] argv[argc];
+  }
+
+  delete [] argv;
+}
+
+int wmain(int argc, WCHAR **argv)
+{
+  char **argvConverted = new char*[argc + 1];
+  if (!argvConverted)
+    return 127;
+
+  for (int i = 0; i < argc; ++i) {
+    argvConverted[i] = AllocConvertUTF16toUTF8(argv[i]);
+    if (!argvConverted[i]) {
+      return 127;
+    }
+  }
+  argvConverted[argc] = NULL;
+  
+  int result = main(argc, argvConverted);
+  FreeAllocStrings(argc, argvConverted);
+  return result;
+}
--- a/toolkit/xre/nsXULAppAPI.h
+++ b/toolkit/xre/nsXULAppAPI.h
@@ -249,37 +249,36 @@ struct nsXREAppData
  * the aAppDirProvider object passed to XRE_InitEmbedding.
  */
 #define NS_APP_PROFILE_LOCAL_DIR_STARTUP "ProfLDS"
 
 /**
  * Begin an XUL application. Does not return until the user exits the
  * application.
  *
- * @param argc/argv Command-line parameters to pass to the application. These
- *                  are in the "native" character set.
+ * @param argc/argv Command-line parameters to pass to the application. On
+ *                  Windows, these should be in UTF8. On unix-like platforms
+ *                  these are in the "native" character set.
  *
  * @param aAppData  Information about the application to be run.
  *
  * @return         A native result code suitable for returning from main().
  *
  * @note           If the binary is linked against the standalone XPCOM glue,
  *                 XPCOMGlueStartup() should be called before this method.
  *
- * @note           XXXbsmedberg Nobody uses the glue yet, but there is a
- *                 potential problem: on windows, the standalone glue calls
- *                 SetCurrentDirectory, and relative paths on the command line
- *                 won't be correct.
  */
 XRE_API(int,
         XRE_main, (int argc, char* argv[], const nsXREAppData* sAppData))
 
 /**
  * Given a path relative to the current working directory (or an absolute
  * path), return an appropriate nsILocalFile object.
+ *
+ * @note Pass UTF8 strings on Windows... native charset on other platforms.
  */
 XRE_API(nsresult,
         XRE_GetFileFromPath, (const char *aPath, nsILocalFile* *aResult))
 
 /**
  * Get the path of the running application binary and store it in aResult.
  * @param argv0   The value passed as argv[0] of main(). This value is only
  *                used on *nix, and only when other methods of determining
--- a/uriloader/exthandler/win/nsMIMEInfoWin.cpp
+++ b/uriloader/exthandler/win/nsMIMEInfoWin.cpp
@@ -49,16 +49,17 @@
 #include "nsAutoPtr.h"
 #include "nsIMutableArray.h"
 #include "nsTArray.h"
 #include "shlobj.h"
 #include "windows.h"
 #include "nsIWindowsRegKey.h"
 #include "nsIProcess.h"
 #include "nsOSHelperAppService.h"
+#include "nsUnicharUtils.h"
 
 NS_IMPL_ISUPPORTS_INHERITED1(nsMIMEInfoWin, nsMIMEInfoBase, nsIPropertyBag)
 
 nsMIMEInfoWin::~nsMIMEInfoWin()
 {
 }
 
 nsresult
@@ -536,25 +537,25 @@ PRBool nsMIMEInfoWin::GetProgIDVerbComma
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
 // Helper routine used in tracking app lists. Converts path
 // entries to lower case and stores them in the trackList array.
 void nsMIMEInfoWin::ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
-                                nsTArray<nsCAutoString>& trackList,
+                                nsTArray<nsString>& trackList,
                                 const nsAString& appFilesystemCommand)
 {
-  NS_ConvertUTF16toUTF8 lower(appFilesystemCommand);
+  nsAutoString lower(appFilesystemCommand);
   ToLowerCase(lower);
 
   // Don't include firefox.exe in the list
-  char exe[MAX_PATH+1];
-  PRUint32 len = GetModuleFileName(NULL, exe, MAX_PATH);
+  WCHAR exe[MAX_PATH+1];
+  PRUint32 len = GetModuleFileNameW(NULL, exe, MAX_PATH);
   if (len < MAX_PATH && len != 0) {
     PRUint32 index = lower.Find(exe);
     if (index != -1)
       return;
   }
 
   nsCOMPtr<nsILocalHandlerApp> aApp;
   if (!GetLocalHandlerApp(appFilesystemCommand, aApp))
@@ -563,21 +564,21 @@ void nsMIMEInfoWin::ProcessPath(nsCOMPtr
   // Save in our main tracking arrays
   appList->AppendElement(aApp, PR_FALSE);
   trackList.AppendElement(lower);
 }
 
 // Helper routine that handles a compare between a path
 // and an array of paths.
 static PRBool IsPathInList(nsAString& appPath,
-                           nsTArray<nsCAutoString>& trackList)
+                           nsTArray<nsString>& trackList)
 {
   // trackList data is always lowercase, see ProcessPath
   // above.
-  NS_ConvertUTF16toUTF8 tmp(appPath);
+  nsAutoString tmp(appPath);
   ToLowerCase(tmp);
 
   for (PRUint32 i = 0; i < trackList.Length(); i++) {
     if (tmp.Equals(trackList[i]))
       return PR_TRUE;
   }
   return PR_FALSE;
 }
@@ -599,17 +600,17 @@ nsMIMEInfoWin::GetPossibleLocalHandlers(
   *_retval = nsnull;
 
   nsCOMPtr<nsIMutableArray> appList =
     do_CreateInstance("@mozilla.org/array;1");
 
   if (!appList)
     return NS_ERROR_FAILURE;
 
-  nsTArray<nsCAutoString> trackList;
+  nsTArray<nsString> trackList;
 
   nsCAutoString fileExt;
   GetPrimaryExtension(fileExt);
 
   nsCOMPtr<nsIWindowsRegKey> regKey =
     do_CreateInstance("@mozilla.org/windows-registry-key;1");
   if (!regKey) 
     return NS_ERROR_FAILURE; 
--- a/uriloader/exthandler/win/nsMIMEInfoWin.h
+++ b/uriloader/exthandler/win/nsMIMEInfoWin.h
@@ -89,14 +89,14 @@ class nsMIMEInfoWin : public nsMIMEInfoB
     // Lookup a rundll command handler and return
     // a populated command template for use with rundll32.exe.
     PRBool GetDllLaunchInfo(nsIFile * aDll,
                             nsILocalFile * aFile,
                             nsAString& args, PRBool bEdit);
 
     // Helper routine used in tracking app lists
     void ProcessPath(nsCOMPtr<nsIMutableArray>& appList,
-                     nsTArray<nsCAutoString>& trackList,
+                     nsTArray<nsString>& trackList,
                      const nsAString& appFilesystemCommand);
 
 };
 
 #endif
--- a/xpcom/string/public/nsCharTraits.h
+++ b/xpcom/string/public/nsCharTraits.h
@@ -57,20 +57,30 @@
 #include <string.h>
   // for |memcpy|, et al
 
 #ifndef nscore_h___
 #include "nscore.h"
   // for |PRUnichar|
 #endif
 
+// This file may be used (through nsUTF8Utils.h) from non-XPCOM code, in
+// particular the standalone software updater. In that case stub out
+// the macros provided by nsDebug.h which are only usable when linking XPCOM
+
+#ifdef NS_NO_XPCOM
+#define NS_WARNING(msg)
+#define NS_ASSERTION(cond, msg)
+#define NS_ERROR(msg)
+#else
 #ifndef nsDebug_h__
 #include "nsDebug.h"
   // for NS_ASSERTION
 #endif
+#endif
 
 #ifdef HAVE_CPP_BOOL
   typedef bool nsCharTraits_bool;
 #else
   typedef PRBool nsCharTraits_bool;
 #endif
 
 /*
--- a/xpcom/string/public/nsUTF8Utils.h
+++ b/xpcom/string/public/nsUTF8Utils.h
@@ -33,16 +33,22 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsUTF8Utils_h_
 #define nsUTF8Utils_h_
 
+// This file may be used in two ways: if MOZILLA_INTERNAL_API is defined, this
+// file will provide signatures for the Mozilla abstract string types. It will
+// use XPCOM assertion/debugging macros, etc.
+
+#include "nscore.h"
+
 #include "nsCharTraits.h"
 
 class UTF8traits
   {
     public:
       static PRBool isASCII(char c) { return (c & 0x80) == 0x00; }
       static PRBool isInSeq(char c) { return (c & 0xC0) == 0x80; }
       static PRBool is2byte(char c) { return (c & 0xE0) == 0xC0; }
@@ -131,16 +137,18 @@ public:
     if (err)
       *err = PR_FALSE;
     if (overlong)
       *overlong = ucs4 < minUcs4;
     *buffer = p;
     return ucs4;
   }
 
+#ifdef MOZILLA_INTERNAL_API
+
   static PRUint32 NextChar(nsACString::const_iterator& iter,
                            const nsACString::const_iterator& end,
                            PRBool *err = nsnull, PRBool *overlong = nsnull)
   {
     if ( iter == end )
       {
         NS_ERROR("No input to work with");
         if (err)
@@ -194,16 +202,17 @@ public:
       }
 
     if (err)
       *err = PR_FALSE;
     if (overlong)
       *overlong = ucs4 < minUcs4;
     return ucs4;
   }
+#endif // MOZILLA_INTERNAL_API
 
 private:
   static PRBool CalcState(char c, PRUint32& ucs4, PRUint32& minUcs4,
                           PRInt32& state)
   {
     if ( UTF8traits::is2byte(c) )
       {
         ucs4 = (PRUint32(c) << 6) & 0x000007C0L;
@@ -351,16 +360,18 @@ public:
         return 0xFFFD;
       }
 
     if (err)
       *err = PR_TRUE;
     return 0;
   }
 
+#ifdef MOZILLA_INTERNAL_API
+
   static PRUint32 NextChar(nsAString::const_iterator& iter,
                            const nsAString::const_iterator& end,
                            PRBool *err = nsnull)
   {
     if (iter == end)
       {
         if (err)
           *err = PR_TRUE;
@@ -432,28 +443,29 @@ public:
           *err = PR_TRUE;
         return 0xFFFD;
       }
 
     if (err)
       *err = PR_TRUE;
     return 0;
   }
+#endif // MOZILLA_INTERNAL_API
 };
 
 
 /**
  * A character sink (see |copy_string| in nsAlgorithm.h) for converting
  * UTF-8 to UTF-16
  */
 class ConvertUTF8toUTF16
   {
     public:
-      typedef nsACString::char_type value_type;
-      typedef nsAString::char_type  buffer_type;
+      typedef char      value_type;
+      typedef PRUnichar buffer_type;
 
     ConvertUTF8toUTF16( buffer_type* aBuffer )
         : mStart(aBuffer), mBuffer(aBuffer), mErrorEncountered(PR_FALSE) {}
 
     size_t Length() const { return mBuffer - mStart; }
 
     PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N )
       {
@@ -528,17 +540,17 @@ class ConvertUTF8toUTF16
 
 /**
  * A character sink (see |copy_string| in nsAlgorithm.h) for computing
  * the length of the UTF-16 string equivalent to a UTF-8 string.
  */
 class CalculateUTF8Length
   {
     public:
-      typedef nsACString::char_type value_type;
+      typedef char value_type;
 
     CalculateUTF8Length() : mLength(0), mErrorEncountered(PR_FALSE) { }
 
     size_t Length() const { return mLength; }
 
     PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N )
       {
           // ignore any further requests
@@ -597,18 +609,18 @@ class CalculateUTF8Length
 /**
  * A character sink (see |copy_string| in nsAlgorithm.h) for
  * converting UTF-16 to UTF-8. Treats invalid UTF-16 data as 0xFFFD
  * (0xEFBFBD in UTF-8).
  */
 class ConvertUTF16toUTF8
   {
     public:
-      typedef nsAString::char_type  value_type;
-      typedef nsACString::char_type buffer_type;
+      typedef PRUnichar value_type;
+      typedef char      buffer_type;
 
     // The error handling here is more lenient than that in
     // |ConvertUTF8toUTF16|, but it's that way for backwards
     // compatibility.
 
     ConvertUTF16toUTF8( buffer_type* aBuffer )
         : mStart(aBuffer), mBuffer(aBuffer) {}
 
@@ -711,17 +723,17 @@ class ConvertUTF16toUTF8
 /**
  * A character sink (see |copy_string| in nsAlgorithm.h) for computing
  * the number of bytes a UTF-16 would occupy in UTF-8. Treats invalid
  * UTF-16 data as 0xFFFD (0xEFBFBD in UTF-8).
  */
 class CalculateUTF8Size
   {
     public:
-      typedef nsAString::char_type value_type;
+      typedef PRUnichar value_type;
 
     CalculateUTF8Size()
       : mSize(0) { }
 
     size_t Size() const { return mSize; }
 
     PRUint32 NS_ALWAYS_INLINE write( const value_type* start, PRUint32 N )
       {
@@ -775,16 +787,17 @@ class CalculateUTF8Size
 
         return N;
       }
 
     private:
       size_t mSize;
   };
 
+#ifdef MOZILLA_INTERNAL_API
 /**
  * A character sink that performs a |reinterpret_cast| style conversion
  * between character types.
  */
 template <class FromCharT, class ToCharT>
 class LossyConvertEncoding
   {
     public:
@@ -811,10 +824,11 @@ class LossyConvertEncoding
       write_terminator()
         {
           *mDestination = output_type(0);
         }
 
     private:
       output_type* mDestination;
   };
+#endif // MOZILLA_INTERNAL_API
 
 #endif /* !defined(nsUTF8Utils_h_) */
--- a/xulrunner/app/Makefile.in
+++ b/xulrunner/app/Makefile.in
@@ -128,16 +128,22 @@ MOZ_WINCONSOLE = 0
 endif
 endif
 DEFINES += -DMOZ_WINCONSOLE=$(MOZ_WINCONSOLE)
 
 NSDISTMODE = copy
 
 include $(topsrcdir)/config/config.mk
 
+ifdef _MSC_VER
+# Always enter a Windows program through wmain, whether or not we're
+# a console application.
+WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
+endif
+
 ifdef NS_TRACE_MALLOC
 EXTRA_DSO_LIBS += tracemalloc
 endif
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,comctl32 comdlg32 uuid shell32 ole32 oleaut32 version winspool)
 RCINCLUDE = splash.rc
 ifndef GNU_CC
--- a/xulrunner/app/nsXULRunnerApp.cpp
+++ b/xulrunner/app/nsXULRunnerApp.cpp
@@ -52,16 +52,20 @@
 #include "nsCRTGlue.h"
 #include "nsStringAPI.h"
 #include "nsServiceManagerUtils.h"
 #include "plstr.h"
 #include "prprf.h"
 #include "prenv.h"
 #include "nsINIParser.h"
 
+#ifdef XP_WIN
+#include "nsWindowsWMain.cpp"
+#endif
+
 /**
  * Output a string to the user.  This method is really only meant to be used to
  * output last-ditch error messages designed for developers NOT END USERS.
  *
  * @param isError
  *        Pass true to indicate severe errors.
  * @param fmt
  *        printf-style format string followed by arguments.
@@ -440,18 +444,8 @@ int main(int argc, char* argv[])
   AutoAppData appData(appDataLF);
   if (!appData) {
     Output(PR_TRUE, "Error: couldn't parse application.ini.\n");
     return 2;
   }
 
   return XRE_main(argc, argv, appData);
 }
-
-#if defined( XP_WIN ) && defined( WIN32 ) && !defined(__GNUC__)
-// We need WinMain in order to not be a console app.  This function is
-// unused if we are a console application.
-int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
-{
-  // Do the real work.
-  return main( __argc, __argv );
-}
-#endif
--- a/xulrunner/stub/Makefile.in
+++ b/xulrunner/stub/Makefile.in
@@ -39,17 +39,17 @@ DEPTH     = ../..
 topsrcdir = @top_srcdir@
 srcdir    = @srcdir@
 VPATH     = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE    = xulrunner
 
-REQUIRES  = xpcom xulapp
+REQUIRES  = xpcom string xulapp
 
 CPPSRCS   = nsXULStub.cpp
 
 # Statically link the CRT when possible
 USE_STATIC_LIBS = 1
 
 # The value of XULRUNNER_STUB_NAME is generated by configure to allow XULRunner
 # apps to override it using the --with-xulrunner-stub-name=<appname> argument.
@@ -79,13 +79,19 @@ endif
 ifndef MOZ_WINCONSOLE
 ifdef MOZ_DEBUG
 MOZ_WINCONSOLE = 1
 else
 MOZ_WINCONSOLE = 0
 endif
 endif
 
+include $(topsrcdir)/config/config.mk
+
+ifdef _MSC_VER
+WIN32_EXE_LDFLAGS += -ENTRY:wmainCRTStartup
+endif
+
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH),WINNT)
 OS_LIBS += $(call EXPAND_LIBNAME,shell32)
 endif
--- a/xulrunner/stub/nsXULStub.cpp
+++ b/xulrunner/stub/nsXULStub.cpp
@@ -46,17 +46,16 @@
 #include <stdarg.h>
 
 #ifdef XP_WIN
 #include <windows.h>
 #include <io.h>
 #define snprintf _snprintf
 #define vsnprintf _vsnprintf
 #define PATH_SEPARATOR_CHAR '\\'
-#include "nsWindowsRestart.cpp"
 #define R_OK 04
 #elif defined(XP_MACOSX)
 #include <CFBundle.h>
 #define PATH_SEPARATOR_CHAR '/'
 #elif defined (XP_OS2)
 #define INCL_DOS
 #define INCL_DOSMISC
 #define INCL_DOSERRORS
@@ -67,16 +66,20 @@
 #define PATH_SEPARATOR_CHAR '\\'
 #else
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #define PATH_SEPARATOR_CHAR '/'
 #endif
 
+#ifdef XP_WIN
+#include "nsWindowsWMain.cpp"
+#endif
+
 #define VERSION_MAXLEN 128
 
 static void Output(PRBool isError, const char *fmt, ... )
 {
   va_list ap;
   va_start(ap, fmt);
 
 #if defined(XP_WIN) && !MOZ_WINCONSOLE
@@ -346,18 +349,8 @@ main(int argc, char **argv)
   }
 
   NS_LogTerm();
 
   XPCOMGlueShutdown();
 
   return retval;
 }
-
-#if defined( XP_WIN ) && defined( WIN32 ) && !defined(__GNUC__)
-// We need WinMain in order to not be a console app.  This function is
-// unused if we are a console application.
-int WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR args, int )
-{
-  // Do the real work.
-  return main( __argc, __argv );
-}
-#endif