From 90a973e5c24d3bca7ba36061e6f8df97873555a6 Mon Sep 17 00:00:00 2001 From: Siddharth Agarwal Date: Sun, 21 Dec 2008 02:31:35 +0100 Subject: [PATCH] Bug 469739 - Add support for displaying Vista UAC shield icon; r=joe sr=vladimir --- .../decoders/icon/win/nsIconChannel.cpp | 124 ++++++++++++++++-- .../libpr0n/decoders/icon/win/nsIconChannel.h | 10 ++ 2 files changed, 122 insertions(+), 12 deletions(-) diff --git a/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp b/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp index 0c25cb44869e..e403ffac611f 100644 --- a/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp +++ b/modules/libpr0n/decoders/icon/win/nsIconChannel.cpp @@ -59,6 +59,13 @@ #include "nsCExternalHandlerService.h" #include "nsDirectoryServiceDefs.h" +#ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +#define _WIN32_WINNT 0x0600 +#endif + // we need windows.h to read out registry information... #include #include @@ -82,6 +89,20 @@ struct ICONENTRY { PRUint32 ieFileOffset; }; +#ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS +typedef HRESULT (WINAPI*SHGetStockIconInfoPtr) (SHSTOCKICONID siid, UINT uFlags, SHSTOCKICONINFO *psii); + +// Match stock icons with names +static SHSTOCKICONID GetStockIconIDForName(const nsACString &aStockName) +{ + // UAC shield icon + if (aStockName == NS_LITERAL_CSTRING("uac-shield")) + return SIID_SHIELD; + + return SIID_INVALID; +} +#endif + // nsIconChannel methods nsIconChannel::nsIconChannel() { @@ -272,7 +293,20 @@ static DWORD GetSpecialFolderIcon(nsIFile* aFile, int aFolder, SHFILEINFOW* aSFI return shellResult; } -nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBlocking) +static UINT GetSizeInfoFlag(PRUint32 aDesiredImageSize) +{ + UINT infoFlag; +#ifndef WINCE + if (aDesiredImageSize > 16) + infoFlag = SHGFI_SHELLICONSIZE; + else +#endif + infoFlag = SHGFI_SMALLICON; + + return infoFlag; +} + +nsresult nsIconChannel::GetHIconFromFile(HICON *hIcon) { nsXPIDLCString contentType; nsCString fileExt; @@ -309,12 +343,7 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc if (!fileExists) infoFlags |= SHGFI_USEFILEATTRIBUTES; -#ifndef WINCE - if (desiredImageSize > 16) - infoFlags |= SHGFI_SHELLICONSIZE; - else -#endif - infoFlags |= SHGFI_SMALLICON; + infoFlags |= GetSizeInfoFlag(desiredImageSize); // if we have a content type... then use it! but for existing files, we want // to show their real icon. @@ -331,8 +360,6 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc filePath = NS_LITERAL_CSTRING(".") + defFileExt; } - rv = NS_ERROR_NOT_AVAILABLE; - // Is this the "Desktop" folder? DWORD shellResult = GetSpecialFolderIcon(localFile, CSIDL_DESKTOP, &sfi, infoFlags); if (!shellResult) { @@ -351,10 +378,83 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc FILE_ATTRIBUTE_ARCHIVE, &sfi, sizeof(sfi), infoFlags); if (shellResult && sfi.hIcon) + *hIcon = sfi.hIcon; + else + rv = NS_ERROR_NOT_AVAILABLE; + + return rv; +} + +#ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS +nsresult nsIconChannel::GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon) +{ + nsresult rv = NS_OK; + + // We can only do this on Vista or above + HMODULE hShellDLL = ::LoadLibraryW(L"shell32.dll"); + SHGetStockIconInfoPtr pSHGetStockIconInfo = + (SHGetStockIconInfoPtr) ::GetProcAddress(hShellDLL, "SHGetStockIconInfo"); + + if (pSHGetStockIconInfo) + { + PRUint32 desiredImageSize; + aIconURI->GetImageSize(&desiredImageSize); + nsCAutoString stockIcon; + aIconURI->GetStockIcon(stockIcon); + + SHSTOCKICONID stockIconID = GetStockIconIDForName(stockIcon); + if (stockIconID == SIID_INVALID) + return NS_ERROR_NOT_AVAILABLE; + + UINT infoFlags = SHGSI_ICON; + infoFlags |= GetSizeInfoFlag(desiredImageSize); + + SHSTOCKICONINFO sii = {0}; + sii.cbSize = sizeof(sii); + HRESULT hr = pSHGetStockIconInfo(stockIconID, infoFlags, &sii); + + if (SUCCEEDED(hr)) + *hIcon = sii.hIcon; + else + rv = NS_ERROR_FAILURE; + } + else + { + rv = NS_ERROR_NOT_AVAILABLE; + } + + if (hShellDLL) + ::FreeLibrary(hShellDLL); + + return rv; +} +#endif + +nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBlocking) +{ + // Check whether the icon requested's a file icon or a stock icon + nsresult rv; + HICON hIcon = NULL; + +#ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS + nsCOMPtr iconURI(do_QueryInterface(mUrl, &rv)); + NS_ENSURE_SUCCESS(rv, rv); + + nsCAutoString stockIcon; + iconURI->GetStockIcon(stockIcon); + if (!stockIcon.IsEmpty()) + rv = GetStockHIcon(iconURI, &hIcon); + else +#endif + rv = GetHIconFromFile(&hIcon); + + NS_ENSURE_SUCCESS(rv, rv); + + if (hIcon) { // we got a handle to an icon. Now we want to get a bitmap for the icon using GetIconInfo.... ICONINFO iconInfo; - if (GetIconInfo(sfi.hIcon, &iconInfo)) + if (GetIconInfo(hIcon, &iconInfo)) { // we got the bitmaps, first find out their size HDC hDC = CreateCompatibleDC(NULL); // get a device context for the screen. @@ -419,8 +519,8 @@ nsresult nsIconChannel::MakeInputStream(nsIInputStream** _retval, PRBool nonBloc DeleteObject(iconInfo.hbmColor); DeleteObject(iconInfo.hbmMask); } // if we got icon info - DestroyIcon(sfi.hIcon); - } // if we got sfi + DestroyIcon(hIcon); + } // if we got an hIcon return rv; } diff --git a/modules/libpr0n/decoders/icon/win/nsIconChannel.h b/modules/libpr0n/decoders/icon/win/nsIconChannel.h index a69ea61c0d87..97d41e322452 100644 --- a/modules/libpr0n/decoders/icon/win/nsIconChannel.h +++ b/modules/libpr0n/decoders/icon/win/nsIconChannel.h @@ -49,6 +49,9 @@ #include "nsIURI.h" #include "nsIInputStreamPump.h" #include "nsIStreamListener.h" +#include "nsIIconURI.h" + +#include class nsIFile; @@ -78,7 +81,14 @@ protected: nsCOMPtr mListener; nsresult ExtractIconInfoFromUrl(nsIFile ** aLocalFile, PRUint32 * aDesiredImageSize, nsCString &aContentType, nsCString &aFileExtension); + nsresult GetHIconFromFile(HICON *hIcon); nsresult MakeInputStream(nsIInputStream** _retval, PRBool nonBlocking); + + // Functions specific to Vista and above +#ifndef MOZ_DISABLE_VISTA_SDK_REQUIREMENTS +protected: + nsresult GetStockHIcon(nsIMozIconURI *aIconURI, HICON *hIcon); +#endif }; #endif /* nsIconChannel_h___ */