toolkit/xre/nsNativeAppSupportWin.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "nsNativeAppSupportBase.h"
     7 #include "nsNativeAppSupportWin.h"
     8 #include "nsAppRunner.h"
     9 #include "nsXULAppAPI.h"
    10 #include "nsString.h"
    11 #include "nsIBrowserDOMWindow.h"
    12 #include "nsICommandLineRunner.h"
    13 #include "nsCOMPtr.h"
    14 #include "nsXPIDLString.h"
    15 #include "nsIComponentManager.h"
    16 #include "nsIServiceManager.h"
    17 #include "nsIDOMChromeWindow.h"
    18 #include "nsXPCOM.h"
    19 #include "nsISupportsPrimitives.h"
    20 #include "nsIWindowWatcher.h"
    21 #include "nsPIDOMWindow.h"
    22 #include "nsIDocShell.h"
    23 #include "nsIDocShellTreeItem.h"
    24 #include "nsIBaseWindow.h"
    25 #include "nsIWidget.h"
    26 #include "nsIAppShellService.h"
    27 #include "nsIXULWindow.h"
    28 #include "nsIInterfaceRequestor.h"
    29 #include "nsIInterfaceRequestorUtils.h"
    30 #include "nsIPromptService.h"
    31 #include "nsNetCID.h"
    32 #include "nsNetUtil.h"
    33 #include "nsIObserver.h"
    34 #include "nsIObserverService.h"
    35 #include "nsIDOMLocation.h"
    36 #include "nsIWebNavigation.h"
    37 #include "nsIWindowMediator.h"
    38 #include "nsNativeCharsetUtils.h"
    39 #include "nsIAppStartup.h"
    41 #include <windows.h>
    42 #include <shellapi.h>
    43 #include <ddeml.h>
    44 #include <stdlib.h>
    45 #include <stdio.h>
    46 #include <io.h>
    47 #include <direct.h>
    48 #include <fcntl.h>
    50 using namespace mozilla;
    52 static HWND hwndForDOMWindow( nsISupports * );
    54 static
    55 nsresult
    56 GetMostRecentWindow(const char16_t* aType, nsIDOMWindow** aWindow) {
    57     nsresult rv;
    58     nsCOMPtr<nsIWindowMediator> med( do_GetService( NS_WINDOWMEDIATOR_CONTRACTID, &rv ) );
    59     if ( NS_FAILED( rv ) )
    60         return rv;
    62     if ( med )
    63         return med->GetMostRecentWindow( aType, aWindow );
    65     return NS_ERROR_FAILURE;
    66 }
    68 static
    69 void
    70 activateWindow( nsIDOMWindow *win ) {
    71     // Try to get native window handle.
    72     HWND hwnd = hwndForDOMWindow( win );
    73     if ( hwnd ) {
    74         // Restore the window if it is minimized.
    75         if ( ::IsIconic( hwnd ) ) {
    76             ::ShowWindow( hwnd, SW_RESTORE );
    77         }
    78         // Use the OS call, if possible.
    79         ::SetForegroundWindow( hwnd );
    80     } else {
    81         // Use internal method.
    82         win->Focus();
    83     }
    84 }
    87 #ifdef DEBUG_law
    88 #undef MOZ_DEBUG_DDE
    89 #define MOZ_DEBUG_DDE 1
    90 #endif
    92 // Simple Win32 mutex wrapper.
    93 struct Mutex {
    94     Mutex( const char16_t *name )
    95         : mName( name ),
    96           mHandle( 0 ),
    97           mState( -1 ) {
    98         mHandle = CreateMutexW( 0, FALSE, mName.get() );
    99 #if MOZ_DEBUG_DDE
   100         printf( "CreateMutex error = 0x%08X\n", (int)GetLastError() );
   101 #endif
   102     }
   103     ~Mutex() {
   104         if ( mHandle ) {
   105             // Make sure we release it if we own it.
   106             Unlock();
   108             BOOL rc = CloseHandle( mHandle );
   109 #if MOZ_DEBUG_DDE
   110             if ( !rc ) {
   111                 printf( "CloseHandle error = 0x%08X\n", (int)GetLastError() );
   112             }
   113 #endif
   114         }
   115     }
   116     BOOL Lock( DWORD timeout ) {
   117         if ( mHandle ) {
   118 #if MOZ_DEBUG_DDE
   119             printf( "Waiting (%d msec) for DDE mutex...\n", (int)timeout );
   120 #endif
   121             mState = WaitForSingleObject( mHandle, timeout );
   122 #if MOZ_DEBUG_DDE
   123             printf( "...wait complete, result = 0x%08X, GetLastError=0x%08X\n", (int)mState, (int)::GetLastError() );
   124 #endif
   125             return mState == WAIT_OBJECT_0 || mState == WAIT_ABANDONED;
   126         } else {
   127             return FALSE;
   128         }
   129     }
   130     void Unlock() {
   131         if ( mHandle && mState == WAIT_OBJECT_0 ) {
   132 #if MOZ_DEBUG_DDE
   133             printf( "Releasing DDE mutex\n" );
   134 #endif
   135             ReleaseMutex( mHandle );
   136             mState = -1;
   137         }
   138     }
   139 private:
   140     nsString  mName;
   141     HANDLE    mHandle;
   142     DWORD     mState;
   143 };
   145 /* DDE Notes
   146  *
   147  * This section describes the Win32 DDE service implementation for
   148  * Mozilla.  DDE is used on Win32 platforms to communicate between
   149  * separate instances of mozilla.exe (or other Mozilla-based
   150  * executables), or, between the Win32 desktop shell and Mozilla.
   151  *
   152  * The first instance of Mozilla will become the "server" and
   153  * subsequent executables (and the shell) will use DDE to send
   154  * requests to that process.  The requests are DDE "execute" requests
   155  * that pass the command line arguments.
   156  *
   157  * Mozilla registers the DDE application "Mozilla" and currently
   158  * supports only the "WWW_OpenURL" topic.  This should be reasonably
   159  * compatible with applications that interfaced with Netscape
   160  * Communicator (and its predecessors?).  Note that even that topic
   161  * may not be supported in a compatible fashion as the command-line
   162  * options for Mozilla are different than for Communiator.
   163  *
   164  * It is imperative that at most one instance of Mozilla execute in
   165  * "server mode" at any one time.  The "native app support" in Mozilla
   166  * on Win32 ensures that only the server process performs XPCOM
   167  * initialization (that is not required for subsequent client processes
   168  * to communicate with the server process).
   169  *
   170  * To guarantee that only one server starts up, a Win32 "mutex" is used
   171  * to ensure only one process executes the server-detection code.  That
   172  * code consists of initializing DDE and doing a DdeConnect to Mozilla's
   173  * application/topic.  If that connection succeeds, then a server process
   174  * must be running already.
   175  *
   176  * Otherwise, no server has started.  In that case, the current process
   177  * calls DdeNameService to register that application/topic.  Only at that
   178  * point does the mutex get released.
   179  *
   180  * There are a couple of subtleties that one should be aware of:
   181  *
   182  * 1. It is imperative that DdeInitialize be called only after the mutex
   183  *    lock has been obtained.  The reason is that at shutdown, DDE
   184  *    notifications go out to all initialized DDE processes.  Thus, if
   185  *    the mutex is owned by a terminating intance of Mozilla, then
   186  *    calling DdeInitialize and then WaitForSingleObject will cause the
   187  *    DdeUninitialize from the terminating process to "hang" until the
   188  *    process waiting for the mutex times out (and can then service the
   189  *    notification that the DDE server is terminating).  So, don't mess
   190  *    with the sequence of things in the startup/shutdown logic.
   191  *
   192  * 2. All mutex requests are made with a reasonably long timeout value and
   193  *    are designed to "fail safe" (i.e., a timeout is treated as failure).
   194  *
   195  * 3. An attempt has been made to minimize the degree to which the main
   196  *    Mozilla application logic needs to be aware of the DDE mechanisms
   197  *    implemented herein.  As a result, this module surfaces a very
   198  *    large-grained interface, consisting of simple start/stop methods.
   199  *    As a consequence, details of certain scenarios can be "lost."
   200  *    Particularly, incoming DDE requests can arrive after this module
   201  *    initiates the DDE server, but before Mozilla is initialized to the
   202  *    point where those requests can be serviced (e.g., open a browser
   203  *    window to a particular URL).  Since the client process sends the
   204  *    request early on, it may not be prepared to respond to that error.
   205  *    Thus, such situations may fail silently.  The design goal is that
   206  *    they fail harmlessly.  Refinements on this point will be made as
   207  *    details emerge (and time permits).
   208  */
   210 /* Update 2001 March
   211  *
   212  * A significant DDE bug in Windows is causing Mozilla to get wedged at
   213  * startup.  This is detailed in Bugzill bug 53952
   214  * (http://bugzilla.mozilla.org/show_bug.cgi?id=53952).
   215  *
   216  * To resolve this, we are using a new strategy:
   217  *   o Use a "message window" to detect that Mozilla is already running and
   218  *     to pass requests from a second instance back to the first;
   219  *   o Run only as a "DDE server" (not as DDE client); this avoids the
   220  *     problematic call to DDEConnect().
   221  *
   222  * We still use the mutex semaphore to protect the code that detects
   223  * whether Mozilla is already running.
   224  */
   226 /* Update 2007 January
   227  *
   228  * A change in behavior was implemented in July 2004 which made the
   229  * application on launch to add and on quit to remove the ddexec registry key.
   230  * See bug 246078.
   231  * Windows Vista has changed the methods used to set an application as default
   232  * and the new methods are incompatible with removing the ddeexec registry key.
   233  * See bug 353089.
   234  *
   235  * OS DDE Sequence:
   236  * 1. OS checks if the dde name is registered.
   237  * 2. If it is registered the OS sends a DDE request with the WWW_OpenURL topic
   238  *    and the params as specified in the default value of the ddeexec registry
   239  *    key for the verb (e.g. open).
   240  * 3. If it isn't registered the OS launches the executable defined in the
   241  *    verb's (e.g. open) command registry key.
   242  * 4. If the ifexec registry key is not present the OS sends a DDE request with
   243  *    the WWW_OpenURL topic and the params as specified in the default value of
   244  *    the ddeexec registry key for the verb (e.g. open).
   245  * 5. If the ifexec registry key is present the OS sends a DDE request with the
   246  *    WWW_OpenURL topic and the params as specified in the ifexec registry key
   247  *    for the verb (e.g. open).
   248  *
   249  * Application DDE Sequence:
   250  * 1. If the application is running a DDE request is received with the
   251  *    WWW_OpenURL topic and the params as specified in the default value of the
   252  *    ddeexec registry key (e.g. "%1",,0,0,,,, where '%1' is the url to open)
   253  *    for the verb (e.g. open).
   254  * 2. If the application is not running it is launched with the -requestPending
   255  *    and the -url argument.
   256  * 2.1  If the application does not need to restart and the -requestPending
   257  *      argument is present the accompanying url will not be used. Instead the
   258  *      application will wait for the DDE message to open the url.
   259  * 2.2  If the application needs to restart the -requestPending argument is
   260  *      removed from the arguments used to restart the application and the url
   261  *      will be handled normally.
   262  *
   263  * Note: Due to a bug in IE the ifexec key should not be used (see bug 355650).
   264  */
   266 class nsNativeAppSupportWin : public nsNativeAppSupportBase,
   267                               public nsIObserver
   268 {
   269 public:
   270     NS_DECL_NSIOBSERVER
   271     NS_DECL_ISUPPORTS_INHERITED
   273     // Overrides of base implementation.
   274     NS_IMETHOD Start( bool *aResult );
   275     NS_IMETHOD Stop( bool *aResult );
   276     NS_IMETHOD Quit();
   277     NS_IMETHOD Enable();
   278     // The "old" Start method (renamed).
   279     NS_IMETHOD StartDDE();
   280     // Utility function to handle a Win32-specific command line
   281     // option: "-console", which dynamically creates a Windows
   282     // console.
   283     void CheckConsole();
   285 private:
   286     static void HandleCommandLine(const char* aCmdLineString, nsIFile* aWorkingDir, uint32_t aState);
   287     static HDDEDATA CALLBACK HandleDDENotification( UINT     uType,
   288                                                     UINT     uFmt,
   289                                                     HCONV    hconv,
   290                                                     HSZ      hsz1,
   291                                                     HSZ      hsz2,
   292                                                     HDDEDATA hdata,
   293                                                     ULONG_PTR dwData1,
   294                                                     ULONG_PTR dwData2 );
   295     static void ParseDDEArg( HSZ args, int index, nsString& string);
   296     static void ParseDDEArg( const WCHAR* args, int index, nsString& aString);
   297     static HDDEDATA CreateDDEData( DWORD value );
   298     static HDDEDATA CreateDDEData( LPBYTE value, DWORD len );
   299     static bool     InitTopicStrings();
   300     static int      FindTopic( HSZ topic );
   301     static void ActivateLastWindow();
   302     static nsresult OpenWindow( const char *urlstr, const char *args );
   303     static nsresult OpenBrowserWindow();
   304     static void     SetupSysTrayIcon();
   305     static void     RemoveSysTrayIcon();
   307     static int   mConversations;
   308     enum {
   309         topicOpenURL,
   310         topicActivate,
   311         topicCancelProgress,
   312         topicVersion,
   313         topicRegisterViewer,
   314         topicUnRegisterViewer,
   315         topicGetWindowInfo,
   316         // Note: Insert new values above this line!!!!!
   317         topicCount // Count of the number of real topics
   318     };
   319     static HSZ   mApplication, mTopics[ topicCount ];
   320     static DWORD mInstance;
   321     static bool mCanHandleRequests;
   322     static char16_t mMutexName[];
   323     friend struct MessageWindow;
   324 }; // nsNativeAppSupportWin
   326 NS_INTERFACE_MAP_BEGIN(nsNativeAppSupportWin)
   327     NS_INTERFACE_MAP_ENTRY(nsIObserver)
   328 NS_INTERFACE_MAP_END_INHERITING(nsNativeAppSupportBase)
   330 NS_IMPL_ADDREF_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
   331 NS_IMPL_RELEASE_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
   333 void
   334 nsNativeAppSupportWin::CheckConsole() {
   335     for ( int i = 1; i < gArgc; i++ ) {
   336         if ( strcmp( "-console", gArgv[i] ) == 0
   337              ||
   338              strcmp( "/console", gArgv[i] ) == 0 ) {
   339             // Users wants to make sure we have a console.
   340             // Try to allocate one.
   341             BOOL rc = ::AllocConsole();
   342             if ( rc ) {
   343                 // Console allocated.  Fix it up so that output works in
   344                 // all cases.  See http://support.microsoft.com/support/kb/articles/q105/3/05.asp.
   346                 // stdout
   347                 int hCrt = ::_open_osfhandle( (intptr_t)GetStdHandle( STD_OUTPUT_HANDLE ),
   348                                             _O_TEXT );
   349                 if ( hCrt != -1 ) {
   350                     FILE *hf = ::_fdopen( hCrt, "w" );
   351                     if ( hf ) {
   352                         *stdout = *hf;
   353 #ifdef DEBUG
   354                         ::fprintf( stdout, "stdout directed to dynamic console\n" );
   355 #endif
   356                     }
   357                 }
   359                 // stderr
   360                 hCrt = ::_open_osfhandle( (intptr_t)::GetStdHandle( STD_ERROR_HANDLE ),
   361                                           _O_TEXT );
   362                 if ( hCrt != -1 ) {
   363                     FILE *hf = ::_fdopen( hCrt, "w" );
   364                     if ( hf ) {
   365                         *stderr = *hf;
   366 #ifdef DEBUG
   367                         ::fprintf( stderr, "stderr directed to dynamic console\n" );
   368 #endif
   369                     }
   370                 }
   372                 // stdin?
   373                 /* Don't bother for now.
   374                 hCrt = ::_open_osfhandle( (long)::GetStdHandle( STD_INPUT_HANDLE ),
   375                                           _O_TEXT );
   376                 if ( hCrt != -1 ) {
   377                     FILE *hf = ::_fdopen( hCrt, "r" );
   378                     if ( hf ) {
   379                         *stdin = *hf;
   380                     }
   381                 }
   382                 */
   383             } else {
   384                 // Failed.  Probably because there already is one.
   385                 // There's little we can do, in any case.
   386             }
   387             // Remove the console argument from the command line.
   388             do {
   389                 gArgv[i] = gArgv[i + 1];
   390                 ++i;
   391             } while (gArgv[i]);
   393             --gArgc;
   395         } else if ( strcmp( "-attach-console", gArgv[i] ) == 0
   396                     ||
   397                     strcmp( "/attach-console", gArgv[i] ) == 0 ) {
   398             // Try to attach console to the parent process.
   399             // It will succeed when the parent process is a command line,
   400             // so that stdio will be displayed in it.
   401             if (AttachConsole(ATTACH_PARENT_PROCESS)) {
   402                 // Change std handles to refer to new console handles.
   403                 // Before doing so, ensure that stdout/stderr haven't been
   404                 // redirected to a valid file
   405                 if (_fileno(stdout) == -1 ||
   406                     _get_osfhandle(fileno(stdout)) == -1)
   407                     freopen("CONOUT$", "w", stdout);
   408                 // Merge stderr into CONOUT$ since there isn't any `CONERR$`.
   409                 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
   410                 if (_fileno(stderr) == -1 ||
   411                     _get_osfhandle(fileno(stderr)) == -1)
   412                     freopen("CONOUT$", "w", stderr);
   413                 if (_fileno(stdin) == -1 || _get_osfhandle(fileno(stdin)) == -1)
   414                     freopen("CONIN$", "r", stdin);
   415             }
   416         }
   417     }
   419     return;
   420 }
   423 // Create and return an instance of class nsNativeAppSupportWin.
   424 nsresult
   425 NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) {
   426     nsNativeAppSupportWin *pNative = new nsNativeAppSupportWin;
   427     if (!pNative) return NS_ERROR_OUT_OF_MEMORY;
   429     // Check for dynamic console creation request.
   430     pNative->CheckConsole();
   432     *aResult = pNative;
   433     NS_ADDREF( *aResult );
   435     return NS_OK;
   436 }
   438 // Constants
   439 #define MOZ_DDE_APPLICATION    "Mozilla"
   440 #define MOZ_MUTEX_NAMESPACE    L"Local\\"
   441 #define MOZ_STARTUP_MUTEX_NAME L"StartupMutex"
   442 #define MOZ_DDE_START_TIMEOUT 30000
   443 #define MOZ_DDE_STOP_TIMEOUT  15000
   444 #define MOZ_DDE_EXEC_TIMEOUT  15000
   446 // The array entries must match the enum ordering!
   447 const char * const topicNames[] = { "WWW_OpenURL",
   448                                     "WWW_Activate",
   449                                     "WWW_CancelProgress",
   450                                     "WWW_Version",
   451                                     "WWW_RegisterViewer",
   452                                     "WWW_UnRegisterViewer",
   453                                     "WWW_GetWindowInfo" };
   455 // Static member definitions.
   456 int   nsNativeAppSupportWin::mConversations = 0;
   457 HSZ   nsNativeAppSupportWin::mApplication   = 0;
   458 HSZ   nsNativeAppSupportWin::mTopics[nsNativeAppSupportWin::topicCount] = { 0 };
   459 DWORD nsNativeAppSupportWin::mInstance      = 0;
   460 bool nsNativeAppSupportWin::mCanHandleRequests   = false;
   462 char16_t nsNativeAppSupportWin::mMutexName[ 128 ] = { 0 };
   465 // Message window encapsulation.
   466 struct MessageWindow {
   467     // ctor/dtor are simplistic
   468     MessageWindow() {
   469         // Try to find window.
   470         mHandle = ::FindWindowW( className(), 0 );
   471     }
   473     // Act like an HWND.
   474     operator HWND() {
   475         return mHandle;
   476     }
   478     // Class name: appName + "MessageWindow"
   479     static const wchar_t *className() {
   480         static wchar_t classNameBuffer[128];
   481         static wchar_t *mClassName = 0;
   482         if ( !mClassName ) {
   483             ::_snwprintf(classNameBuffer,
   484                          128,   // size of classNameBuffer in PRUnichars
   485                          L"%s%s",
   486                          NS_ConvertUTF8toUTF16(gAppData->name).get(),
   487                          L"MessageWindow" );
   488             mClassName = classNameBuffer;
   489         }
   490         return mClassName;
   491     }
   493     // Create: Register class and create window.
   494     NS_IMETHOD Create() {
   495         WNDCLASSW classStruct = { 0,                          // style
   496                                  &MessageWindow::WindowProc, // lpfnWndProc
   497                                  0,                          // cbClsExtra
   498                                  0,                          // cbWndExtra
   499                                  0,                          // hInstance
   500                                  0,                          // hIcon
   501                                  0,                          // hCursor
   502                                  0,                          // hbrBackground
   503                                  0,                          // lpszMenuName
   504                                  className() };              // lpszClassName
   506         // Register the window class.
   507         NS_ENSURE_TRUE( ::RegisterClassW( &classStruct ), NS_ERROR_FAILURE );
   509         // Create the window.
   510         NS_ENSURE_TRUE( ( mHandle = ::CreateWindowW(className(),
   511                                                     0,          // title
   512                                                     WS_CAPTION, // style
   513                                                     0,0,0,0,    // x, y, cx, cy
   514                                                     0,          // parent
   515                                                     0,          // menu
   516                                                     0,          // instance
   517                                                     0 ) ),      // create struct
   518                         NS_ERROR_FAILURE );
   520 #if MOZ_DEBUG_DDE
   521         printf( "Message window = 0x%08X\n", (int)mHandle );
   522 #endif
   524         return NS_OK;
   525     }
   527     // Destory:  Get rid of window and reset mHandle.
   528     NS_IMETHOD Destroy() {
   529         nsresult retval = NS_OK;
   531         if ( mHandle ) {
   532             // DestroyWindow can only destroy windows created from
   533             //  the same thread.
   534             BOOL desRes = DestroyWindow( mHandle );
   535             if ( FALSE != desRes ) {
   536                 mHandle = nullptr;
   537             }
   538             else {
   539                 retval = NS_ERROR_FAILURE;
   540             }
   541         }
   543         return retval;
   544     }
   546     // SendRequest: Pass the command line via WM_COPYDATA to message window.
   547     NS_IMETHOD SendRequest() {
   548         WCHAR *cmd = ::GetCommandLineW();
   549         WCHAR cwd[MAX_PATH];
   550         _wgetcwd(cwd, MAX_PATH);
   552         // Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
   553         NS_ConvertUTF16toUTF8 utf8buffer(cmd);
   554         utf8buffer.Append('\0');
   555         AppendUTF16toUTF8(cwd, utf8buffer);
   556         utf8buffer.Append('\0');
   558         // We used to set dwData to zero, when we didn't send the working dir.
   559         // Now we're using it as a version number.
   560         COPYDATASTRUCT cds = {
   561             1,
   562             utf8buffer.Length(),
   563             (void*) utf8buffer.get()
   564         };
   565         // Bring the already running Mozilla process to the foreground.
   566         // nsWindow will restore the window (if minimized) and raise it.
   567         ::SetForegroundWindow( mHandle );
   568         ::SendMessage( mHandle, WM_COPYDATA, 0, (LPARAM)&cds );
   569         return NS_OK;
   570     }
   572     // Window proc.
   573     static LRESULT CALLBACK WindowProc( HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp ) {
   574         if ( msg == WM_COPYDATA ) {
   575             if (!nsNativeAppSupportWin::mCanHandleRequests)
   576                 return FALSE;
   578             // This is an incoming request.
   579             COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lp;
   580 #if MOZ_DEBUG_DDE
   581             printf( "Incoming request: %s\n", (const char*)cds->lpData );
   582 #endif
   583             nsCOMPtr<nsIFile> workingDir;
   585             if (1 >= cds->dwData) {
   586                 char* wdpath = (char*) cds->lpData;
   587                 // skip the command line, and get the working dir of the
   588                 // other process, which is after the first null char
   589                 while (*wdpath)
   590                     ++wdpath;
   592                 ++wdpath;
   594 #ifdef MOZ_DEBUG_DDE
   595                 printf( "Working dir: %s\n", wdpath);
   596 #endif
   598                 NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath),
   599                                 false,
   600                                 getter_AddRefs(workingDir));
   601             }
   602             (void)nsNativeAppSupportWin::HandleCommandLine((char*)cds->lpData, workingDir, nsICommandLine::STATE_REMOTE_AUTO);
   604             // Get current window and return its window handle.
   605             nsCOMPtr<nsIDOMWindow> win;
   606             GetMostRecentWindow( 0, getter_AddRefs( win ) );
   607             return win ? (LRESULT)hwndForDOMWindow( win ) : 0;
   608         }
   609         return DefWindowProc( msgWindow, msg, wp, lp );
   610     }
   612 private:
   613     HWND mHandle;
   614 }; // struct MessageWindow
   616 /* Start: Tries to find the "message window" to determine if it
   617  *        exists.  If so, then Mozilla is already running.  In that
   618  *        case, we use the handle to the "message" window and send
   619  *        a request corresponding to this process's command line
   620  *        options.
   621  *
   622  *        If not, then this is the first instance of Mozilla.  In
   623  *        that case, we create and set up the message window.
   624  *
   625  *        The checking for existence of the message window must
   626  *        be protected by use of a mutex semaphore.
   627  */
   628 NS_IMETHODIMP
   629 nsNativeAppSupportWin::Start( bool *aResult ) {
   630     NS_ENSURE_ARG( aResult );
   631     NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
   632     NS_ENSURE_STATE( gAppData );
   634     if (getenv("MOZ_NO_REMOTE"))
   635     {
   636         *aResult = true;
   637         return NS_OK;
   638     }
   640     nsresult rv = NS_ERROR_FAILURE;
   641     *aResult = false;
   643     // Grab mutex first.
   645     // Build mutex name from app name.
   646     ::_snwprintf(reinterpret_cast<wchar_t*>(mMutexName),
   647                  sizeof mMutexName / sizeof(char16_t), L"%s%s%s",
   648                  MOZ_MUTEX_NAMESPACE,
   649                  NS_ConvertUTF8toUTF16(gAppData->name).get(),
   650                  MOZ_STARTUP_MUTEX_NAME );
   651     Mutex startupLock = Mutex( mMutexName );
   653     NS_ENSURE_TRUE( startupLock.Lock( MOZ_DDE_START_TIMEOUT ), NS_ERROR_FAILURE );
   655     // Search for existing message window.
   656     MessageWindow msgWindow;
   657     if ( (HWND)msgWindow ) {
   658         // We are a client process.  Pass request to message window.
   659         rv = msgWindow.SendRequest();
   660     } else {
   661         // We will be server.
   662         rv = msgWindow.Create();
   663         if ( NS_SUCCEEDED( rv ) ) {
   664             // Start up DDE server.
   665             this->StartDDE();
   666             // Tell caller to spin message loop.
   667             *aResult = true;
   668         }
   669     }
   671     startupLock.Unlock();
   673     return rv;
   674 }
   676 bool
   677 nsNativeAppSupportWin::InitTopicStrings() {
   678     for ( int i = 0; i < topicCount; i++ ) {
   679         if ( !( mTopics[ i ] = DdeCreateStringHandleA( mInstance, const_cast<char *>(topicNames[ i ]), CP_WINANSI ) ) ) {
   680             return false;
   681         }
   682     }
   683     return true;
   684 }
   686 int
   687 nsNativeAppSupportWin::FindTopic( HSZ topic ) {
   688     for ( int i = 0; i < topicCount; i++ ) {
   689         if ( DdeCmpStringHandles( topic, mTopics[i] ) == 0 ) {
   690             return i;
   691         }
   692     }
   693     return -1;
   694 }
   697 // Start DDE server.
   698 //
   699 // This used to be the Start() method when we were using DDE as the
   700 // primary IPC mechanism between secondary Mozilla processes and the
   701 // initial "server" process.
   702 //
   703 // Now, it simply initializes the DDE server.  The caller must check
   704 // that this process is to be the server, and, must acquire the DDE
   705 // startup mutex semaphore prior to calling this routine.  See ::Start(),
   706 // above.
   707 NS_IMETHODIMP
   708 nsNativeAppSupportWin::StartDDE() {
   709     NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
   711     // Initialize DDE.
   712     NS_ENSURE_TRUE( DMLERR_NO_ERROR == DdeInitialize( &mInstance,
   713                                                       nsNativeAppSupportWin::HandleDDENotification,
   714                                                       APPCLASS_STANDARD,
   715                                                       0 ),
   716                     NS_ERROR_FAILURE );
   718     // Allocate DDE strings.
   719     NS_ENSURE_TRUE( ( mApplication = DdeCreateStringHandleA( mInstance, (char*) gAppData->name, CP_WINANSI ) ) && InitTopicStrings(),
   720                     NS_ERROR_FAILURE );
   722     // Next step is to register a DDE service.
   723     NS_ENSURE_TRUE( DdeNameService( mInstance, mApplication, 0, DNS_REGISTER ), NS_ERROR_FAILURE );
   725 #if MOZ_DEBUG_DDE
   726     printf( "DDE server started\n" );
   727 #endif
   729     return NS_OK;
   730 }
   732 // If no DDE conversations are pending, terminate DDE.
   733 NS_IMETHODIMP
   734 nsNativeAppSupportWin::Stop( bool *aResult ) {
   735     NS_ENSURE_ARG( aResult );
   736     NS_ENSURE_TRUE( mInstance, NS_ERROR_NOT_INITIALIZED );
   738     nsresult rv = NS_OK;
   739     *aResult = true;
   741     Mutex ddeLock( mMutexName );
   743     if ( ddeLock.Lock( MOZ_DDE_STOP_TIMEOUT ) ) {
   744         if ( mConversations == 0 ) {
   745             this->Quit();
   746         } else {
   747             *aResult = false;
   748         }
   750         ddeLock.Unlock();
   751     }
   752     else {
   753         // No DDE application name specified, but that's OK.  Just
   754         // forge ahead.
   755         *aResult = true;
   756     }
   758     return rv;
   759 }
   761 NS_IMETHODIMP
   762 nsNativeAppSupportWin::Observe(nsISupports* aSubject, const char* aTopic,
   763                                const char16_t* aData)
   764 {
   765     if (strcmp(aTopic, "quit-application") == 0) {
   766         Quit();
   767     } else {
   768         NS_ERROR("Unexpected observer topic.");
   769     }
   771     return NS_OK;
   772 }
   774 // Terminate DDE regardless.
   775 NS_IMETHODIMP
   776 nsNativeAppSupportWin::Quit() {
   777     // If another process wants to look for the message window, they need
   778     // to wait to hold the lock, in which case they will not find the
   779     // window as we will destroy ours under our lock.
   780     // When the mutex goes off the stack, it is unlocked via destructor.
   781     Mutex mutexLock(mMutexName);
   782     NS_ENSURE_TRUE(mutexLock.Lock(MOZ_DDE_START_TIMEOUT), NS_ERROR_FAILURE);
   784     // If we've got a message window to receive IPC or new window requests,
   785     // get rid of it as we are shutting down.
   786     // Note:  Destroy calls DestroyWindow, which will only work on a window
   787     //  created by the same thread.
   788     MessageWindow mw;
   789     mw.Destroy();
   791     if ( mInstance ) {
   792         // Unregister application name.
   793         DdeNameService( mInstance, mApplication, 0, DNS_UNREGISTER );
   794         // Clean up strings.
   795         if ( mApplication ) {
   796             DdeFreeStringHandle( mInstance, mApplication );
   797             mApplication = 0;
   798         }
   799         for ( int i = 0; i < topicCount; i++ ) {
   800             if ( mTopics[i] ) {
   801                 DdeFreeStringHandle( mInstance, mTopics[i] );
   802                 mTopics[i] = 0;
   803             }
   804         }
   805         DdeUninitialize( mInstance );
   806         mInstance = 0;
   807 #if MOZ_DEBUG_DDE
   808     printf( "DDE server stopped\n" );
   809 #endif
   810     }
   812     return NS_OK;
   813 }
   815 NS_IMETHODIMP
   816 nsNativeAppSupportWin::Enable()
   817 {
   818     mCanHandleRequests = true;
   820     nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   821     if (obs) {
   822         obs->AddObserver(this, "quit-application", false);
   823     } else {
   824         NS_ERROR("No observer service?");
   825     }
   827     return NS_OK;
   828 }
   830 #if MOZ_DEBUG_DDE
   831 // Macro to generate case statement for a given XTYP value.
   832 #define XTYP_CASE(t) \
   833     case t: result = #t; break
   835 static nsCString uTypeDesc( UINT uType ) {
   836     nsCString result;
   837     switch ( uType ) {
   838     XTYP_CASE(XTYP_ADVSTART);
   839     XTYP_CASE(XTYP_CONNECT);
   840     XTYP_CASE(XTYP_ADVREQ);
   841     XTYP_CASE(XTYP_REQUEST);
   842     XTYP_CASE(XTYP_WILDCONNECT);
   843     XTYP_CASE(XTYP_ADVDATA);
   844     XTYP_CASE(XTYP_EXECUTE);
   845     XTYP_CASE(XTYP_POKE);
   846     XTYP_CASE(XTYP_ADVSTOP);
   847     XTYP_CASE(XTYP_CONNECT_CONFIRM);
   848     XTYP_CASE(XTYP_DISCONNECT);
   849     XTYP_CASE(XTYP_ERROR);
   850     XTYP_CASE(XTYP_MONITOR);
   851     XTYP_CASE(XTYP_REGISTER);
   852     XTYP_CASE(XTYP_XACT_COMPLETE);
   853     XTYP_CASE(XTYP_UNREGISTER);
   854     default: result = "XTYP_?????";
   855     }
   856     return result;
   857 }
   859 static nsCString hszValue( DWORD instance, HSZ hsz ) {
   860     // Extract string from HSZ.
   861     nsCString result("[");
   862     DWORD len = DdeQueryString( instance, hsz, nullptr, nullptr, CP_WINANSI );
   863     if ( len ) {
   864         char buffer[ 256 ];
   865         DdeQueryString( instance, hsz, buffer, sizeof buffer, CP_WINANSI );
   866         result += buffer;
   867     }
   868     result += "]";
   869     return result;
   870 }
   871 #else
   872 // These are purely a safety measure to avoid the infamous "won't
   873 // build non-debug" type Tinderbox flames.
   874 static nsCString uTypeDesc( UINT ) {
   875     return nsCString( "?" );
   876 }
   877 static nsCString hszValue( DWORD, HSZ ) {
   878     return nsCString( "?" );
   879 }
   880 #endif
   883 // Utility function to escape double-quotes within a string.
   884 static void escapeQuotes( nsAString &aString ) {
   885     int32_t offset = -1;
   886     while( 1 ) {
   887        // Find next '"'.
   888        offset = aString.FindChar( '"', ++offset );
   889        if ( offset == kNotFound ) {
   890            // No more quotes, exit.
   891            break;
   892        } else {
   893            // Insert back-slash ahead of the '"'.
   894            aString.Insert( char16_t('\\'), offset );
   895            // Increment offset because we just inserted a slash
   896            offset++;
   897        }
   898     }
   899     return;
   900 }
   902 HDDEDATA CALLBACK
   903 nsNativeAppSupportWin::HandleDDENotification( UINT uType,       // transaction type
   904                                               UINT uFmt,        // clipboard data format
   905                                               HCONV hconv,      // handle to the conversation
   906                                               HSZ hsz1,         // handle to a string
   907                                               HSZ hsz2,         // handle to a string
   908                                               HDDEDATA hdata,   // handle to a global memory object
   909                                               ULONG_PTR dwData1,    // transaction-specific data
   910                                               ULONG_PTR dwData2 ) { // transaction-specific data
   912     if (!mCanHandleRequests)
   913         return 0;
   916 #if MOZ_DEBUG_DDE
   917     printf( "DDE: uType  =%s\n",      uTypeDesc( uType ).get() );
   918     printf( "     uFmt   =%u\n",      (unsigned)uFmt );
   919     printf( "     hconv  =%08x\n",    (int)hconv );
   920     printf( "     hsz1   =%08x:%s\n", (int)hsz1, hszValue( mInstance, hsz1 ).get() );
   921     printf( "     hsz2   =%08x:%s\n", (int)hsz2, hszValue( mInstance, hsz2 ).get() );
   922     printf( "     hdata  =%08x\n",    (int)hdata );
   923     printf( "     dwData1=%08x\n",    (int)dwData1 );
   924     printf( "     dwData2=%08x\n",    (int)dwData2 );
   925 #endif
   927     HDDEDATA result = 0;
   928     if ( uType & XCLASS_BOOL ) {
   929         switch ( uType ) {
   930             case XTYP_CONNECT:
   931                 // Make sure its for our service/topic.
   932                 if ( FindTopic( hsz1 ) != -1 ) {
   933                     // We support this connection.
   934                     result = (HDDEDATA)1;
   935                 }
   936                 break;
   937             case XTYP_CONNECT_CONFIRM:
   938                 // We don't care about the conversation handle, at this point.
   939                 result = (HDDEDATA)1;
   940                 break;
   941         }
   942     } else if ( uType & XCLASS_DATA ) {
   943         if ( uType == XTYP_REQUEST ) {
   944             switch ( FindTopic( hsz1 ) ) {
   945                 case topicOpenURL: {
   946                     // Open a given URL...
   948                     // Get the URL from the first argument in the command.
   949                     nsAutoString url;
   950                     ParseDDEArg(hsz2, 0, url);
   952                     // Read the 3rd argument in the command to determine if a
   953                     // new window is to be used.
   954                     nsAutoString windowID;
   955                     ParseDDEArg(hsz2, 2, windowID);
   956                     // "" means to open the URL in a new window.
   957                     if ( windowID.IsEmpty() ) {
   958                         url.Insert(NS_LITERAL_STRING("mozilla -new-window "), 0);
   959                     }
   960                     else {
   961                         url.Insert(NS_LITERAL_STRING("mozilla -url "), 0);
   962                     }
   964 #if MOZ_DEBUG_DDE
   965                     printf( "Handling dde XTYP_REQUEST request: [%s]...\n", NS_ConvertUTF16toUTF8(url).get() );
   966 #endif
   967                     // Now handle it.
   968                     HandleCommandLine(NS_ConvertUTF16toUTF8(url).get(), nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
   970                     // Return pseudo window ID.
   971                     result = CreateDDEData( 1 );
   972                     break;
   973                 }
   974                 case topicGetWindowInfo: {
   975                     // This topic has to get the current URL, get the current
   976                     // page title and then format the output into the DDE
   977                     // return string.  The return value is "URL","Page Title",
   978                     // "Window ID" however the window ID is not used for this
   979                     // command, therefore it is returned as a null string
   981                     // This isn't really a loop.  We just use "break"
   982                     // statements to bypass the remaining steps when
   983                     // something goes wrong.
   984                     do {
   985                         // Get most recently used Nav window.
   986                         nsCOMPtr<nsIDOMWindow> navWin;
   987                         GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(),
   988                                              getter_AddRefs( navWin ) );
   989                         if ( !navWin ) {
   990                             // There is not a window open
   991                             break;
   992                         }
   993                         // Get content window.
   994                         nsCOMPtr<nsIDOMWindow> content;
   995                         navWin->GetContent( getter_AddRefs( content ) );
   996                         if ( !content ) {
   997                             break;
   998                         }
   999                         // Convert that to internal interface.
  1000                         nsCOMPtr<nsPIDOMWindow> internalContent( do_QueryInterface( content ) );
  1001                         if ( !internalContent ) {
  1002                             break;
  1004                         // Get location.
  1005                         nsCOMPtr<nsIDOMLocation> location;
  1006                         internalContent->GetLocation( getter_AddRefs( location ) );
  1007                         if ( !location ) {
  1008                             break;
  1010                         // Get href for URL.
  1011                         nsAutoString url;
  1012                         if ( NS_FAILED( location->GetHref( url ) ) ) {
  1013                             break;
  1015                         // Escape any double-quotes.
  1016                         escapeQuotes( url );
  1018                         // Now for the title...
  1020                         // Get the base window from the doc shell...
  1021                         nsCOMPtr<nsIBaseWindow> baseWindow =
  1022                           do_QueryInterface( internalContent->GetDocShell() );
  1023                         if ( !baseWindow ) {
  1024                             break;
  1026                         // And from the base window we can get the title.
  1027                         nsXPIDLString title;
  1028                         if(!baseWindow) {
  1029                             break;
  1031                         baseWindow->GetTitle(getter_Copies(title));
  1032                         // Escape any double-quotes in the title.
  1033                         escapeQuotes( title );
  1035                         // Use a string buffer for the output data, first
  1036                         // save a quote.
  1037                         nsAutoCString   outpt( NS_LITERAL_CSTRING("\"") );
  1038                         // Now copy the URL converting the Unicode string
  1039                         // to a single-byte ASCII string
  1040                         nsAutoCString tmpNativeStr;
  1041                         NS_CopyUnicodeToNative( url, tmpNativeStr );
  1042                         outpt.Append( tmpNativeStr );
  1043                         // Add the "," used to separate the URL and the page
  1044                         // title
  1045                         outpt.Append( NS_LITERAL_CSTRING("\",\"") );
  1046                         // Now copy the current page title to the return string
  1047                         NS_CopyUnicodeToNative( title, tmpNativeStr );
  1048                         outpt.Append( tmpNativeStr );
  1049                         // Fill out the return string with the remainin ",""
  1050                         outpt.Append( NS_LITERAL_CSTRING( "\",\"\"" ));
  1052                         // Create a DDE handle to a char string for the data
  1053                         // being returned, this copies and creates a "shared"
  1054                         // copy of the DDE response until the calling APP
  1055                         // reads it and says it can be freed.
  1056                         result = CreateDDEData( (LPBYTE)(const char*)outpt.get(),
  1057                                                 outpt.Length() + 1 );
  1058 #if MOZ_DEBUG_DDE
  1059                         printf( "WWW_GetWindowInfo->%s\n", outpt.get() );
  1060 #endif
  1061                     } while ( false );
  1062                     break;
  1064                 case topicActivate: {
  1065                     // Activate a Nav window...
  1066                     nsAutoString windowID;
  1067                     ParseDDEArg(hsz2, 0, windowID);
  1068                     // 4294967295 is decimal for 0xFFFFFFFF which is also a
  1069                     //   correct value to do that Activate last window stuff
  1070                     if ( windowID.EqualsLiteral( "-1" ) ||
  1071                          windowID.EqualsLiteral( "4294967295" ) ) {
  1072                         // We only support activating the most recent window (or a new one).
  1073                         ActivateLastWindow();
  1074                         // Return pseudo window ID.
  1075                         result = CreateDDEData( 1 );
  1077                     break;
  1079                 case topicVersion: {
  1080                     // Return version.  We're restarting at 1.0!
  1081                     DWORD version = 1 << 16; // "1.0"
  1082                     result = CreateDDEData( version );
  1083                     break;
  1085                 case topicRegisterViewer: {
  1086                     // Register new viewer (not implemented).
  1087                     result = CreateDDEData( false );
  1088                     break;
  1090                 case topicUnRegisterViewer: {
  1091                     // Unregister new viewer (not implemented).
  1092                     result = CreateDDEData( false );
  1093                     break;
  1095                 default:
  1096                     break;
  1098         } else if ( uType & XTYP_POKE ) {
  1099             switch ( FindTopic( hsz1 ) ) {
  1100                 case topicCancelProgress: {
  1101                     // "Handle" progress cancel (actually, pretty much ignored).
  1102                     result = (HDDEDATA)DDE_FACK;
  1103                     break;
  1105                 default:
  1106                     break;
  1109     } else if ( uType & XCLASS_FLAGS ) {
  1110         if ( uType == XTYP_EXECUTE ) {
  1111             // Prove that we received the request.
  1112             DWORD bytes;
  1113             LPBYTE request = DdeAccessData( hdata, &bytes );
  1114 #if MOZ_DEBUG_DDE
  1115             printf( "Handling dde request: [%s]...\n", (char*)request );
  1116 #endif
  1118             nsAutoString url;
  1119             ParseDDEArg((const WCHAR*) request, 0, url);
  1121             // Read the 3rd argument in the command to determine if a
  1122             // new window is to be used.
  1123             nsAutoString windowID;
  1124             ParseDDEArg((const WCHAR*) request, 2, windowID);
  1126             // "" means to open the URL in a new window.
  1127             if ( windowID.IsEmpty() ) {
  1128                 url.Insert(NS_LITERAL_STRING("mozilla -new-window "), 0);
  1130             else {
  1131                 url.Insert(NS_LITERAL_STRING("mozilla -url "), 0);
  1133 #if MOZ_DEBUG_DDE
  1134             printf( "Handling dde XTYP_REQUEST request: [%s]...\n", NS_ConvertUTF16toUTF8(url).get() );
  1135 #endif
  1136             // Now handle it.
  1137             HandleCommandLine(NS_ConvertUTF16toUTF8(url).get(), nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
  1139             // Release the data.
  1140             DdeUnaccessData( hdata );
  1141             result = (HDDEDATA)DDE_FACK;
  1142         } else {
  1143             result = (HDDEDATA)DDE_FNOTPROCESSED;
  1145     } else if ( uType & XCLASS_NOTIFICATION ) {
  1147 #if MOZ_DEBUG_DDE
  1148     printf( "DDE result=%d (0x%08X)\n", (int)result, (int)result );
  1149 #endif
  1150     return result;
  1153 // Utility function to advance to end of quoted string.
  1154 // p+offset must point to the comma preceding the arg on entry.
  1155 // On return, p+result points to the closing '"' (or end of the string
  1156 // if the closing '"' is missing) if the arg is quoted.  If the arg
  1157 // is not quoted, then p+result will point to the first character
  1158 // of the arg.
  1159 static int32_t advanceToEndOfQuotedArg( const WCHAR *p, int32_t offset, int32_t len ) {
  1160     // Check whether the current arg is quoted.
  1161     if ( p[++offset] == '"' ) {
  1162         // Advance past the closing quote.
  1163         while ( offset < len && p[++offset] != '"' ) {
  1164             // If the current character is a backslash, then the
  1165             // next character can't be a *real* '"', so skip it.
  1166             if ( p[offset] == '\\' ) {
  1167                 offset++;
  1171     return offset;
  1174 void nsNativeAppSupportWin::ParseDDEArg( const WCHAR* args, int index, nsString& aString) {
  1175     if ( args ) {
  1176         nsDependentString temp(args);
  1178         // offset points to the comma preceding the desired arg.
  1179         int32_t offset = -1;
  1180         // Skip commas till we get to the arg we want.
  1181         while( index-- ) {
  1182             // If this arg is quoted, then go to closing quote.
  1183             offset = advanceToEndOfQuotedArg( args, offset, temp.Length());
  1184             // Find next comma.
  1185             offset = temp.FindChar( ',', offset );
  1186             if ( offset == kNotFound ) {
  1187                 // No more commas, give up.
  1188                 aString = args;
  1189                 return;
  1192         // The desired argument starts just past the preceding comma,
  1193         // which offset points to, and extends until the following
  1194         // comma (or the end of the string).
  1195         //
  1196         // Since the argument might be enclosed in quotes, we need to
  1197         // deal with that before searching for the terminating comma.
  1198         // We advance offset so it ends up pointing to the start of
  1199         // the argument we want.
  1200         int32_t end = advanceToEndOfQuotedArg( args, offset++, temp.Length() );
  1201         // Find next comma (or end of string).
  1202         end = temp.FindChar( ',', end );
  1203         if ( end == kNotFound ) {
  1204             // Arg is the rest of the string.
  1205             end = temp.Length();
  1207         // Extract result.
  1208         aString.Assign( args + offset, end - offset );
  1210     return;
  1213 // Utility to parse out argument from a DDE item string.
  1214 void nsNativeAppSupportWin::ParseDDEArg( HSZ args, int index, nsString& aString) {
  1215     DWORD argLen = DdeQueryStringW( mInstance, args, nullptr, 0, CP_WINUNICODE );
  1216     // there wasn't any string, so return empty string
  1217     if ( !argLen ) return;
  1218     nsAutoString temp;
  1219     // Ensure result's buffer is sufficiently big.
  1220     temp.SetLength( argLen );
  1221     // Now get the string contents.
  1222     DdeQueryString( mInstance, args, reinterpret_cast<wchar_t*>(temp.BeginWriting()), temp.Length(), CP_WINUNICODE );
  1223     // Parse out the given arg.
  1224     ParseDDEArg(temp.get(), index, aString);
  1225     return;
  1228 HDDEDATA nsNativeAppSupportWin::CreateDDEData( DWORD value ) {
  1229     return CreateDDEData( (LPBYTE)&value, sizeof value );
  1232 HDDEDATA nsNativeAppSupportWin::CreateDDEData( LPBYTE value, DWORD len ) {
  1233     HDDEDATA result = DdeCreateDataHandle( mInstance,
  1234                                            value,
  1235                                            len,
  1236                                            0,
  1237                                            mApplication,
  1238                                            CF_TEXT,
  1239                                            0 );
  1240     return result;
  1243 void nsNativeAppSupportWin::ActivateLastWindow() {
  1244     nsCOMPtr<nsIDOMWindow> navWin;
  1245     GetMostRecentWindow( MOZ_UTF16("navigator:browser"), getter_AddRefs( navWin ) );
  1246     if ( navWin ) {
  1247         // Activate that window.
  1248         activateWindow( navWin );
  1249     } else {
  1250         // Need to create a Navigator window, then.
  1251         OpenBrowserWindow();
  1255 void
  1256 nsNativeAppSupportWin::HandleCommandLine(const char* aCmdLineString,
  1257                                          nsIFile* aWorkingDir,
  1258                                          uint32_t aState)
  1260     nsresult rv;
  1262     int justCounting = 1;
  1263     char **argv = 0;
  1264     // Flags, etc.
  1265     int init = 1;
  1266     int between, quoted, bSlashCount;
  1267     int argc;
  1268     const char *p;
  1269     nsAutoCString arg;
  1271     nsCOMPtr<nsICommandLineRunner> cmdLine
  1272         (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
  1273     if (!cmdLine) {
  1274         NS_ERROR("Couldn't create command line!");
  1275         return;
  1278     // Parse command line args according to MS spec
  1279     // (see "Parsing C++ Command-Line Arguments" at
  1280     // http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
  1281     // We loop if we've not finished the second pass through.
  1282     while ( 1 ) {
  1283         // Initialize if required.
  1284         if ( init ) {
  1285             p = aCmdLineString;
  1286             between = 1;
  1287             argc = quoted = bSlashCount = 0;
  1289             init = 0;
  1291         if ( between ) {
  1292             // We are traversing whitespace between args.
  1293             // Check for start of next arg.
  1294             if (  *p != 0 && !isspace( *p ) ) {
  1295                 // Start of another arg.
  1296                 between = 0;
  1297                 arg = "";
  1298                 switch ( *p ) {
  1299                     case '\\':
  1300                         // Count the backslash.
  1301                         bSlashCount = 1;
  1302                         break;
  1303                     case '"':
  1304                         // Remember we're inside quotes.
  1305                         quoted = 1;
  1306                         break;
  1307                     default:
  1308                         // Add character to arg.
  1309                         arg += *p;
  1310                         break;
  1312             } else {
  1313                 // Another space between args, ignore it.
  1315         } else {
  1316             // We are processing the contents of an argument.
  1317             // Check for whitespace or end.
  1318             if ( *p == 0 || ( !quoted && isspace( *p ) ) ) {
  1319                 // Process pending backslashes (interpret them
  1320                 // literally since they're not followed by a ").
  1321                 while( bSlashCount ) {
  1322                     arg += '\\';
  1323                     bSlashCount--;
  1325                 // End current arg.
  1326                 if ( !justCounting ) {
  1327                     argv[argc] = new char[ arg.Length() + 1 ];
  1328                     strcpy( argv[argc], arg.get() );
  1330                 argc++;
  1331                 // We're now between args.
  1332                 between = 1;
  1333             } else {
  1334                 // Still inside argument, process the character.
  1335                 switch ( *p ) {
  1336                     case '"':
  1337                         // First, digest preceding backslashes (if any).
  1338                         while ( bSlashCount > 1 ) {
  1339                             // Put one backsplash in arg for each pair.
  1340                             arg += '\\';
  1341                             bSlashCount -= 2;
  1343                         if ( bSlashCount ) {
  1344                             // Quote is literal.
  1345                             arg += '"';
  1346                             bSlashCount = 0;
  1347                         } else {
  1348                             // Quote starts or ends a quoted section.
  1349                             if ( quoted ) {
  1350                                 // Check for special case of consecutive double
  1351                                 // quotes inside a quoted section.
  1352                                 if ( *(p+1) == '"' ) {
  1353                                     // This implies a literal double-quote.  Fake that
  1354                                     // out by causing next double-quote to look as
  1355                                     // if it was preceded by a backslash.
  1356                                     bSlashCount = 1;
  1357                                 } else {
  1358                                     quoted = 0;
  1360                             } else {
  1361                                 quoted = 1;
  1364                         break;
  1365                     case '\\':
  1366                         // Add to count.
  1367                         bSlashCount++;
  1368                         break;
  1369                     default:
  1370                         // Accept any preceding backslashes literally.
  1371                         while ( bSlashCount ) {
  1372                             arg += '\\';
  1373                             bSlashCount--;
  1375                         // Just add next char to the current arg.
  1376                         arg += *p;
  1377                         break;
  1381         // Check for end of input.
  1382         if ( *p ) {
  1383             // Go to next character.
  1384             p++;
  1385         } else {
  1386             // If on first pass, go on to second.
  1387             if ( justCounting ) {
  1388                 // Allocate argv array.
  1389                 argv = new char*[ argc ];
  1391                 // Start second pass
  1392                 justCounting = 0;
  1393                 init = 1;
  1394             } else {
  1395                 // Quit.
  1396                 break;
  1401     rv = cmdLine->Init(argc, argv, aWorkingDir, aState);
  1403     // Cleanup.
  1404     while ( argc ) {
  1405         delete [] argv[ --argc ];
  1407     delete [] argv;
  1409     if (NS_FAILED(rv)) {
  1410         NS_ERROR("Error initializing command line.");
  1411         return;
  1414     cmdLine->Run();
  1417 nsresult
  1418 nsNativeAppSupportWin::OpenWindow( const char*urlstr, const char *args ) {
  1420   nsresult rv = NS_ERROR_FAILURE;
  1422   nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
  1423   nsCOMPtr<nsISupportsCString> sarg(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
  1424   if (sarg)
  1425     sarg->SetData(nsDependentCString(args));
  1427   if (wwatch && sarg) {
  1428     nsCOMPtr<nsIDOMWindow> newWindow;
  1429     rv = wwatch->OpenWindow(0, urlstr, "_blank", "chrome,dialog=no,all",
  1430                    sarg, getter_AddRefs(newWindow));
  1431 #if MOZ_DEBUG_DDE
  1432   } else {
  1433       printf("Get WindowWatcher (or create string) failed\n");
  1434 #endif
  1436   return rv;
  1439 HWND hwndForDOMWindow( nsISupports *window ) {
  1440     nsCOMPtr<nsPIDOMWindow> pidomwindow( do_QueryInterface(window) );
  1441     if ( !pidomwindow ) {
  1442         return 0;
  1445     nsCOMPtr<nsIBaseWindow> ppBaseWindow =
  1446         do_QueryInterface( pidomwindow->GetDocShell() );
  1447     if ( !ppBaseWindow ) {
  1448         return 0;
  1451     nsCOMPtr<nsIWidget> ppWidget;
  1452     ppBaseWindow->GetMainWidget( getter_AddRefs( ppWidget ) );
  1454     return (HWND)( ppWidget->GetNativeData( NS_NATIVE_WIDGET ) );
  1457 nsresult
  1458 nsNativeAppSupportWin::OpenBrowserWindow()
  1460     nsresult rv = NS_OK;
  1462     // Open the argument URL in the most recently used Navigator window.
  1463     // If there is no Nav window, open a new one.
  1465     // If at all possible, hand the request off to the most recent
  1466     // browser window.
  1468     nsCOMPtr<nsIDOMWindow> navWin;
  1469     GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(), getter_AddRefs( navWin ) );
  1471     // This isn't really a loop.  We just use "break" statements to fall
  1472     // out to the OpenWindow call when things go awry.
  1473     do {
  1474         // If caller requires a new window, then don't use an existing one.
  1475         if ( !navWin ) {
  1476             // Have to open a new one.
  1477             break;
  1480         nsCOMPtr<nsIBrowserDOMWindow> bwin;
  1481         { // scope a bunch of temporary cruft used to generate bwin
  1482           nsCOMPtr<nsIWebNavigation> navNav( do_GetInterface( navWin ) );
  1483           nsCOMPtr<nsIDocShellTreeItem> navItem( do_QueryInterface( navNav ) );
  1484           if ( navItem ) {
  1485             nsCOMPtr<nsIDocShellTreeItem> rootItem;
  1486             navItem->GetRootTreeItem( getter_AddRefs( rootItem ) );
  1487             nsCOMPtr<nsIDOMWindow> rootWin( do_GetInterface( rootItem ) );
  1488             nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
  1489             if ( chromeWin )
  1490               chromeWin->GetBrowserDOMWindow( getter_AddRefs ( bwin ) );
  1493         if ( bwin ) {
  1494           nsCOMPtr<nsIURI> uri;
  1495           NS_NewURI( getter_AddRefs( uri ), NS_LITERAL_CSTRING("about:blank"), 0, 0 );
  1496           if ( uri ) {
  1497             nsCOMPtr<nsIDOMWindow> container;
  1498             rv = bwin->OpenURI( uri, 0,
  1499                                 nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
  1500                                 nsIBrowserDOMWindow::OPEN_EXTERNAL,
  1501                                 getter_AddRefs( container ) );
  1502             if ( NS_SUCCEEDED( rv ) )
  1503               return NS_OK;
  1507         NS_ERROR("failed to hand off external URL to extant window");
  1508     } while ( false );
  1510     // open a new window if caller requested it or if anything above failed
  1512     char* argv[] = { 0 };
  1513     nsCOMPtr<nsICommandLineRunner> cmdLine
  1514         (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
  1515     NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
  1517     rv = cmdLine->Init(0, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
  1518     NS_ENSURE_SUCCESS(rv, rv);
  1520     return cmdLine->Run();

mercurial