123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #include "nsNativeAppSupportBase.h"
- #include "nsNativeAppSupportWin.h"
- #include "nsAppRunner.h"
- #include "nsXULAppAPI.h"
- #include "nsString.h"
- #include "nsIBrowserDOMWindow.h"
- #include "nsICommandLineRunner.h"
- #include "nsCOMPtr.h"
- #include "nsXPIDLString.h"
- #include "nsIComponentManager.h"
- #include "nsIServiceManager.h"
- #include "nsIDOMChromeWindow.h"
- #include "nsXPCOM.h"
- #include "nsISupportsPrimitives.h"
- #include "nsIWindowWatcher.h"
- #include "nsPIDOMWindow.h"
- #include "nsGlobalWindow.h"
- #include "nsIDocShell.h"
- #include "nsIDocShellTreeItem.h"
- #include "nsIBaseWindow.h"
- #include "nsIWidget.h"
- #include "nsIAppShellService.h"
- #include "nsIXULWindow.h"
- #include "nsIInterfaceRequestor.h"
- #include "nsIInterfaceRequestorUtils.h"
- #include "nsIPromptService.h"
- #include "nsNetCID.h"
- #include "nsNetUtil.h"
- #include "mozilla/Services.h"
- #include "nsIFile.h"
- #include "nsIObserver.h"
- #include "nsIObserverService.h"
- #include "nsIDOMLocation.h"
- #include "nsIWebNavigation.h"
- #include "nsIWindowMediator.h"
- #include "nsNativeCharsetUtils.h"
- #include "nsIAppStartup.h"
- #include <windows.h>
- #include <shellapi.h>
- #include <ddeml.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <io.h>
- #include <direct.h>
- #include <fcntl.h>
- using namespace mozilla;
- static HWND hwndForDOMWindow( mozIDOMWindowProxy * );
- static
- nsresult
- GetMostRecentWindow(const char16_t* aType, mozIDOMWindowProxy** aWindow) {
- nsresult rv;
- nsCOMPtr<nsIWindowMediator> med( do_GetService( NS_WINDOWMEDIATOR_CONTRACTID, &rv ) );
- if ( NS_FAILED( rv ) )
- return rv;
- if ( med )
- return med->GetMostRecentWindow( aType, aWindow );
- return NS_ERROR_FAILURE;
- }
- static
- void
- activateWindow( mozIDOMWindowProxy *win ) {
- // Try to get native window handle.
- HWND hwnd = hwndForDOMWindow( win );
- if ( hwnd ) {
- // Restore the window if it is minimized.
- if ( ::IsIconic( hwnd ) ) {
- ::ShowWindow( hwnd, SW_RESTORE );
- }
- // Use the OS call, if possible.
- ::SetForegroundWindow( hwnd );
- } else {
- // Use internal method.
- nsCOMPtr<nsPIDOMWindowOuter> piWin = nsPIDOMWindowOuter::From(win);
- piWin->Focus();
- }
- }
- #ifdef DEBUG_law
- #undef MOZ_DEBUG_DDE
- #define MOZ_DEBUG_DDE 1
- #endif
- // Simple Win32 mutex wrapper.
- struct Win32Mutex {
- Win32Mutex( const char16_t *name )
- : mName( name ),
- mHandle( 0 ),
- mState( -1 ) {
- mHandle = CreateMutexW( 0, FALSE, mName.get() );
- #if MOZ_DEBUG_DDE
- printf( "CreateMutex error = 0x%08X\n", (int)GetLastError() );
- #endif
- }
- ~Win32Mutex() {
- if ( mHandle ) {
- // Make sure we release it if we own it.
- Unlock();
- BOOL rc = CloseHandle( mHandle );
- #if MOZ_DEBUG_DDE
- if ( !rc ) {
- printf( "CloseHandle error = 0x%08X\n", (int)GetLastError() );
- }
- #endif
- }
- }
- BOOL Lock( DWORD timeout ) {
- if ( mHandle ) {
- #if MOZ_DEBUG_DDE
- printf( "Waiting (%d msec) for DDE mutex...\n", (int)timeout );
- #endif
- mState = WaitForSingleObject( mHandle, timeout );
- #if MOZ_DEBUG_DDE
- printf( "...wait complete, result = 0x%08X, GetLastError=0x%08X\n", (int)mState, (int)::GetLastError() );
- #endif
- return mState == WAIT_OBJECT_0 || mState == WAIT_ABANDONED;
- } else {
- return FALSE;
- }
- }
- void Unlock() {
- if ( mHandle && mState == WAIT_OBJECT_0 ) {
- #if MOZ_DEBUG_DDE
- printf( "Releasing DDE mutex\n" );
- #endif
- ReleaseMutex( mHandle );
- mState = -1;
- }
- }
- private:
- nsString mName;
- HANDLE mHandle;
- DWORD mState;
- };
- /* DDE Notes
- *
- * This section describes the Win32 DDE service implementation for
- * Mozilla. DDE is used on Win32 platforms to communicate between
- * separate instances of mozilla.exe (or other Mozilla-based
- * executables), or, between the Win32 desktop shell and Mozilla.
- *
- * The first instance of Mozilla will become the "server" and
- * subsequent executables (and the shell) will use DDE to send
- * requests to that process. The requests are DDE "execute" requests
- * that pass the command line arguments.
- *
- * Mozilla registers the DDE application "Mozilla" and currently
- * supports only the "WWW_OpenURL" topic. This should be reasonably
- * compatible with applications that interfaced with Netscape
- * Communicator (and its predecessors?). Note that even that topic
- * may not be supported in a compatible fashion as the command-line
- * options for Mozilla are different than for Communiator.
- *
- * It is imperative that at most one instance of Mozilla execute in
- * "server mode" at any one time. The "native app support" in Mozilla
- * on Win32 ensures that only the server process performs XPCOM
- * initialization (that is not required for subsequent client processes
- * to communicate with the server process).
- *
- * To guarantee that only one server starts up, a Win32 "mutex" is used
- * to ensure only one process executes the server-detection code. That
- * code consists of initializing DDE and doing a DdeConnect to Mozilla's
- * application/topic. If that connection succeeds, then a server process
- * must be running already.
- *
- * Otherwise, no server has started. In that case, the current process
- * calls DdeNameService to register that application/topic. Only at that
- * point does the mutex get released.
- *
- * There are a couple of subtleties that one should be aware of:
- *
- * 1. It is imperative that DdeInitialize be called only after the mutex
- * lock has been obtained. The reason is that at shutdown, DDE
- * notifications go out to all initialized DDE processes. Thus, if
- * the mutex is owned by a terminating intance of Mozilla, then
- * calling DdeInitialize and then WaitForSingleObject will cause the
- * DdeUninitialize from the terminating process to "hang" until the
- * process waiting for the mutex times out (and can then service the
- * notification that the DDE server is terminating). So, don't mess
- * with the sequence of things in the startup/shutdown logic.
- *
- * 2. All mutex requests are made with a reasonably long timeout value and
- * are designed to "fail safe" (i.e., a timeout is treated as failure).
- *
- * 3. An attempt has been made to minimize the degree to which the main
- * Mozilla application logic needs to be aware of the DDE mechanisms
- * implemented herein. As a result, this module surfaces a very
- * large-grained interface, consisting of simple start/stop methods.
- * As a consequence, details of certain scenarios can be "lost."
- * Particularly, incoming DDE requests can arrive after this module
- * initiates the DDE server, but before Mozilla is initialized to the
- * point where those requests can be serviced (e.g., open a browser
- * window to a particular URL). Since the client process sends the
- * request early on, it may not be prepared to respond to that error.
- * Thus, such situations may fail silently. The design goal is that
- * they fail harmlessly. Refinements on this point will be made as
- * details emerge (and time permits).
- */
- /* Update 2001 March
- *
- * A significant DDE bug in Windows is causing Mozilla to get wedged at
- * startup. This is detailed in Bugzill bug 53952
- * (http://bugzilla.mozilla.org/show_bug.cgi?id=53952).
- *
- * To resolve this, we are using a new strategy:
- * o Use a "message window" to detect that Mozilla is already running and
- * to pass requests from a second instance back to the first;
- * o Run only as a "DDE server" (not as DDE client); this avoids the
- * problematic call to DDEConnect().
- *
- * We still use the mutex semaphore to protect the code that detects
- * whether Mozilla is already running.
- */
- /* Update 2007 January
- *
- * A change in behavior was implemented in July 2004 which made the
- * application on launch to add and on quit to remove the ddexec registry key.
- * See bug 246078.
- * Windows Vista has changed the methods used to set an application as default
- * and the new methods are incompatible with removing the ddeexec registry key.
- * See bug 353089.
- *
- * OS DDE Sequence:
- * 1. OS checks if the dde name is registered.
- * 2. If it is registered the OS sends a DDE request with the WWW_OpenURL topic
- * and the params as specified in the default value of the ddeexec registry
- * key for the verb (e.g. open).
- * 3. If it isn't registered the OS launches the executable defined in the
- * verb's (e.g. open) command registry key.
- * 4. If the ifexec registry key is not present the OS sends a DDE request with
- * the WWW_OpenURL topic and the params as specified in the default value of
- * the ddeexec registry key for the verb (e.g. open).
- * 5. If the ifexec registry key is present the OS sends a DDE request with the
- * WWW_OpenURL topic and the params as specified in the ifexec registry key
- * for the verb (e.g. open).
- *
- * Application DDE Sequence:
- * 1. If the application is running a DDE request is received with the
- * WWW_OpenURL topic and the params as specified in the default value of the
- * ddeexec registry key (e.g. "%1",,0,0,,,, where '%1' is the url to open)
- * for the verb (e.g. open).
- * 2. If the application is not running it is launched with the --requestPending
- * and the --url argument.
- * 2.1 If the application does not need to restart and the --requestPending
- * argument is present the accompanying url will not be used. Instead the
- * application will wait for the DDE message to open the url.
- * 2.2 If the application needs to restart the --requestPending argument is
- * removed from the arguments used to restart the application and the url
- * will be handled normally.
- *
- * Note: Due to a bug in IE the ifexec key should not be used (see bug 355650).
- */
- class nsNativeAppSupportWin : public nsNativeAppSupportBase,
- public nsIObserver
- {
- public:
- NS_DECL_NSIOBSERVER
- NS_DECL_ISUPPORTS_INHERITED
- // Overrides of base implementation.
- NS_IMETHOD Start( bool *aResult );
- NS_IMETHOD Stop( bool *aResult );
- NS_IMETHOD Quit();
- NS_IMETHOD Enable();
- // The "old" Start method (renamed).
- NS_IMETHOD StartDDE();
- // Utility function to handle a Win32-specific command line
- // option: "--console", which dynamically creates a Windows
- // console.
- void CheckConsole();
- private:
- ~nsNativeAppSupportWin() {}
- static void HandleCommandLine(const char* aCmdLineString, nsIFile* aWorkingDir, uint32_t aState);
- static HDDEDATA CALLBACK HandleDDENotification( UINT uType,
- UINT uFmt,
- HCONV hconv,
- HSZ hsz1,
- HSZ hsz2,
- HDDEDATA hdata,
- ULONG_PTR dwData1,
- ULONG_PTR dwData2 );
- static void ParseDDEArg( HSZ args, int index, nsString& string);
- static void ParseDDEArg( const WCHAR* args, int index, nsString& aString);
- static HDDEDATA CreateDDEData( DWORD value );
- static HDDEDATA CreateDDEData( LPBYTE value, DWORD len );
- static bool InitTopicStrings();
- static int FindTopic( HSZ topic );
- static void ActivateLastWindow();
- static nsresult OpenWindow( const char *urlstr, const char *args );
- static nsresult OpenBrowserWindow();
- static void SetupSysTrayIcon();
- static void RemoveSysTrayIcon();
- static int mConversations;
- enum {
- topicOpenURL,
- topicActivate,
- topicCancelProgress,
- topicVersion,
- topicRegisterViewer,
- topicUnRegisterViewer,
- topicGetWindowInfo,
- // Note: Insert new values above this line!!!!!
- topicCount // Count of the number of real topics
- };
- static HSZ mApplication, mTopics[ topicCount ];
- static DWORD mInstance;
- static bool mCanHandleRequests;
- static char16_t mMutexName[];
- friend struct MessageWindow;
- }; // nsNativeAppSupportWin
- NS_INTERFACE_MAP_BEGIN(nsNativeAppSupportWin)
- NS_INTERFACE_MAP_ENTRY(nsIObserver)
- NS_INTERFACE_MAP_END_INHERITING(nsNativeAppSupportBase)
- NS_IMPL_ADDREF_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
- NS_IMPL_RELEASE_INHERITED(nsNativeAppSupportWin, nsNativeAppSupportBase)
- void
- UseParentConsole()
- {
- // Try to attach console to the parent process.
- // It will succeed when the parent process is a command line,
- // so that stdio will be displayed in it.
- if (AttachConsole(ATTACH_PARENT_PROCESS)) {
- // Change std handles to refer to new console handles.
- // Before doing so, ensure that stdout/stderr haven't been
- // redirected to a valid file.
- // The return value for _fileno(<a std handle>) for GUI apps was changed over.
- // Until VC7, it was -1. Starting from VC8, it was changed to -2.
- // http://msdn.microsoft.com/en-us/library/zs6wbdhx%28v=vs.80%29.aspx
- // Starting from VC11, the return value was cahnged to 0 for stdin,
- // 1 for stdout, 2 for stdout. Accroding to Microsoft, this is a bug
- // which will be fixed in VC14.
- // https://connect.microsoft.com/VisualStudio/feedback/details/785119/
- // Although the document does not make it explicit, it looks like
- // the return value from _get_osfhandle(_fileno(<a std handle>)) also
- // changed to -2 and VC11 and 12 do not have a bug about _get_osfhandle().
- // We support VC10 or later, so it's sufficient to compare the return
- // value with -2.
- if (_fileno(stdout) == -2 ||
- _get_osfhandle(fileno(stdout)) == -2)
- freopen("CONOUT$", "w", stdout);
- // Merge stderr into CONOUT$ since there isn't any `CONERR$`.
- // http://msdn.microsoft.com/en-us/library/windows/desktop/ms683231%28v=vs.85%29.aspx
- if (_fileno(stderr) == -2 ||
- _get_osfhandle(fileno(stderr)) == -2)
- freopen("CONOUT$", "w", stderr);
- if (_fileno(stdin) == -2 || _get_osfhandle(fileno(stdin)) == -2)
- freopen("CONIN$", "r", stdin);
- }
- }
- void
- nsNativeAppSupportWin::CheckConsole() {
- for ( int i = 1; i < gArgc; i++ ) {
- if ( strcmp( "-console", gArgv[i] ) == 0 ||
- strcmp( "--console", gArgv[i] ) == 0 ||
- strcmp( "/console", gArgv[i] ) == 0 ) {
- // Users wants to make sure we have a console.
- // Try to allocate one.
- BOOL rc = ::AllocConsole();
- if ( rc ) {
- // Console allocated. Fix it up so that output works in
- // all cases. See http://support.microsoft.com/support/kb/articles/q105/3/05.asp.
- // stdout
- int hCrt = ::_open_osfhandle( (intptr_t)GetStdHandle( STD_OUTPUT_HANDLE ),
- _O_TEXT );
- if ( hCrt != -1 ) {
- FILE *hf = ::_fdopen( hCrt, "w" );
- if ( hf ) {
- *stdout = *hf;
- #ifdef DEBUG
- ::fprintf( stdout, "stdout directed to dynamic console\n" );
- #endif
- }
- }
- // stderr
- hCrt = ::_open_osfhandle( (intptr_t)::GetStdHandle( STD_ERROR_HANDLE ),
- _O_TEXT );
- if ( hCrt != -1 ) {
- FILE *hf = ::_fdopen( hCrt, "w" );
- if ( hf ) {
- *stderr = *hf;
- #ifdef DEBUG
- ::fprintf( stderr, "stderr directed to dynamic console\n" );
- #endif
- }
- }
- // stdin?
- /* Don't bother for now.
- hCrt = ::_open_osfhandle( (long)::GetStdHandle( STD_INPUT_HANDLE ),
- _O_TEXT );
- if ( hCrt != -1 ) {
- FILE *hf = ::_fdopen( hCrt, "r" );
- if ( hf ) {
- *stdin = *hf;
- }
- }
- */
- } else {
- // Failed. Probably because there already is one.
- // There's little we can do, in any case.
- }
- // Remove the console argument from the command line.
- do {
- gArgv[i] = gArgv[i + 1];
- ++i;
- } while (gArgv[i]);
- --gArgc;
- } else if ( strcmp( "-attach-console", gArgv[i] ) == 0
- ||
- strcmp( "/attach-console", gArgv[i] ) == 0 ) {
- UseParentConsole();
- }
- }
- return;
- }
- // Create and return an instance of class nsNativeAppSupportWin.
- nsresult
- NS_CreateNativeAppSupport( nsINativeAppSupport **aResult ) {
- nsNativeAppSupportWin *pNative = new nsNativeAppSupportWin;
- if (!pNative) return NS_ERROR_OUT_OF_MEMORY;
- // Check for dynamic console creation request.
- pNative->CheckConsole();
- *aResult = pNative;
- NS_ADDREF( *aResult );
- return NS_OK;
- }
- // Constants
- #define MOZ_DDE_APPLICATION "Mozilla"
- #define MOZ_MUTEX_NAMESPACE L"Local\\"
- #define MOZ_STARTUP_MUTEX_NAME L"StartupMutex"
- #define MOZ_DDE_START_TIMEOUT 30000
- #define MOZ_DDE_STOP_TIMEOUT 15000
- #define MOZ_DDE_EXEC_TIMEOUT 15000
- // The array entries must match the enum ordering!
- const char * const topicNames[] = { "WWW_OpenURL",
- "WWW_Activate",
- "WWW_CancelProgress",
- "WWW_Version",
- "WWW_RegisterViewer",
- "WWW_UnRegisterViewer",
- "WWW_GetWindowInfo" };
- // Static member definitions.
- int nsNativeAppSupportWin::mConversations = 0;
- HSZ nsNativeAppSupportWin::mApplication = 0;
- HSZ nsNativeAppSupportWin::mTopics[nsNativeAppSupportWin::topicCount] = { 0 };
- DWORD nsNativeAppSupportWin::mInstance = 0;
- bool nsNativeAppSupportWin::mCanHandleRequests = false;
- char16_t nsNativeAppSupportWin::mMutexName[ 128 ] = { 0 };
- // Message window encapsulation.
- struct MessageWindow {
- // ctor/dtor are simplistic
- MessageWindow() {
- // Try to find window.
- mHandle = ::FindWindowW( className(), 0 );
- }
- // Act like an HWND.
- operator HWND() {
- return mHandle;
- }
- // Class name: appName + "MessageWindow"
- static const wchar_t *className() {
- static wchar_t classNameBuffer[128];
- static wchar_t *mClassName = 0;
- if ( !mClassName ) {
- ::_snwprintf(classNameBuffer,
- 128, // size of classNameBuffer in PRUnichars
- L"%s%s",
- static_cast<const wchar_t*>(NS_ConvertUTF8toUTF16(gAppData->remotingName).get()),
- L"MessageWindow" );
- mClassName = classNameBuffer;
- }
- return mClassName;
- }
- // Create: Register class and create window.
- NS_IMETHOD Create() {
- WNDCLASSW classStruct = { 0, // style
- &MessageWindow::WindowProc, // lpfnWndProc
- 0, // cbClsExtra
- 0, // cbWndExtra
- 0, // hInstance
- 0, // hIcon
- 0, // hCursor
- 0, // hbrBackground
- 0, // lpszMenuName
- className() }; // lpszClassName
- // Register the window class.
- NS_ENSURE_TRUE( ::RegisterClassW( &classStruct ), NS_ERROR_FAILURE );
- // Create the window.
- NS_ENSURE_TRUE( ( mHandle = ::CreateWindowW(className(),
- 0, // title
- WS_CAPTION, // style
- 0,0,0,0, // x, y, cx, cy
- 0, // parent
- 0, // menu
- 0, // instance
- 0 ) ), // create struct
- NS_ERROR_FAILURE );
- #if MOZ_DEBUG_DDE
- printf( "Message window = 0x%08X\n", (int)mHandle );
- #endif
- return NS_OK;
- }
- // Destory: Get rid of window and reset mHandle.
- NS_IMETHOD Destroy() {
- nsresult retval = NS_OK;
- if ( mHandle ) {
- // DestroyWindow can only destroy windows created from
- // the same thread.
- BOOL desRes = DestroyWindow( mHandle );
- if ( FALSE != desRes ) {
- mHandle = nullptr;
- }
- else {
- retval = NS_ERROR_FAILURE;
- }
- }
- return retval;
- }
- // SendRequest: Pass the command line via WM_COPYDATA to message window.
- NS_IMETHOD SendRequest() {
- WCHAR *cmd = ::GetCommandLineW();
- WCHAR cwd[MAX_PATH];
- _wgetcwd(cwd, MAX_PATH);
- // Construct a narrow UTF8 buffer <commandline>\0<workingdir>\0
- NS_ConvertUTF16toUTF8 utf8buffer(cmd);
- utf8buffer.Append('\0');
- 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,
- utf8buffer.Length(),
- (void*) utf8buffer.get()
- };
- // Bring the already running Mozilla process to the foreground.
- // nsWindow will restore the window (if minimized) and raise it.
- ::SetForegroundWindow( mHandle );
- ::SendMessage( mHandle, WM_COPYDATA, 0, (LPARAM)&cds );
- return NS_OK;
- }
- // Window proc.
- static LRESULT CALLBACK WindowProc( HWND msgWindow, UINT msg, WPARAM wp, LPARAM lp ) {
- if ( msg == WM_COPYDATA ) {
- if (!nsNativeAppSupportWin::mCanHandleRequests)
- return FALSE;
- // This is an incoming request.
- COPYDATASTRUCT *cds = (COPYDATASTRUCT*)lp;
- #if MOZ_DEBUG_DDE
- printf( "Incoming request: %s\n", (const char*)cds->lpData );
- #endif
- nsCOMPtr<nsIFile> workingDir;
- if (1 >= cds->dwData) {
- char* wdpath = (char*) cds->lpData;
- // skip the command line, and get the working dir of the
- // other process, which is after the first null char
- while (*wdpath)
- ++wdpath;
- ++wdpath;
- #ifdef MOZ_DEBUG_DDE
- printf( "Working dir: %s\n", wdpath);
- #endif
- NS_NewLocalFile(NS_ConvertUTF8toUTF16(wdpath),
- false,
- getter_AddRefs(workingDir));
- }
- (void)nsNativeAppSupportWin::HandleCommandLine((char*)cds->lpData, workingDir, nsICommandLine::STATE_REMOTE_AUTO);
- // Get current window and return its window handle.
- nsCOMPtr<mozIDOMWindowProxy> win;
- GetMostRecentWindow( 0, getter_AddRefs( win ) );
- return win ? (LRESULT)hwndForDOMWindow( win ) : 0;
- }
- return DefWindowProc( msgWindow, msg, wp, lp );
- }
- private:
- HWND mHandle;
- }; // struct MessageWindow
- /* Start: Tries to find the "message window" to determine if it
- * exists. If so, then Mozilla is already running. In that
- * case, we use the handle to the "message" window and send
- * a request corresponding to this process's command line
- * options.
- *
- * If not, then this is the first instance of Mozilla. In
- * that case, we create and set up the message window.
- *
- * The checking for existence of the message window must
- * be protected by use of a mutex semaphore.
- */
- NS_IMETHODIMP
- nsNativeAppSupportWin::Start( bool *aResult ) {
- NS_ENSURE_ARG( aResult );
- NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
- NS_ENSURE_STATE( gAppData );
- if (getenv("MOZ_NO_REMOTE"))
- {
- *aResult = true;
- return NS_OK;
- }
- nsresult rv = NS_ERROR_FAILURE;
- *aResult = false;
- // Grab mutex first.
- // Build mutex name from app name.
- ::_snwprintf(reinterpret_cast<wchar_t*>(mMutexName),
- sizeof mMutexName / sizeof(char16_t), L"%s%s%s",
- MOZ_MUTEX_NAMESPACE,
- static_cast<const wchar_t*>(NS_ConvertUTF8toUTF16(gAppData->name).get()),
- MOZ_STARTUP_MUTEX_NAME );
- Win32Mutex startupLock = Win32Mutex( mMutexName );
- NS_ENSURE_TRUE( startupLock.Lock( MOZ_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.
- 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 = true;
- }
- }
- startupLock.Unlock();
- return rv;
- }
- bool
- nsNativeAppSupportWin::InitTopicStrings() {
- for ( int i = 0; i < topicCount; i++ ) {
- if ( !( mTopics[ i ] = DdeCreateStringHandleA( mInstance, const_cast<char *>(topicNames[ i ]), CP_WINANSI ) ) ) {
- return false;
- }
- }
- return true;
- }
- int
- nsNativeAppSupportWin::FindTopic( HSZ topic ) {
- for ( int i = 0; i < topicCount; i++ ) {
- if ( DdeCmpStringHandles( topic, mTopics[i] ) == 0 ) {
- return i;
- }
- }
- return -1;
- }
- // Start DDE server.
- //
- // This used to be the Start() method when we were using DDE as the
- // primary IPC mechanism between secondary Mozilla processes and the
- // initial "server" process.
- //
- // Now, it simply initializes the DDE server. The caller must check
- // that this process is to be the server, and, must acquire the DDE
- // startup mutex semaphore prior to calling this routine. See ::Start(),
- // above.
- NS_IMETHODIMP
- nsNativeAppSupportWin::StartDDE() {
- NS_ENSURE_TRUE( mInstance == 0, NS_ERROR_NOT_INITIALIZED );
- // Initialize DDE.
- NS_ENSURE_TRUE( DMLERR_NO_ERROR == DdeInitialize( &mInstance,
- nsNativeAppSupportWin::HandleDDENotification,
- APPCLASS_STANDARD,
- 0 ),
- NS_ERROR_FAILURE );
- // Allocate DDE strings.
- NS_ENSURE_TRUE( ( mApplication = DdeCreateStringHandleA( mInstance, (char*) gAppData->name, CP_WINANSI ) ) && InitTopicStrings(),
- NS_ERROR_FAILURE );
- // Next step is to register a DDE service.
- NS_ENSURE_TRUE( DdeNameService( mInstance, mApplication, 0, DNS_REGISTER ), NS_ERROR_FAILURE );
- #if MOZ_DEBUG_DDE
- printf( "DDE server started\n" );
- #endif
- return NS_OK;
- }
- // If no DDE conversations are pending, terminate DDE.
- NS_IMETHODIMP
- nsNativeAppSupportWin::Stop( bool *aResult ) {
- NS_ENSURE_ARG( aResult );
- NS_ENSURE_TRUE( mInstance, NS_ERROR_NOT_INITIALIZED );
- nsresult rv = NS_OK;
- *aResult = true;
- Win32Mutex ddeLock( mMutexName );
- if ( ddeLock.Lock( MOZ_DDE_STOP_TIMEOUT ) ) {
- if ( mConversations == 0 ) {
- this->Quit();
- } else {
- *aResult = false;
- }
- ddeLock.Unlock();
- }
- else {
- // No DDE application name specified, but that's OK. Just
- // forge ahead.
- *aResult = true;
- }
- return rv;
- }
- NS_IMETHODIMP
- nsNativeAppSupportWin::Observe(nsISupports* aSubject, const char* aTopic,
- const char16_t* aData)
- {
- if (strcmp(aTopic, "quit-application") == 0) {
- Quit();
- } else {
- NS_ERROR("Unexpected observer topic.");
- }
- return NS_OK;
- }
- // Terminate DDE regardless.
- NS_IMETHODIMP
- nsNativeAppSupportWin::Quit() {
- // If another process wants to look for the message window, they need
- // to wait to hold the lock, in which case they will not find the
- // window as we will destroy ours under our lock.
- // When the mutex goes off the stack, it is unlocked via destructor.
- Win32Mutex mutexLock(mMutexName);
- NS_ENSURE_TRUE(mutexLock.Lock(MOZ_DDE_START_TIMEOUT), NS_ERROR_FAILURE);
- // If we've got a message window to receive IPC or new window requests,
- // get rid of it as we are shutting down.
- // Note: Destroy calls DestroyWindow, which will only work on a window
- // created by the same thread.
- MessageWindow mw;
- mw.Destroy();
- if ( mInstance ) {
- // Unregister application name.
- DdeNameService( mInstance, mApplication, 0, DNS_UNREGISTER );
- // Clean up strings.
- if ( mApplication ) {
- DdeFreeStringHandle( mInstance, mApplication );
- mApplication = 0;
- }
- for ( int i = 0; i < topicCount; i++ ) {
- if ( mTopics[i] ) {
- DdeFreeStringHandle( mInstance, mTopics[i] );
- mTopics[i] = 0;
- }
- }
- DdeUninitialize( mInstance );
- mInstance = 0;
- #if MOZ_DEBUG_DDE
- printf( "DDE server stopped\n" );
- #endif
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsNativeAppSupportWin::Enable()
- {
- mCanHandleRequests = true;
- nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
- if (obs) {
- obs->AddObserver(this, "quit-application", false);
- } else {
- NS_ERROR("No observer service?");
- }
- return NS_OK;
- }
- #if MOZ_DEBUG_DDE
- // Macro to generate case statement for a given XTYP value.
- #define XTYP_CASE(t) \
- case t: result = #t; break
- static nsCString uTypeDesc( UINT uType ) {
- nsCString result;
- switch ( uType ) {
- XTYP_CASE(XTYP_ADVSTART);
- XTYP_CASE(XTYP_CONNECT);
- XTYP_CASE(XTYP_ADVREQ);
- XTYP_CASE(XTYP_REQUEST);
- XTYP_CASE(XTYP_WILDCONNECT);
- XTYP_CASE(XTYP_ADVDATA);
- XTYP_CASE(XTYP_EXECUTE);
- XTYP_CASE(XTYP_POKE);
- XTYP_CASE(XTYP_ADVSTOP);
- XTYP_CASE(XTYP_CONNECT_CONFIRM);
- XTYP_CASE(XTYP_DISCONNECT);
- XTYP_CASE(XTYP_ERROR);
- XTYP_CASE(XTYP_MONITOR);
- XTYP_CASE(XTYP_REGISTER);
- XTYP_CASE(XTYP_XACT_COMPLETE);
- XTYP_CASE(XTYP_UNREGISTER);
- default: result = "XTYP_?????";
- }
- return result;
- }
- static nsCString hszValue( DWORD instance, HSZ hsz ) {
- // Extract string from HSZ.
- nsCString result("[");
- DWORD len = DdeQueryString( instance, hsz, nullptr, nullptr, CP_WINANSI );
- if ( len ) {
- char buffer[ 256 ];
- DdeQueryString( instance, hsz, buffer, sizeof buffer, CP_WINANSI );
- result += buffer;
- }
- result += "]";
- return result;
- }
- #else
- // These are purely a safety measure to avoid the infamous "won't
- // build non-debug" type Tinderbox flames.
- static nsCString uTypeDesc( UINT ) {
- return nsCString( "?" );
- }
- static nsCString hszValue( DWORD, HSZ ) {
- return nsCString( "?" );
- }
- #endif
- // Utility function to escape double-quotes within a string.
- static void escapeQuotes( nsAString &aString ) {
- int32_t offset = -1;
- while( 1 ) {
- // Find next '"'.
- offset = aString.FindChar( '"', ++offset );
- if ( offset == kNotFound ) {
- // No more quotes, exit.
- break;
- } else {
- // Insert back-slash ahead of the '"'.
- aString.Insert( char16_t('\\'), offset );
- // Increment offset because we just inserted a slash
- offset++;
- }
- }
- return;
- }
- HDDEDATA CALLBACK
- nsNativeAppSupportWin::HandleDDENotification( UINT uType, // transaction type
- UINT uFmt, // clipboard data format
- HCONV hconv, // handle to the conversation
- HSZ hsz1, // handle to a string
- HSZ hsz2, // handle to a string
- HDDEDATA hdata, // handle to a global memory object
- ULONG_PTR dwData1, // transaction-specific data
- ULONG_PTR dwData2 ) { // transaction-specific data
- if (!mCanHandleRequests)
- return 0;
- #if MOZ_DEBUG_DDE
- printf( "DDE: uType =%s\n", uTypeDesc( uType ).get() );
- printf( " uFmt =%u\n", (unsigned)uFmt );
- printf( " hconv =%08x\n", (int)hconv );
- printf( " hsz1 =%08x:%s\n", (int)hsz1, hszValue( mInstance, hsz1 ).get() );
- printf( " hsz2 =%08x:%s\n", (int)hsz2, hszValue( mInstance, hsz2 ).get() );
- printf( " hdata =%08x\n", (int)hdata );
- printf( " dwData1=%08x\n", (int)dwData1 );
- printf( " dwData2=%08x\n", (int)dwData2 );
- #endif
- HDDEDATA result = 0;
- if ( uType & XCLASS_BOOL ) {
- switch ( uType ) {
- case XTYP_CONNECT:
- // Make sure its for our service/topic.
- if ( FindTopic( hsz1 ) != -1 ) {
- // We support this connection.
- result = (HDDEDATA)1;
- }
- break;
- case XTYP_CONNECT_CONFIRM:
- // We don't care about the conversation handle, at this point.
- result = (HDDEDATA)1;
- break;
- }
- } else if ( uType & XCLASS_DATA ) {
- if ( uType == XTYP_REQUEST ) {
- switch ( FindTopic( hsz1 ) ) {
- case topicOpenURL: {
- // Open a given URL...
- // Get the URL from the first argument in the command.
- nsAutoString url;
- ParseDDEArg(hsz2, 0, url);
- // Read the 3rd argument in the command to determine if a
- // new window is to be used.
- nsAutoString windowID;
- ParseDDEArg(hsz2, 2, windowID);
- // "" means to open the URL in a new window.
- if ( windowID.IsEmpty() ) {
- url.Insert(NS_LITERAL_STRING("mozilla -new-window "), 0);
- }
- else {
- url.Insert(NS_LITERAL_STRING("mozilla -url "), 0);
- }
- #if MOZ_DEBUG_DDE
- printf( "Handling dde XTYP_REQUEST request: [%s]...\n", NS_ConvertUTF16toUTF8(url).get() );
- #endif
- // Now handle it.
- HandleCommandLine(NS_ConvertUTF16toUTF8(url).get(), nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
- // Return pseudo window ID.
- result = CreateDDEData( 1 );
- break;
- }
- case topicGetWindowInfo: {
- // This topic has to get the current URL, get the current
- // page title and then format the output into the DDE
- // return string. The return value is "URL","Page Title",
- // "Window ID" however the window ID is not used for this
- // command, therefore it is returned as a null string
- // This isn't really a loop. We just use "break"
- // statements to bypass the remaining steps when
- // something goes wrong.
- do {
- // Get most recently used Nav window.
- nsCOMPtr<mozIDOMWindowProxy> navWin;
- GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(),
- getter_AddRefs( navWin ) );
- nsCOMPtr<nsPIDOMWindowOuter> piNavWin = do_QueryInterface(navWin);
- if ( !piNavWin ) {
- // There is not a window open
- break;
- }
- // Get content window.
- nsCOMPtr<nsPIDOMWindowOuter> internalContent = nsGlobalWindow::Cast(piNavWin)->GetContent();
- if ( !internalContent ) {
- break;
- }
- // Get location.
- nsCOMPtr<nsIDOMLocation> location = internalContent->GetLocation();
- if ( !location ) {
- break;
- }
- // Get href for URL.
- nsAutoString url;
- if ( NS_FAILED( location->GetHref( url ) ) ) {
- break;
- }
- // Escape any double-quotes.
- escapeQuotes( url );
- // Now for the title...
- // Get the base window from the doc shell...
- nsCOMPtr<nsIBaseWindow> baseWindow =
- do_QueryInterface( internalContent->GetDocShell() );
- if ( !baseWindow ) {
- break;
- }
- // And from the base window we can get the title.
- nsXPIDLString title;
- if(!baseWindow) {
- break;
- }
- baseWindow->GetTitle(getter_Copies(title));
- // Escape any double-quotes in the title.
- escapeQuotes( title );
- // Use a string buffer for the output data, first
- // save a quote.
- nsAutoCString outpt( NS_LITERAL_CSTRING("\"") );
- // Now copy the URL converting the Unicode string
- // to a single-byte ASCII string
- nsAutoCString tmpNativeStr;
- NS_CopyUnicodeToNative( url, tmpNativeStr );
- outpt.Append( tmpNativeStr );
- // Add the "," used to separate the URL and the page
- // title
- outpt.Append( NS_LITERAL_CSTRING("\",\"") );
- // Now copy the current page title to the return string
- NS_CopyUnicodeToNative( title, tmpNativeStr );
- outpt.Append( tmpNativeStr );
- // Fill out the return string with the remainin ",""
- outpt.Append( NS_LITERAL_CSTRING( "\",\"\"" ));
- // Create a DDE handle to a char string for the data
- // being returned, this copies and creates a "shared"
- // copy of the DDE response until the calling APP
- // reads it and says it can be freed.
- result = CreateDDEData( (LPBYTE)(const char*)outpt.get(),
- outpt.Length() + 1 );
- #if MOZ_DEBUG_DDE
- printf( "WWW_GetWindowInfo->%s\n", outpt.get() );
- #endif
- } while ( false );
- break;
- }
- case topicActivate: {
- // Activate a Nav window...
- nsAutoString windowID;
- ParseDDEArg(hsz2, 0, windowID);
- // 4294967295 is decimal for 0xFFFFFFFF which is also a
- // correct value to do that Activate last window stuff
- if ( windowID.EqualsLiteral( "-1" ) ||
- windowID.EqualsLiteral( "4294967295" ) ) {
- // We only support activating the most recent window (or a new one).
- ActivateLastWindow();
- // Return pseudo window ID.
- result = CreateDDEData( 1 );
- }
- break;
- }
- case topicVersion: {
- // Return version. We're restarting at 1.0!
- DWORD version = 1 << 16; // "1.0"
- result = CreateDDEData( version );
- break;
- }
- case topicRegisterViewer: {
- // Register new viewer (not implemented).
- result = CreateDDEData( false );
- break;
- }
- case topicUnRegisterViewer: {
- // Unregister new viewer (not implemented).
- result = CreateDDEData( false );
- break;
- }
- default:
- break;
- }
- } else if ( uType & XTYP_POKE ) {
- switch ( FindTopic( hsz1 ) ) {
- case topicCancelProgress: {
- // "Handle" progress cancel (actually, pretty much ignored).
- result = (HDDEDATA)DDE_FACK;
- break;
- }
- default:
- break;
- }
- }
- } else if ( uType & XCLASS_FLAGS ) {
- if ( uType == XTYP_EXECUTE ) {
- // Prove that we received the request.
- DWORD bytes;
- LPBYTE request = DdeAccessData( hdata, &bytes );
- #if MOZ_DEBUG_DDE
- printf( "Handling dde request: [%s]...\n", (char*)request );
- #endif
- nsAutoString url;
- ParseDDEArg((const WCHAR*) request, 0, url);
- // Read the 3rd argument in the command to determine if a
- // new window is to be used.
- nsAutoString windowID;
- ParseDDEArg((const WCHAR*) request, 2, windowID);
- // "" means to open the URL in a new window.
- if ( windowID.IsEmpty() ) {
- url.Insert(NS_LITERAL_STRING("mozilla -new-window "), 0);
- }
- else {
- url.Insert(NS_LITERAL_STRING("mozilla -url "), 0);
- }
- #if MOZ_DEBUG_DDE
- printf( "Handling dde XTYP_REQUEST request: [%s]...\n", NS_ConvertUTF16toUTF8(url).get() );
- #endif
- // Now handle it.
- HandleCommandLine(NS_ConvertUTF16toUTF8(url).get(), nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
- // Release the data.
- DdeUnaccessData( hdata );
- result = (HDDEDATA)DDE_FACK;
- } else {
- result = (HDDEDATA)DDE_FNOTPROCESSED;
- }
- } else if ( uType & XCLASS_NOTIFICATION ) {
- }
- #if MOZ_DEBUG_DDE
- printf( "DDE result=%d (0x%08X)\n", (int)result, (int)result );
- #endif
- return result;
- }
- // Utility function to advance to end of quoted string.
- // p+offset must point to the comma preceding the arg on entry.
- // On return, p+result points to the closing '"' (or end of the string
- // if the closing '"' is missing) if the arg is quoted. If the arg
- // is not quoted, then p+result will point to the first character
- // of the arg.
- static int32_t advanceToEndOfQuotedArg( const WCHAR *p, int32_t offset, int32_t len ) {
- // Check whether the current arg is quoted.
- if ( p[++offset] == '"' ) {
- // Advance past the closing quote.
- while ( offset < len && p[++offset] != '"' ) {
- // If the current character is a backslash, then the
- // next character can't be a *real* '"', so skip it.
- if ( p[offset] == '\\' ) {
- offset++;
- }
- }
- }
- return offset;
- }
- void nsNativeAppSupportWin::ParseDDEArg( const WCHAR* args, int index, nsString& aString) {
- if ( args ) {
- nsDependentString temp(args);
- // offset points to the comma preceding the desired arg.
- int32_t offset = -1;
- // Skip commas till we get to the arg we want.
- while( index-- ) {
- // If this arg is quoted, then go to closing quote.
- offset = advanceToEndOfQuotedArg( args, offset, temp.Length());
- // Find next comma.
- offset = temp.FindChar( ',', offset );
- if ( offset == kNotFound ) {
- // No more commas, give up.
- aString = args;
- return;
- }
- }
- // The desired argument starts just past the preceding comma,
- // which offset points to, and extends until the following
- // comma (or the end of the string).
- //
- // Since the argument might be enclosed in quotes, we need to
- // deal with that before searching for the terminating comma.
- // We advance offset so it ends up pointing to the start of
- // the argument we want.
- int32_t end = advanceToEndOfQuotedArg( args, offset++, temp.Length() );
- // Find next comma (or end of string).
- end = temp.FindChar( ',', end );
- if ( end == kNotFound ) {
- // Arg is the rest of the string.
- end = temp.Length();
- }
- // Extract result.
- aString.Assign( args + offset, end - offset );
- }
- return;
- }
- // Utility to parse out argument from a DDE item string.
- void nsNativeAppSupportWin::ParseDDEArg( HSZ args, int index, nsString& aString) {
- DWORD argLen = DdeQueryStringW( mInstance, args, nullptr, 0, CP_WINUNICODE );
- // there wasn't any string, so return empty string
- if ( !argLen ) return;
- nsAutoString temp;
- // Ensure result's buffer is sufficiently big.
- temp.SetLength( argLen );
- // Now get the string contents.
- DdeQueryString( mInstance, args, reinterpret_cast<wchar_t*>(temp.BeginWriting()), temp.Length(), CP_WINUNICODE );
- // Parse out the given arg.
- ParseDDEArg(temp.get(), index, aString);
- return;
- }
- HDDEDATA nsNativeAppSupportWin::CreateDDEData( DWORD value ) {
- return CreateDDEData( (LPBYTE)&value, sizeof value );
- }
- HDDEDATA nsNativeAppSupportWin::CreateDDEData( LPBYTE value, DWORD len ) {
- HDDEDATA result = DdeCreateDataHandle( mInstance,
- value,
- len,
- 0,
- mApplication,
- CF_TEXT,
- 0 );
- return result;
- }
- void nsNativeAppSupportWin::ActivateLastWindow() {
- nsCOMPtr<mozIDOMWindowProxy> navWin;
- GetMostRecentWindow( u"navigator:browser", getter_AddRefs( navWin ) );
- if ( navWin ) {
- // Activate that window.
- activateWindow( navWin );
- } else {
- // Need to create a Navigator window, then.
- OpenBrowserWindow();
- }
- }
- void
- nsNativeAppSupportWin::HandleCommandLine(const char* aCmdLineString,
- nsIFile* aWorkingDir,
- uint32_t aState)
- {
- nsresult rv;
- int justCounting = 1;
- char **argv = 0;
- // Flags, etc.
- int init = 1;
- int between, quoted, bSlashCount;
- int argc;
- const char *p;
- nsAutoCString arg;
- nsCOMPtr<nsICommandLineRunner> cmdLine
- (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
- if (!cmdLine) {
- NS_ERROR("Couldn't create command line!");
- return;
- }
- // Parse command line args according to MS spec
- // (see "Parsing C++ Command-Line Arguments" at
- // http://msdn.microsoft.com/library/devprods/vs6/visualc/vclang/_pluslang_parsing_c.2b2b_.command.2d.line_arguments.htm).
- // We loop if we've not finished the second pass through.
- while ( 1 ) {
- // Initialize if required.
- if ( init ) {
- p = aCmdLineString;
- between = 1;
- argc = quoted = bSlashCount = 0;
- init = 0;
- }
- if ( between ) {
- // We are traversing whitespace between args.
- // Check for start of next arg.
- if ( *p != 0 && !isspace( *p ) ) {
- // Start of another arg.
- between = 0;
- arg = "";
- switch ( *p ) {
- case '\\':
- // Count the backslash.
- bSlashCount = 1;
- break;
- case '"':
- // Remember we're inside quotes.
- quoted = 1;
- break;
- default:
- // Add character to arg.
- arg += *p;
- break;
- }
- } else {
- // Another space between args, ignore it.
- }
- } else {
- // We are processing the contents of an argument.
- // Check for whitespace or end.
- if ( *p == 0 || ( !quoted && isspace( *p ) ) ) {
- // Process pending backslashes (interpret them
- // literally since they're not followed by a ").
- while( bSlashCount ) {
- arg += '\\';
- bSlashCount--;
- }
- // End current arg.
- if ( !justCounting ) {
- argv[argc] = new char[ arg.Length() + 1 ];
- strcpy( argv[argc], arg.get() );
- }
- argc++;
- // We're now between args.
- between = 1;
- } else {
- // Still inside argument, process the character.
- switch ( *p ) {
- case '"':
- // First, digest preceding backslashes (if any).
- while ( bSlashCount > 1 ) {
- // Put one backsplash in arg for each pair.
- arg += '\\';
- bSlashCount -= 2;
- }
- if ( bSlashCount ) {
- // Quote is literal.
- arg += '"';
- bSlashCount = 0;
- } else {
- // Quote starts or ends a quoted section.
- if ( quoted ) {
- // Check for special case of consecutive double
- // quotes inside a quoted section.
- if ( *(p+1) == '"' ) {
- // This implies a literal double-quote. Fake that
- // out by causing next double-quote to look as
- // if it was preceded by a backslash.
- bSlashCount = 1;
- } else {
- quoted = 0;
- }
- } else {
- quoted = 1;
- }
- }
- break;
- case '\\':
- // Add to count.
- bSlashCount++;
- break;
- default:
- // Accept any preceding backslashes literally.
- while ( bSlashCount ) {
- arg += '\\';
- bSlashCount--;
- }
- // Just add next char to the current arg.
- arg += *p;
- break;
- }
- }
- }
- // Check for end of input.
- if ( *p ) {
- // Go to next character.
- p++;
- } else {
- // If on first pass, go on to second.
- if ( justCounting ) {
- // Allocate argv array.
- argv = new char*[ argc ];
- // Start second pass
- justCounting = 0;
- init = 1;
- } else {
- // Quit.
- break;
- }
- }
- }
- rv = cmdLine->Init(argc, argv, aWorkingDir, aState);
- // Cleanup.
- while ( argc ) {
- delete [] argv[ --argc ];
- }
- delete [] argv;
- if (NS_FAILED(rv)) {
- NS_ERROR("Error initializing command line.");
- return;
- }
- cmdLine->Run();
- }
- nsresult
- nsNativeAppSupportWin::OpenWindow( const char*urlstr, const char *args ) {
- nsresult rv = NS_ERROR_FAILURE;
- nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));
- nsCOMPtr<nsISupportsCString> sarg(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
- if (sarg)
- sarg->SetData(nsDependentCString(args));
- if (wwatch && sarg) {
- nsCOMPtr<mozIDOMWindowProxy> newWindow;
- rv = wwatch->OpenWindow(0, urlstr, "_blank", "chrome,dialog=no,all",
- sarg, getter_AddRefs(newWindow));
- #if MOZ_DEBUG_DDE
- } else {
- printf("Get WindowWatcher (or create string) failed\n");
- #endif
- }
- return rv;
- }
- HWND hwndForDOMWindow(mozIDOMWindowProxy *window ) {
- if ( !window ) {
- return 0;
- }
- nsCOMPtr<nsPIDOMWindowOuter > pidomwindow = nsPIDOMWindowOuter::From(window);
- nsCOMPtr<nsIBaseWindow> ppBaseWindow =
- do_QueryInterface( pidomwindow->GetDocShell() );
- if ( !ppBaseWindow ) {
- return 0;
- }
- nsCOMPtr<nsIWidget> ppWidget;
- ppBaseWindow->GetMainWidget( getter_AddRefs( ppWidget ) );
- return (HWND)( ppWidget->GetNativeData( NS_NATIVE_WIDGET ) );
- }
- nsresult
- nsNativeAppSupportWin::OpenBrowserWindow()
- {
- nsresult rv = NS_OK;
- // Open the argument URL in the most recently used Navigator window.
- // If there is no Nav window, open a new one.
- // If at all possible, hand the request off to the most recent
- // browser window.
- nsCOMPtr<mozIDOMWindowProxy> navWin;
- GetMostRecentWindow( NS_LITERAL_STRING( "navigator:browser" ).get(), getter_AddRefs( navWin ) );
- // This isn't really a loop. We just use "break" statements to fall
- // out to the OpenWindow call when things go awry.
- do {
- // If caller requires a new window, then don't use an existing one.
- if ( !navWin ) {
- // Have to open a new one.
- break;
- }
- nsCOMPtr<nsIBrowserDOMWindow> bwin;
- { // scope a bunch of temporary cruft used to generate bwin
- nsCOMPtr<nsIWebNavigation> navNav( do_GetInterface( navWin ) );
- nsCOMPtr<nsIDocShellTreeItem> navItem( do_QueryInterface( navNav ) );
- if ( navItem ) {
- nsCOMPtr<nsIDocShellTreeItem> rootItem;
- navItem->GetRootTreeItem( getter_AddRefs( rootItem ) );
- nsCOMPtr<nsPIDOMWindowOuter> rootWin =
- rootItem ? rootItem->GetWindow() : nullptr;
- nsCOMPtr<nsIDOMChromeWindow> chromeWin(do_QueryInterface(rootWin));
- if ( chromeWin )
- chromeWin->GetBrowserDOMWindow( getter_AddRefs ( bwin ) );
- }
- }
- if ( bwin ) {
- nsCOMPtr<nsIURI> uri;
- NS_NewURI( getter_AddRefs( uri ), NS_LITERAL_CSTRING("about:blank"), 0, 0 );
- if ( uri ) {
- nsCOMPtr<mozIDOMWindowProxy> container;
- rv = bwin->OpenURI( uri, 0,
- nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
- nsIBrowserDOMWindow::OPEN_EXTERNAL,
- getter_AddRefs( container ) );
- if ( NS_SUCCEEDED( rv ) )
- return NS_OK;
- }
- }
- NS_ERROR("failed to hand off external URL to extant window");
- } while ( false );
- // open a new window if caller requested it or if anything above failed
- char* argv[] = { 0 };
- nsCOMPtr<nsICommandLineRunner> cmdLine
- (do_CreateInstance("@mozilla.org/toolkit/command-line;1"));
- NS_ENSURE_TRUE(cmdLine, NS_ERROR_FAILURE);
- rv = cmdLine->Init(0, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
- NS_ENSURE_SUCCESS(rv, rv);
- return cmdLine->Run();
- }
|