NS_IMPL_THREADSAFE_ISUPPORTS2(ProfileChangeObserver, nsIObserver, nsISupportsWeakReference);
NS_IMPL_THREADSAFE_ISUPPORTS2(ProfileChangeObserver, nsIObserver, nsISupportsWeakReference)
static nsresult ResizeEmbedding(nsIWebBrowserChrome* chrome);// Profile chooser stuffstatic BOOL ChooseNewProfile(BOOL bShowForMultipleProfilesOnly, const char *szDefaultProfile);static LRESULT CALLBACK ChooseProfileDlgProc(HWND, UINT, WPARAM, LPARAM);// Global variablesstatic UINT gDialogCount = 0;static BOOL gProfileSwitch = FALSE;static HINSTANCE ghInstanceResources = NULL;static HINSTANCE ghInstanceApp = NULL;static char gFirstURL[1024];// A list of URLs to populate the URL drop down list withstatic const TCHAR *gDefaultURLs[] = {    _T("http://www.mozilla.org/"),    _T("http://www.netscape.com/"),    _T("http://browsertest.web.aol.com/tests/javascript/javascpt/index.htm"),    _T("http://127.0.0.1/"),    _T("http://www.yahoo.com/"),    _T("http://www.travelocity.com/"),    _T("http://www.disney.com/"),    _T("http://www.go.com/"),    _T("http://www.google.com/"),    _T("http://www.ebay.com/"),    _T("http://www.shockwave.com/"),    _T("http://www.slashdot.org/"),    _T("http://www.quicken.com/"),    _T("http://www.hotmail.com/"),    _T("http://www.cnn.com/"),    _T("http://www.javasoft.com/")};class ProfileChangeObserver : public nsIObserver,                              public nsSupportsWeakReference{public:    ProfileChangeObserver();    NS_DECL_ISUPPORTS    NS_DECL_NSIOBSERVER};int main(int argc, char *argv[]){    printf("You are embedded, man!\n\n");    printf("******************************************************************\n");    printf("*                                                                *\n");    printf("*  IMPORTANT NOTE:                                               *\n");    printf("*                                                                *\n");    printf("*  WinEmbed is not supported!!! Do not raise bugs on it unless   *\n");    printf("*  it is badly broken (e.g. crash on start/exit, build errors)   *\n");    printf("*  or you have the patch to make it better! MFCEmbed is now our  *\n");    printf("*  embedding test application on Win32 and all testing should    *\n");    printf("*  be done on that.                                              *\n");    printf("*                                                                *\n");    printf("******************************************************************\n");    printf("\n\n");        // Sophisticated command-line parsing in action    char *szFirstURL = "http://www.mozilla.org/projects/embedding";    char *szDefaultProfile = nsnull;    int argn;    for (argn = 1; argn < argc; argn++)    {        if (stricmp("-P", argv[argn]) == 0)        {            if (argn + 1 < argc)            {                szDefaultProfile = argv[++argn];            }        }        else        {            szFirstURL = argv[argn];        }    }    strncpy(gFirstURL, szFirstURL, sizeof(gFirstURL) - 1);    ghInstanceApp = GetModuleHandle(NULL);    ghInstanceResources = GetModuleHandle(NULL);    // Initialize global strings    TCHAR szTitle[MAX_LOADSTRING];    LoadString(ghInstanceResources, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);    MyRegisterClass(ghInstanceApp);#ifdef _BUILD_STATIC_BIN    // Initialize XPCOM's module info table    NSGetStaticModuleInfo = app_getModuleInfo;#endif    // Init Embedding APIs    NS_InitEmbedding(nsnull, nsnull);    // Choose the new profile    if (!ChooseNewProfile(TRUE, szDefaultProfile))    {        NS_TermEmbedding();        return 1;    }    WPARAM rv;    {            // Now register an observer to watch for profile changes        nsCOMPtr<nsIObserverService> observerService(do_GetService("@mozilla.org/observer-service;1"));        ProfileChangeObserver *observer = new ProfileChangeObserver;        observer->AddRef();        observerService->AddObserver(NS_STATIC_CAST(nsIObserver *, observer), "profile-approve-change", PR_TRUE);        observerService->AddObserver(NS_STATIC_CAST(nsIObserver *, observer), "profile-change-teardown", PR_TRUE);        observerService->AddObserver(NS_STATIC_CAST(nsIObserver *, observer), "profile-after-change", PR_TRUE);        InitializeWindowCreator();        // Open the initial browser window        OpenWebPage(gFirstURL);        // Main message loop.        // NOTE: We use a fake event and a timeout in order to process idle stuff for        //       Mozilla every 1/10th of a second.        PRBool runCondition = PR_TRUE;        rv = AppCallbacks::RunEventLoop(runCondition);        observer->Release();    }    // Close down Embedding APIs    NS_TermEmbedding();    return rv;}//-----------------------------------------------------------------------------// ProfileChangeObserver//-----------------------------------------------------------------------------NS_IMPL_THREADSAFE_ISUPPORTS2(ProfileChangeObserver, nsIObserver, nsISupportsWeakReference);ProfileChangeObserver::ProfileChangeObserver(){}// ---------------------------------------------------------------------------//  CMfcEmbedApp : nsIObserver// ---------------------------------------------------------------------------NS_IMETHODIMP ProfileChangeObserver::Observe(nsISupports *aSubject, const char *aTopic, const PRUnichar *someData){    nsresult rv = NS_OK;    if (nsCRT::strcmp(aTopic, "profile-approve-change") == 0)    {        // The profile is about to change!        // Ask the user if they want to        int result = ::MessageBox(NULL, "Do you want to close all windows in order to switch the profile?", "Confirm", MB_YESNO | MB_ICONQUESTION);        if (result != IDYES)        {            nsCOMPtr<nsIProfileChangeStatus> status = do_QueryInterface(aSubject);            NS_ENSURE_TRUE(status, NS_ERROR_FAILURE);            status->VetoChange();        }    }    else if (nsCRT::strcmp(aTopic, "profile-change-teardown") == 0)    {        // The profile is changing!        // Prevent WM_QUIT by incrementing the dialog count        gDialogCount++;    }    else if (nsCRT::strcmp(aTopic, "profile-after-change") == 0)    {        // Decrease the dialog count so WM_QUIT can once more happen        gDialogCount--;        if (gDialogCount == 0)        {            // All the dialogs have been torn down so open new page            OpenWebPage(gFirstURL);        }        else        {            // The profile has changed, but dialogs are still being            // torn down. Set this flag so when the last one goes            // it can finish the switch.            gProfileSwitch = TRUE;        }    }    return rv;}/* InitializeWindowCreator creates and hands off an object with a callback   to a window creation function. This is how all new windows are opened,   except any created directly by the embedding app. */nsresult InitializeWindowCreator(){    // create an nsWindowCreator and give it to the WindowWatcher service    WindowCreator *creatorCallback = new WindowCreator();    if (creatorCallback)    {        nsCOMPtr<nsIWindowCreator> windowCreator(NS_STATIC_CAST(nsIWindowCreator *, creatorCallback));        if (windowCreator)        {            nsCOMPtr<nsIWindowWatcher> wwatch(do_GetService(NS_WINDOWWATCHER_CONTRACTID));            if (wwatch)            {                wwatch->SetWindowCreator(windowCreator);                return NS_OK;            }        }    }    return NS_ERROR_FAILURE;}//-----------------------------------------------------------------------------////  FUNCTION: OpenWebPage()////  PURPOSE: Opens a new browser dialog and starts it loading to the//           specified url.//nsresult OpenWebPage(const char *url){    nsresult  rv;    // Create the chrome object. Note that it leaves this function    // with an extra reference so that it can released correctly during    // destruction (via Win32UI::Destroy)    nsCOMPtr<nsIWebBrowserChrome> chrome;    rv = AppCallbacks::CreateBrowserWindow(nsIWebBrowserChrome::CHROME_ALL,           nsnull, getter_AddRefs(chrome));    if (NS_SUCCEEDED(rv))    {        // Start loading a page        nsCOMPtr<nsIWebBrowser> newBrowser;        chrome->GetWebBrowser(getter_AddRefs(newBrowser));        nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(newBrowser));        return webNav->LoadURI(NS_ConvertASCIItoUCS2(url).get(),                               nsIWebNavigation::LOAD_FLAGS_NONE,                               nsnull,                               nsnull,                               nsnull);    }    return rv;}   ////  FUNCTION: GetBrowserFromChrome()////  PURPOSE: Returns the HWND for the webbrowser container associated//           with the specified chrome.//HWND GetBrowserFromChrome(nsIWebBrowserChrome *aChrome){    if (!aChrome)    {        return NULL;    }    nsCOMPtr<nsIEmbeddingSiteWindow> baseWindow = do_QueryInterface(aChrome);    HWND hwnd = NULL;    baseWindow->GetSiteWindow((void **) & hwnd);    return hwnd;}////  FUNCTION: GetBrowserDlgFromChrome()////  PURPOSE: Returns the HWND for the browser dialog associated with//           the specified chrome.//HWND GetBrowserDlgFromChrome(nsIWebBrowserChrome *aChrome){    return GetParent(GetBrowserFromChrome(aChrome));}////  FUNCTION: SaveWebPage()////  PURPOSE: Saves the contents of the web page to a file//void SaveWebPage(nsIWebBrowser *aWebBrowser){    // Use the browser window title as the initial file name    nsCOMPtr<nsIBaseWindow> webBrowserAsWin = do_QueryInterface(aWebBrowser);    nsXPIDLString windowTitle;    webBrowserAsWin->GetTitle(getter_Copies(windowTitle));    nsCString fileName; fileName.AssignWithConversion(windowTitle);    // Sanitize the title of all illegal characters    fileName.CompressWhitespace();     // Remove whitespace from the ends    fileName.StripChars("\\*|:\"><?"); // Strip illegal characters    fileName.ReplaceChar('.', L'_');   // Dots become underscores    fileName.ReplaceChar('/', L'-');   // Forward slashes become hyphens    // Copy filename to a character buffer    char szFile[_MAX_PATH];    memset(szFile, 0, sizeof(szFile));    PL_strncpyz(szFile, fileName.get(), sizeof(szFile) - 1); // XXXldb probably should be just sizeof(szfile)    // Initialize the file save as information structure    OPENFILENAME saveFileNameInfo;    memset(&saveFileNameInfo, 0, sizeof(saveFileNameInfo));    saveFileNameInfo.lStructSize = sizeof(saveFileNameInfo);    saveFileNameInfo.hwndOwner = NULL;    saveFileNameInfo.hInstance = NULL;    saveFileNameInfo.lpstrFilter =        "Web Page, HTML Only (*.htm;*.html)\0*.htm;*.html\0"        "Web Page, Complete (*.htm;*.html)\0*.htm;*.html\0"        "Text File (*.txt)\0*.txt\0";     saveFileNameInfo.lpstrCustomFilter = NULL;     saveFileNameInfo.nMaxCustFilter = NULL;     saveFileNameInfo.nFilterIndex = 1;     saveFileNameInfo.lpstrFile = szFile;     saveFileNameInfo.nMaxFile = sizeof(szFile);     saveFileNameInfo.lpstrFileTitle = NULL;    saveFileNameInfo.nMaxFileTitle = 0;     saveFileNameInfo.lpstrInitialDir = NULL;     saveFileNameInfo.lpstrTitle = NULL;     saveFileNameInfo.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;     saveFileNameInfo.nFileOffset = NULL;     saveFileNameInfo.nFileExtension = NULL;     saveFileNameInfo.lpstrDefExt = "htm";     saveFileNameInfo.lCustData = NULL;     saveFileNameInfo.lpfnHook = NULL;     saveFileNameInfo.lpTemplateName = NULL;     if (GetSaveFileName(&saveFileNameInfo))    {        // Does the user want to save the complete document including        // all frames, images, scripts, stylesheets etc. ?        char *pszDataPath = NULL;        if (saveFileNameInfo.nFilterIndex == 2) // 2nd choice means save everything        {            static char szDataFile[_MAX_PATH];            char szDataPath[_MAX_PATH];            char drive[_MAX_DRIVE];            char dir[_MAX_DIR];            char fname[_MAX_FNAME];            char ext[_MAX_EXT];            _splitpath(szFile, drive, dir, fname, ext);            sprintf(szDataFile, "%s_files", fname);            _makepath(szDataPath, drive, dir, szDataFile, "");            pszDataPath = szDataPath;       }        // Save away        nsCOMPtr<nsIWebBrowserPersist> persist(do_QueryInterface(aWebBrowser));        nsCOMPtr<nsILocalFile> file;        NS_NewNativeLocalFile(nsDependentCString(szFile), TRUE, getter_AddRefs(file));        nsCOMPtr<nsILocalFile> dataPath;        if (pszDataPath)        {            NS_NewNativeLocalFile(nsDependentCString(pszDataPath), TRUE, getter_AddRefs(dataPath));        }        persist->SaveDocument(nsnull, file, dataPath, nsnull, 0, 0);    }}////  FUNCTION: ResizeEmbedding()////  PURPOSE: Resizes the webbrowser window to fit its container.//nsresult ResizeEmbedding(nsIWebBrowserChrome* chrome){    if (!chrome)        return NS_ERROR_FAILURE;        nsCOMPtr<nsIEmbeddingSiteWindow> embeddingSite = do_QueryInterface(chrome);    HWND hWnd;    embeddingSite->GetSiteWindow((void **) & hWnd);        if (!hWnd)        return NS_ERROR_NULL_POINTER;        RECT rect;    GetClientRect(hWnd, &rect);        // Make sure the browser is visible and sized    nsCOMPtr<nsIWebBrowser> webBrowser;    chrome->GetWebBrowser(getter_AddRefs(webBrowser));    nsCOMPtr<nsIBaseWindow> webBrowserAsWin = do_QueryInterface(webBrowser);    if (webBrowserAsWin)    {        webBrowserAsWin->SetPositionAndSize(rect.left,                                    rect.top,                                    rect.right - rect.left,                                    rect.bottom - rect.top,                                   PR_TRUE);        webBrowserAsWin->SetVisibility(PR_TRUE);    }    return NS_OK;}