/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Bill Law * Syd Logan added turbo mode stuff * Joe Elwell * Håkan Waara * Aaron Kaluszka * Blake Ross * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef MAX_BUF #define MAX_BUF 4096 #endif // Implementation utilities. #include "nsIDOMWindowInternal.h" #include "nsIServiceManager.h" #include "nsIPromptService.h" #include "nsIStringBundle.h" #include "nsIAllocator.h" #include "nsICmdLineService.h" #include "nsXPIDLString.h" #include "nsString.h" #include "nsMemory.h" #include "nsNetUtil.h" #include "nsWindowsHooksUtil.cpp" #include "nsWindowsHooks.h" #include #include #include // for set as wallpaper #include "nsIDocument.h" #include "nsIContent.h" #include "nsIDOMElement.h" #include "nsIDOMDocument.h" #include "nsIFrame.h" #include "nsIPresShell.h" #include "nsIImageLoadingContent.h" #include "imgIRequest.h" #include "imgIContainer.h" #include "gfxIImageFrame.h" #define RUNKEY "Software\\Microsoft\\Windows\\CurrentVersion\\Run" // Objects that describe the Windows registry entries that we need to tweak. static ProtocolRegistryEntry http( "http" ), https( "https" ), ftp( "ftp" ), chrome( "chrome" ), gopher( "gopher" ); const char *xhtmExts[] = { ".xht", ".xhtml", 0 }; const char *htmExts[] = { ".htm", ".html", ".shtml", 0 }; static FileTypeRegistryEntry xhtml( xhtmExts, "MozillaXHTML", "XHTML Document", "", "doc-file.ico"), mozillaMarkup( htmExts, "MozillaHTML", "HTML Document", "htmlfile", "doc-file.ico"); // Implementation of the nsIWindowsHooksSettings interface. // Use standard implementation of nsISupports stuff. NS_IMPL_ISUPPORTS1( nsWindowsHooksSettings, nsIWindowsHooksSettings ) nsWindowsHooksSettings::nsWindowsHooksSettings() { } nsWindowsHooksSettings::~nsWindowsHooksSettings() { } // Generic getter. NS_IMETHODIMP nsWindowsHooksSettings::Get( PRBool *result, PRBool nsWindowsHooksSettings::*member ) { NS_ENSURE_ARG( result ); NS_ENSURE_ARG( member ); *result = this->*member; return NS_OK; } // Generic setter. NS_IMETHODIMP nsWindowsHooksSettings::Set( PRBool value, PRBool nsWindowsHooksSettings::*member ) { NS_ENSURE_ARG( member ); this->*member = value; return NS_OK; } // Macros to define specific getter/setter methods. #define DEFINE_GETTER_AND_SETTER( attr, member ) \ NS_IMETHODIMP \ nsWindowsHooksSettings::Get##attr ( PRBool *result ) { \ return this->Get( result, &nsWindowsHooksSettings::member ); \ } \ NS_IMETHODIMP \ nsWindowsHooksSettings::Set##attr ( PRBool value ) { \ return this->Set( value, &nsWindowsHooksSettings::member ); \ } // Define all the getter/setter methods: DEFINE_GETTER_AND_SETTER( IsHandlingHTML, mHandleHTML ) DEFINE_GETTER_AND_SETTER( IsHandlingXHTML, mHandleXHTML ) DEFINE_GETTER_AND_SETTER( IsHandlingHTTP, mHandleHTTP ) DEFINE_GETTER_AND_SETTER( IsHandlingHTTPS, mHandleHTTPS ) DEFINE_GETTER_AND_SETTER( ShowDialog, mShowDialog ) DEFINE_GETTER_AND_SETTER( HaveBeenSet, mHaveBeenSet ) // Implementation of the nsIWindowsHooks interface. // Use standard implementation of nsISupports stuff. NS_IMPL_ISUPPORTS2( nsWindowsHooks, nsIWindowsHooks, nsIWindowsRegistry ) nsWindowsHooks::nsWindowsHooks() { } nsWindowsHooks::~nsWindowsHooks() { } // Internal GetPreferences. NS_IMETHODIMP nsWindowsHooks::GetSettings( nsWindowsHooksSettings **result ) { nsresult rv = NS_OK; // Validate input arg. NS_ENSURE_ARG( result ); // Allocate prefs object. nsWindowsHooksSettings *prefs = *result = new nsWindowsHooksSettings; NS_ENSURE_TRUE( prefs, NS_ERROR_OUT_OF_MEMORY ); // Got it, increment ref count. NS_ADDREF( prefs ); // Get each registry value and copy to prefs structure. prefs->mHandleHTTP = BoolRegistryEntry( "isHandlingHTTP" ); prefs->mHandleHTTPS = BoolRegistryEntry( "isHandlingHTTPS" ); prefs->mHandleHTML = BoolRegistryEntry( "isHandlingHTML" ); prefs->mHandleXHTML = BoolRegistryEntry( "isHandlingXHTML" ); prefs->mShowDialog = BoolRegistryEntry( "showDialog" ); prefs->mHaveBeenSet = BoolRegistryEntry( "haveBeenSet" ); #ifdef DEBUG_law NS_WARN_IF_FALSE( NS_SUCCEEDED( rv ), "GetPreferences failed" ); #endif return rv; } // Public interface uses internal plus a QI to get to the proper result. NS_IMETHODIMP nsWindowsHooks::GetSettings( nsIWindowsHooksSettings **_retval ) { // Allocate prefs object. nsWindowsHooksSettings *prefs; nsresult rv = this->GetSettings( &prefs ); if ( NS_SUCCEEDED( rv ) ) { // QI to proper interface. rv = prefs->QueryInterface( NS_GET_IID( nsIWindowsHooksSettings ), (void**)_retval ); // Release (to undo our Get...). NS_RELEASE( prefs ); } return rv; } static PRBool misMatch( const PRBool &flag, const ProtocolRegistryEntry &entry ) { PRBool result = PR_FALSE; // Check if we care. if ( flag ) { // Compare registry entry setting to what it *should* be. if ( entry.currentSetting() != entry.setting ) { result = PR_TRUE; } } return result; } // isAccessRestricted - Returns PR_TRUE iff this user only has restricted access // to the registry keys we need to modify. static PRBool isAccessRestricted() { char subKey[] = "Software\\Mozilla - Test Key"; PRBool result = PR_FALSE; DWORD dwDisp = 0; HKEY key; // Try to create/open a subkey under HKLM. DWORD rc = ::RegCreateKeyEx( HKEY_LOCAL_MACHINE, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, &dwDisp ); if ( rc == ERROR_SUCCESS ) { // Key was opened; first close it. ::RegCloseKey( key ); // Delete it if we just created it. switch( dwDisp ) { case REG_CREATED_NEW_KEY: ::RegDeleteKey( HKEY_LOCAL_MACHINE, subKey ); break; case REG_OPENED_EXISTING_KEY: break; } } else { // Can't create/open it; we don't have access. result = PR_TRUE; } return result; } // Implementation of method that checks whether the settings match what's in the // Windows registry. NS_IMETHODIMP nsWindowsHooksSettings::GetRegistryMatches( PRBool *_retval ) { NS_ENSURE_ARG( _retval ); *_retval = PR_TRUE; // Test registry for all selected attributes. if ( misMatch( mHandleHTTP, http ) || misMatch( mHandleHTTPS, https ) || misMatch( mHandleHTML, mozillaMarkup ) || misMatch( mHandleXHTML, xhtml ) ) { // Registry is out of synch. *_retval = PR_FALSE; } return NS_OK; } // Implementation of method that checks settings versus registry and prompts user // if out of synch. NS_IMETHODIMP nsWindowsHooks::CheckSettings( nsIDOMWindowInternal *aParent, PRBool *_retval ) { nsresult rv = NS_OK; *_retval = PR_FALSE; // Only do this once! static PRBool alreadyChecked = PR_FALSE; if ( alreadyChecked ) { return NS_OK; } else { alreadyChecked = PR_TRUE; // Don't check further if we don't have sufficient access. if ( isAccessRestricted() ) { return NS_OK; } } // Get settings. nsWindowsHooksSettings *settings; rv = this->GetSettings( &settings ); if ( NS_SUCCEEDED( rv ) && settings ) { // If not set previously, set to defaults so that they are // set properly when/if the user says to. if ( !settings->mHaveBeenSet ) { settings->mHandleHTTP = PR_TRUE; settings->mHandleHTTPS = PR_TRUE; settings->mHandleHTML = PR_TRUE; settings->mHandleXHTML = PR_TRUE; settings->mShowDialog = PR_TRUE; } // If launched with "-installer" then override mShowDialog. PRBool installing = PR_FALSE; if ( !settings->mShowDialog ) { // Get command line service. nsCID cmdLineCID = NS_COMMANDLINE_SERVICE_CID; nsCOMPtr cmdLineArgs( do_GetService( cmdLineCID, &rv ) ); if ( NS_SUCCEEDED( rv ) && cmdLineArgs ) { // See if "-installer" was specified. nsXPIDLCString installer; rv = cmdLineArgs->GetCmdLineValue( "-installer", getter_Copies( installer ) ); if ( NS_SUCCEEDED( rv ) && installer ) { installing = PR_TRUE; } } } // First, make sure the user cares. if ( settings->mShowDialog || installing ) { // Look at registry setting for all things that are set. PRBool matches = PR_TRUE; settings->GetRegistryMatches( &matches ); if ( !matches ) { // Need to prompt user. // First: // o We need the common dialog service to show the dialog. // o We need the string bundle service to fetch the appropriate // dialog text. nsCID bundleCID = NS_STRINGBUNDLESERVICE_CID; nsCOMPtr promptService( do_GetService("@mozilla.org/embedcomp/prompt-service;1")); nsCOMPtr bundleService( do_GetService( bundleCID, &rv ) ); if ( promptService && bundleService ) { // Next, get bundle that provides text for dialog. nsCOMPtr bundle; nsCOMPtr brandBundle; rv = bundleService->CreateBundle( "chrome://global-platform/locale/nsWindowsHooks.properties", getter_AddRefs( bundle ) ); rv = bundleService->CreateBundle( "chrome://global/locale/brand.properties", getter_AddRefs( brandBundle ) ); if ( NS_SUCCEEDED( rv ) && bundle && brandBundle ) { nsXPIDLString text, label, shortName; if ( NS_SUCCEEDED( ( rv = brandBundle->GetStringFromName( NS_LITERAL_STRING( "brandShortName" ).get(), getter_Copies( shortName ) ) ) ) ) { const PRUnichar* formatStrings[] = { shortName.get() }; if ( NS_SUCCEEDED( ( rv = bundle->FormatStringFromName( NS_LITERAL_STRING( "promptText" ).get(), formatStrings, 1, getter_Copies( text ) ) ) ) && NS_SUCCEEDED( ( rv = bundle->GetStringFromName( NS_LITERAL_STRING( "checkBoxLabel" ).get(), getter_Copies( label ) ) ) ) ) { // Got the text, now show dialog. PRBool showDialog = settings->mShowDialog; PRInt32 dlgResult = -1; // No checkbox for initial display. const PRUnichar *labelArg = 0; if ( settings->mHaveBeenSet ) { // Subsequent display uses label string. labelArg = label; } // Note that the buttons need to be passed in this order: // o Yes // o Cancel // o No rv = promptService->ConfirmEx(aParent, shortName, text, (nsIPromptService::BUTTON_TITLE_YES * nsIPromptService::BUTTON_POS_0) + (nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_1) + (nsIPromptService::BUTTON_TITLE_NO * nsIPromptService::BUTTON_POS_2), nsnull, nsnull, nsnull, labelArg, &showDialog, &dlgResult); if ( NS_SUCCEEDED( rv ) ) { // Dialog was shown *_retval = PR_TRUE; // Did they say go ahead? switch ( dlgResult ) { case 0: // User says: make the changes. // Remember "show dialog" choice. settings->mShowDialog = showDialog; // Apply settings; this single line of // code will do different things depending // on whether this is the first time (i.e., // when "haveBeenSet" is false). The first // time, this will set all prefs to true // (because that's how we initialized 'em // in GetSettings, above) and will update the // registry accordingly. On subsequent passes, // this will only update the registry (because // the settings we got from GetSettings will // not have changed). // // BTW, the term "prefs" in this context does not // refer to conventional Mozilla "prefs." Instead, // it refers to "Desktop Integration" prefs which // are stored in the windows registry. rv = SetSettings( settings ); #ifdef DEBUG_law printf( "Yes, SetSettings returned 0x%08X\n", (int)rv ); #endif break; case 2: // User says: Don't mess with Windows. // We update only the "showDialog" and // "haveBeenSet" keys. Note that this will // have the effect of setting all the prefs // *off* if the user says no to the initial // prompt. BoolRegistryEntry( "haveBeenSet" ).set(); if ( showDialog ) { BoolRegistryEntry( "showDialog" ).set(); } else { BoolRegistryEntry( "showDialog" ).reset(); } #ifdef DEBUG_law printf( "No, haveBeenSet=1 and showDialog=%d\n", (int)showDialog ); #endif break; default: // User says: I dunno. Make no changes (which // should produce the same dialog next time). #ifdef DEBUG_law printf( "Cancel\n" ); #endif break; } } } } } } } #ifdef DEBUG_law else { printf( "Registry and prefs match\n" ); } #endif } #ifdef DEBUG_law else { printf( "showDialog is false and not installing\n" ); } #endif // Release the settings. settings->Release(); } return rv; } // Utility to set PRBool registry value from getter method. nsresult putPRBoolIntoRegistry( const char* valueName, nsIWindowsHooksSettings *prefs, nsWindowsHooksSettings::getter memFun ) { // Use getter method to extract attribute from prefs. PRBool boolValue; (void)(prefs->*memFun)( &boolValue ); // Convert to DWORD. DWORD dwordValue = boolValue; // Store into registry. BoolRegistryEntry pref( valueName ); nsresult rv = boolValue ? pref.set() : pref.reset(); return rv; } /* void setPreferences (in nsIWindowsHooksSettings prefs); */ NS_IMETHODIMP nsWindowsHooks::SetSettings(nsIWindowsHooksSettings *prefs) { nsresult rv = NS_ERROR_FAILURE; putPRBoolIntoRegistry( "isHandlingHTTP", prefs, &nsIWindowsHooksSettings::GetIsHandlingHTTP ); putPRBoolIntoRegistry( "isHandlingHTTPS", prefs, &nsIWindowsHooksSettings::GetIsHandlingHTTPS ); putPRBoolIntoRegistry( "isHandlingHTML", prefs, &nsIWindowsHooksSettings::GetIsHandlingHTML ); putPRBoolIntoRegistry( "isHandlingXHTML", prefs, &nsIWindowsHooksSettings::GetIsHandlingXHTML ); putPRBoolIntoRegistry( "showDialog", prefs, &nsIWindowsHooksSettings::GetShowDialog ); // Indicate that these settings have indeed been set. BoolRegistryEntry( "haveBeenSet" ).set(); rv = SetRegistry(); return rv; } // Get preferences and start handling everything selected. NS_IMETHODIMP nsWindowsHooks::SetRegistry() { nsresult rv = NS_OK; // Get raw prefs object. nsWindowsHooksSettings *prefs; rv = this->GetSettings( &prefs ); NS_ENSURE_TRUE( NS_SUCCEEDED( rv ), rv ); if ( prefs->mHandleHTML ) { (void) mozillaMarkup.set(); } else { (void) mozillaMarkup.reset(); } if ( prefs->mHandleXHTML ) { (void) xhtml.set(); } else { (void) xhtml.reset(); } if ( prefs->mHandleHTTP ) { (void) http.set(); } else { (void) http.reset(); } if ( prefs->mHandleHTTPS ) { (void) https.set(); } else { (void) https.reset(); } // Call SHChangeNotify() to notify the windows shell that file // associations changed, and that an update of the icons need to occur. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); return NS_OK; } NS_IMETHODIMP nsWindowsHooks::GetRegistryEntry( PRInt32 aHKEYConstant, const char *aSubKeyName, const char *aValueName, char **aResult ) { NS_ENSURE_ARG( aResult ); *aResult = 0; // Calculate HKEY_* starting point based on input nsIWindowsHooks constant. HKEY hKey; switch ( aHKEYConstant ) { case HKCR: hKey = HKEY_CLASSES_ROOT; break; case HKCC: hKey = HKEY_CURRENT_CONFIG; break; case HKCU: hKey = HKEY_CURRENT_USER; break; case HKLM: hKey = HKEY_LOCAL_MACHINE; break; case HKU: hKey = HKEY_USERS; break; default: return NS_ERROR_INVALID_ARG; } // Get requested registry entry. nsCAutoString entry( RegistryEntry( hKey, aSubKeyName, aValueName, 0 ).currentSetting() ); // Copy to result. *aResult = PL_strdup( entry.get() ); return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY; } nsresult WriteBitmap(nsString& aPath, gfxIImageFrame* aImage) { PRInt32 width, height; aImage->GetWidth(&width); aImage->GetHeight(&height); PRUint8* bits; PRUint32 length; aImage->GetImageData(&bits, &length); if (!bits) return NS_ERROR_FAILURE; PRUint32 bpr; aImage->GetImageBytesPerRow(&bpr); PRInt32 bitCount = bpr/width; // initialize these bitmap structs which we will later // serialize directly to the head of the bitmap file LPBITMAPINFOHEADER bmi = (LPBITMAPINFOHEADER)new BITMAPINFO; bmi->biSize = sizeof(BITMAPINFOHEADER); bmi->biWidth = width; bmi->biHeight = height; bmi->biPlanes = 1; bmi->biBitCount = (WORD)bitCount*8; bmi->biCompression = BI_RGB; bmi->biSizeImage = 0; // don't need to set this if bmp is uncompressed bmi->biXPelsPerMeter = 0; bmi->biYPelsPerMeter = 0; bmi->biClrUsed = 0; bmi->biClrImportant = 0; BITMAPFILEHEADER bf; bf.bfType = 0x4D42; // 'BM' bf.bfReserved1 = 0; bf.bfReserved2 = 0; bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); bf.bfSize = bf.bfOffBits + bmi->biSizeImage; // get a file output stream nsresult rv; nsCOMPtr path; rv = NS_NewLocalFile(aPath, PR_TRUE, getter_AddRefs(path)); if (NS_FAILED(rv)) return rv; nsCOMPtr stream; NS_NewLocalFileOutputStream(getter_AddRefs(stream), path); // write the bitmap headers and rgb pixel data to the file rv = NS_ERROR_FAILURE; if (stream) { PRUint32 written; stream->Write((const char*)&bf, sizeof(BITMAPFILEHEADER), &written); if (written == sizeof(BITMAPFILEHEADER)) { stream->Write((const char*)bmi, sizeof(BITMAPINFOHEADER), &written); if (written == sizeof(BITMAPINFOHEADER)) { stream->Write((const char*)bits, length, &written); if (written == length) rv = NS_OK; } } stream->Close(); } return rv; } NS_IMETHODIMP nsWindowsHooks::GetDesktopColor(PRUint32* aColors) { PRUint32 color = ::GetSysColor(COLOR_DESKTOP); *aColors = (GetRValue(color) << 16) | (GetGValue(color) << 8) | GetBValue(color); return NS_OK; } NS_IMETHODIMP nsWindowsHooks::SetDesktopColor(PRUint32 aColor) { int aParameters[2] = { COLOR_BACKGROUND, COLOR_DESKTOP }; BYTE r = (aColor >> 16); BYTE g = (aColor << 16) >> 24; BYTE b = (aColor << 24) >> 24; COLORREF colors[2] = { RGB(r,g,b), RGB(r,g,b) }; ::SetSysColors(sizeof(aParameters) / sizeof(int), aParameters, colors); char subKey[] = "Control Panel\\Colors"; PRBool result = PR_FALSE; DWORD dwDisp = 0; HKEY key; // Try to create/open a subkey under HKLM. DWORD rc = ::RegCreateKeyEx(HKEY_CURRENT_USER, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, &dwDisp); if (rc == ERROR_SUCCESS) { char* rgb = new char[12]; sprintf(rgb, "%u %u %u\0", r, g, b); ::RegSetValueEx(key, "Background", 0, REG_SZ, (const unsigned char*)rgb, strlen(rgb)); delete[] rgb; } return NS_OK; } NS_IMETHODIMP nsWindowsHooks::SetImageAsWallpaper(nsIDOMElement* aElement, PRBool aUseBackground, PRInt32 position) { nsresult rv; nsCOMPtr gfxFrame; if (aUseBackground) { // XXX write background loading stuff! } else { nsCOMPtr imageContent = do_QueryInterface(aElement, &rv); if (!imageContent) return rv; // get the image container nsCOMPtr request; rv = imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST, getter_AddRefs(request)); if (!request) return rv; nsCOMPtr container; rv = request->GetImage(getter_AddRefs(container)); if (!request) return rv; // get the current frame, which holds the image data container->GetCurrentFrame(getter_AddRefs(gfxFrame)); } if (!gfxFrame) return NS_ERROR_FAILURE; // get the windows directory ('c:\windows' usually) char winDir[256]; ::GetWindowsDirectory(winDir, sizeof(winDir)); nsAutoString winPath; winPath.AssignWithConversion(winDir); // get the product brand name from localized strings nsXPIDLString brandName; nsCID bundleCID = NS_STRINGBUNDLESERVICE_CID; nsCOMPtr bundleService(do_GetService(bundleCID)); if (bundleService) { nsCOMPtr brandBundle; rv = bundleService->CreateBundle("chrome://global/locale/brand.properties", getter_AddRefs(brandBundle)); if (NS_SUCCEEDED(rv) && brandBundle) { if (NS_FAILED(rv = brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(), getter_Copies(brandName)))) return rv; } } // build the file name winPath.Append(NS_LITERAL_STRING("\\").get()); winPath.Append(brandName); winPath.Append(NS_LITERAL_STRING(" Wallpaper.bmp").get()); // write the bitmap to a file in the windows dir rv = WriteBitmap(winPath, gfxFrame); // if the file was written successfully, set it as the system wallpaper if (NS_SUCCEEDED(rv)) { char subKey[] = "Control Panel\\Desktop"; PRBool result = PR_FALSE; DWORD dwDisp = 0; HKEY key; // Try to create/open a subkey under HKLM. DWORD rc = ::RegCreateKeyEx( HKEY_CURRENT_USER, subKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &key, &dwDisp ); if (rc == ERROR_SUCCESS) { unsigned char tile[2]; unsigned char style[2]; if (position == WALLPAPER_TILE) { tile[0] = '1'; style[0] = '1'; } else if (position == WALLPAPER_CENTER) { tile[0] = '0'; style[0] = '0'; } else if (position == WALLPAPER_STRETCH) { tile[0] = '0'; style[0] = '2'; } tile[1] = '\0'; style[1] = '\0'; ::RegSetValueEx(key, "TileWallpaper", 0, REG_SZ, tile, sizeof(tile)); ::RegSetValueEx(key, "WallpaperStyle", 0, REG_SZ, style, sizeof(style)); ::SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, ToNewCString(winPath), SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE); } } return rv; } NS_IMETHODIMP nsWindowsHooks::OpenDefaultClient(const char* aClient) { nsresult rv; // The Default Client section of the Windows Registry looks like this: // // Clients\aClient\ // e.g. aClient = "Mail"... // \Mail\(default) = Client Subkey Name // \Client Subkey Name // \Client Subkey Name\shell\open\command\ // \Client Subkey Name\shell\open\command\(default) = path to exe // nsCAutoString clientKey(NS_LITERAL_CSTRING("SOFTWARE\\Clients\\")); clientKey += aClient; nsXPIDLCString defaultClient; rv = GetRegistryEntry(nsIWindowsRegistry::HKLM, clientKey.get(), "", getter_Copies(defaultClient)); if (NS_FAILED(rv) || defaultClient.IsEmpty()) return rv; clientKey.Append("\\"); clientKey.Append(defaultClient.get()); clientKey.Append("\\shell\\open\\command"); nsXPIDLCString path; rv = GetRegistryEntry(nsIWindowsRegistry::HKLM, clientKey.get(), "", getter_Copies(path)); if (NS_FAILED(rv) || path.IsEmpty()) return rv; // Look for any embedded environment variables and substitute their // values, as |::CreateProcess| is unable to do this. PRInt32 end = path.Length(); PRInt32 cursor = 0, temp = 0; char buf[_MAX_PATH]; do { cursor = path.FindChar('%', cursor); if (cursor < 0) break; temp = path.FindChar('%', cursor + 1); ++cursor; ::ZeroMemory(&buf, sizeof(buf)); ::GetEnvironmentVariable(nsCAutoString(Substring(path, cursor, temp - cursor)).get(), buf, sizeof(buf)); // "+ 2" is to subtract the extra characters used to delimit the environment // variable ('%'). path.Replace((cursor - 1), temp - cursor + 2, nsDependentCString(buf)); ++cursor; } while (cursor < end); STARTUPINFO si; PROCESS_INFORMATION pi; ::ZeroMemory(&si, sizeof(STARTUPINFO)); ::ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); char* pathCStr = ToNewCString(path); BOOL success = ::CreateProcess(NULL, pathCStr, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); nsCRT::free(pathCStr); if (!success) return NS_ERROR_FAILURE; return NS_OK; } NS_IMETHODIMP nsWindowsHooks::GetUnreadMailCount(PRUint32* aResult) { *aResult = 0; HKEY accountKey; if (GetMailAccountKey(&accountKey)) { DWORD type, length, unreadCount; DWORD result = ::RegQueryValueEx(accountKey, "MessageCount", 0, &type, (LPBYTE)&unreadCount, &length); if (result == ERROR_SUCCESS) { *aResult = unreadCount; } } return NS_OK; } PRBool nsWindowsHooks::GetMailAccountKey(HKEY* aResult) { HKEY mailKey; DWORD result = ::RegOpenKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\UnreadMail\\", 0, KEY_ENUMERATE_SUB_KEYS, &mailKey); PRInt32 i = 0; do { char subkeyName[_MAX_PATH]; DWORD len = sizeof subkeyName; result = ::RegEnumKeyEx(mailKey, i++, subkeyName, &len, 0, 0, 0, 0); if (result == ERROR_SUCCESS) { HKEY accountKey; result = ::RegOpenKeyEx(mailKey, subkeyName, 0, KEY_READ, &accountKey); if (result == ERROR_SUCCESS) { *aResult = accountKey; return PR_TRUE; } } else break; } while (1); return PR_FALSE; }