Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / AppModel / IconHelper.cs / 1 / IconHelper.cs
//---------------------------------------------------------------------------- // // File: IconHelper.cs // // Description: Static internal class implements utility functions for icon // implementation for the Window class. // // Created: 07/27/05 // // Copyright (C) 2001 by Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System; using System.Security; using System.Security.Permissions; using System.Diagnostics; using System.Collections.ObjectModel; using System.Runtime.InteropServices; using System.ComponentModel; using System.Windows; using System.Windows.Interop; using System.Windows.Media.Imaging; using System.Windows.Media; using MS.Internal; using MS.Internal.PresentationFramework; // SecurityHelper using MS.Win32; namespace MS.Internal.AppModel { internal static class IconHelper { ////// Critical: This code elevates to unmanaged Code permission /// TreatAsSafe: There is a demand here /// ///[SecurityCritical, SecurityTreatAsSafe] internal static void GetDefaultIconHandles(object callingObj, ref NativeMethods.IconHandle largeIconHandle, ref NativeMethods.IconHandle smallIconHandle) { SecurityHelper.DemandUIWindowPermission(); IntPtr mainModuleHandle = IntPtr.Zero; string iconModuleFile = String.Empty; NativeMethods.IconHandle[] hLargeIcon = new NativeMethods.IconHandle[1]{new NativeMethods.IconHandle()}; NativeMethods.IconHandle[] hSmallIcon = new NativeMethods.IconHandle[1]{new NativeMethods.IconHandle()}; // In case we don't get any icons from the exe, we don't want to return the input values // as they could be mistaken to have come from the exe, thus, setting to default values here largeIconHandle = hLargeIcon[0]; smallIconHandle = hLargeIcon[0]; // Get the default icon from the application first. // We use GetModuleHandle(null) to get the handle to the // module that created the process. Then we call // GetModuleFileName to get the file name of that module // GetModuleHandle(null) get's the handle of module that created // the running process. GetModuleHandle does not increase the // refCount of the module and hence we don't need to call // FreeLibrary later. However, this means that in multithreaded // application some other thread can free the module and unload // from memory rendering our module handle obsolete. But, this is // not the case here and we're getting the handle to the exe. mainModuleHandle = UnsafeNativeMethods.GetModuleHandle(null); if (mainModuleHandle != IntPtr.Zero) { // find the path and file name of the module that created the process // We start with MAX_PATH as the initial buffer length. If it's UNC path // then it could be pretty big that's why we do it in a while loop with // double the size until we retrieve the entire path. // NOTE: I tried to give a UNC path greater than MAX_PATH and mscorlib // threw FileIOLoadException even before hitting any Avalon code. Seems // like greater than MAX_PATH is not currently supported by CLR. However, // since GetModuleFileName(Ex) documentation mentions that it can return // greater than MAX_PATH so we are doing the do/while loop below. System.Text.StringBuilder sb; int fileNameCopiedLength = 0; int bufferLength = 0; do { bufferLength = (bufferLength == 0 ? NativeMethods.MAX_PATH : bufferLength * 2); sb = new System.Text.StringBuilder( bufferLength ); // get module's file name fileNameCopiedLength = UnsafeNativeMethods.GetModuleFileName( new HandleRef(callingObj, mainModuleHandle), // handle to the module to retrieve the file name of sb, // buffer to copy the file name bufferLength // size of the buffer ); if (fileNameCopiedLength == 0) // error case { throw new Win32Exception(); } } while((fileNameCopiedLength == bufferLength) || (fileNameCopiedLength == (bufferLength - 1))); // GetModuleFileName(Ex) documentation is unclear regarding whether the returned value // includes the null terminator or not thus we check both borderline cases. iconModuleFile = sb.ToString(); } // The following code is run only if we successfully retrieved the file name to retrieve the // icon from. If there was an exception in the code above the method would exit after // executing the finally block. // // ExtractIconEx is not necessiated in an if statement here, but doing so // keeps PreSharp happy since we are doing something with the return value. if ((iconModuleFile != String.Empty) && (UnsafeNativeMethods.ExtractIconEx(iconModuleFile, 0, ref hLargeIcon[0], ref hSmallIcon[0], 1) <= 0)) { return; } largeIconHandle = hLargeIcon[0]; smallIconHandle = hSmallIcon[0]; } // Inputs: // callingObj -- to be used in HandleRef // bf -- BitmapFrame to be used to create HICONs from // In/Out/ref: // largeIconHandle -- to return the large HICON created // smallIconHandle -- to return the small HICON created /// /// Critical: Since it calls CreateIconHandleFromBitmapFrame /// TAS: Since it creates icons with known h/w i.e. IconWidth/Height or SmallIconWidth/Height /// ///[SecurityCritical, SecurityTreatAsSafe] internal static void GetIconHandlesFromBitmapFrame(object callingObj, BitmapFrame bf, ref NativeMethods.IconHandle largeIconHandle, ref NativeMethods.IconHandle smallIconHandle) { Invariant.Assert(bf.Decoder != null, "_icon.Decoder should never be null"); Invariant.Assert(bf.Decoder.Frames != null, "_icon.Decoder.Frames should never be null"); // sysBitDepth is used to select the correct frame among the frames that came from // the ico file int sysBitDepth = IconHelper.GetSystemBitDepth(callingObj); int largeIconIndex = IconHelper.GetBestMatch(bf.Decoder.Frames, sysBitDepth, (int)SystemParameters.IconWidth, (int)SystemParameters.IconHeight); int smallIconIndex = IconHelper.GetBestMatch(bf.Decoder.Frames, sysBitDepth, (int)SystemParameters.SmallIconWidth, (int)SystemParameters.SmallIconHeight); largeIconHandle = IconHelper.CreateIconHandleFromBitmapFrame(bf.Decoder.Frames[largeIconIndex]); smallIconHandle = IconHelper.CreateIconHandleFromBitmapFrame(bf.Decoder.Frames[smallIconIndex]); } /// /// Critical: Since it calls CreateIconCursor which is SecurityCritical. CreateIconCursor is SecurityCritical b/c /// it creates bitmaps with the input w/h etc. That width/height is passed by this method using /// sourceBitmapFrame.Pixel[Width/Height] and is not guarded. /// ///// // Creates and HICON from a bitmap frame [SecurityCritical] private static NativeMethods.IconHandle CreateIconHandleFromBitmapFrame(BitmapFrame sourceBitmapFrame) { Invariant.Assert(sourceBitmapFrame != null, "sourceBitmapFrame cannot be null here"); BitmapSource bitmapSource = sourceBitmapFrame; PixelFormat reqPixelFormat = PixelFormats.Bgra32; if (bitmapSource.Format != reqPixelFormat) { bitmapSource = new FormatConvertedBitmap(bitmapSource, reqPixelFormat, null, 0.0); } // data used by CopyPixels int w = bitmapSource.PixelWidth; int h = bitmapSource.PixelHeight; int bpp = bitmapSource.Format.BitsPerPixel; // ensuring it is in 4 byte increments since we're dealing // with ARGB fromat int stride = (bpp * w + 31) / 32 * 4; int sizeCopyPixels = stride * h; byte[] xor = new byte[sizeCopyPixels]; bitmapSource.CopyPixels(xor, stride, 0); return CreateIconCursor(xor, w, h, 0, 0, true); } // Creates a 32 bit per pixel Icon or cursor. This code is moved from framework\ms\internal\ink\pencursormanager.cs /// /// Critical: Critical as this code create a DIB section and writes data to it /// [SecurityCritical] internal static NativeMethods.IconHandle CreateIconCursor( byte[] colorArray, int width, int height, int xHotspot, int yHotspot, bool isIcon) { NativeMethods.IconHandle returnHandle = new NativeMethods.IconHandle(); // 1. We are going to generate a WIN32 color bitmap which represents the color cursor. // 2. Then we need to create a monochrome bitmap which is used as the cursor mask. // 3. At last we create a WIN32 HICON from the above two bitmaps NativeMethods.BitmapHandle colorBitmap = null; NativeMethods.BitmapHandle maskBitmap = null; try { // 1) Create the color bitmap using colorArray // Fill in the header information NativeMethods.BITMAPINFO bi = new NativeMethods.BITMAPINFO( width, // width -height, // A negative value indicates the bitmap is top-down DIB 32 // biBitCount ); bi.bmiHeader_biCompression = NativeMethods.BI_RGB; IntPtr bits = IntPtr.Zero; colorBitmap = MS.Win32.UnsafeNativeMethods.CreateDIBSection( new HandleRef(null, IntPtr.Zero), // A device context. Pass null in if no DIB_PAL_COLORS is used. ref bi, // A BITMAPINFO structure which specifies the dimensions and colors. NativeMethods.DIB_RGB_COLORS, // Specifies the type of data contained in the bmiColors array member of the BITMAPINFO structure ref bits, // An out Pointer to a variable that receives a pointer to the location of the DIB bit values IntPtr.Zero, // Handle to a file-mapping object that the function will use to create the DIB. This parameter can be null. 0 // dwOffset. This value is ignored if hSection is NULL ); if ( colorBitmap.IsInvalid || bits == IntPtr.Zero) { // Note we will release the GDI resources in the finally block. return new NativeMethods.IconHandle(IntPtr.Zero); } // Copy the color bits to the win32 bitmap Marshal.Copy(colorArray, 0, bits, colorArray.Length); // 2) Now create the mask bitmap which is monochrome byte[] maskArray = GenerateMaskArray(width, height, colorArray); Invariant.Assert(maskArray != null); maskBitmap = UnsafeNativeMethods.CreateBitmap(width, height, 1, 1, maskArray); if ( maskBitmap.IsInvalid ) { // Note we will release the GDI resources in the finally block. return new NativeMethods.IconHandle(IntPtr.Zero); } // Now create HICON from two bitmaps. NativeMethods.ICONINFO iconInfo = new NativeMethods.ICONINFO(); iconInfo.fIcon = isIcon; // fIcon == ture means creating an Icon, otherwise Cursor iconInfo.xHotspot = xHotspot; iconInfo.yHotspot = yHotspot; iconInfo.hbmMask = maskBitmap; iconInfo.hbmColor = colorBitmap; returnHandle = UnsafeNativeMethods.CreateIconIndirect(iconInfo); if ( returnHandle.IsInvalid ) { // Note we will release the GDI resources in the finally block. return new NativeMethods.IconHandle(IntPtr.Zero); } } finally { if (colorBitmap != null) { colorBitmap.Dispose(); colorBitmap = null; } if (maskBitmap != null) { maskBitmap.Dispose(); maskBitmap = null; } } return returnHandle; } // generates the mask array for the input colorArray. // The mask array is 1 bpp private static byte[] GenerateMaskArray(int width, int height, byte[] colorArray) { int nCount = width * height; // NOTICE-2005/04/26-WAYNEZEN, // Check out the notes in CreateBitmap in MSDN. The scan line has to be aliged to WORD. int bytesPerScanLine = AlignToBytes(width, 2) / 8; byte[] bitsMask = new byte[bytesPerScanLine * height]; // We are scaning all pixels in color bitmap. // If the alpha value is 0, we should set the corresponding mask bit to 1. So the pixel will show // the screen pixel. Otherwise, we should set the mask bit to 0 which causes the cursor to display // the color bitmap pixel. for ( int i = 0; i < nCount; i++ ) { // Get the i-th pixel position (hPos, vPos) int hPos = i % width; int vPos = i / width; // For each byte in 2-bit color bitmap, the lowest the bit represents the right-most display pixel. // For example the bollow mask - // 1 1 1 0 0 0 0 1 // ^ ^ // offsetBit = 0x80 offsetBit = 0x01 int byteIndex = hPos / 8; byte offsetBit = (byte)( 0x80 >> ( hPos % 8 ) ); // Now we turn the mask on or off accordingly. if ( colorArray[i * 4 + 3] /* Alpha value since it's in Args32 Format */ == 0x00 ) { // Set the mask bit to 1. bitsMask[byteIndex + bytesPerScanLine * vPos] |= (byte)offsetBit; } else { // Reset the mask bit to 0 bitsMask[byteIndex + bytesPerScanLine * vPos] &= (byte)( ~offsetBit ); } // Since the scan line of the mask bitmap has to be aligned to word. We have set all padding bits to 1. // So the extra pixel can be seen through. if ( hPos == width - 1 && width == 8 ) { bitsMask[1 + bytesPerScanLine * vPos] = 0xff; } } return bitsMask; } ////// Calculate the bits count aligned to N-Byte based on the input count /// /// The original value /// N-Byte ///the nearest bit count which is aligned to N-Byte internal static int AlignToBytes(double original, int nBytesCount) { Debug.Assert(nBytesCount > 0, "The N-Byte has to be greater than 0!"); int nBitsCount = 8 << (nBytesCount - 1); return (((int)Math.Ceiling(original) + (nBitsCount - 1)) / nBitsCount) * nBitsCount; } // returns the current system bit depth -- incdicates the # of // colors that can be shown. // // Code taken from WinForms implementation of selecting // which icon frame to use ////// Critical: Calls GetDC, ReleaseDC and GetDeviceCaps that are marked SecurityCritical /// TreatAsSafe: It is okay to return the current system bit depth /// [SecurityCritical, SecurityTreatAsSafe] private static int GetSystemBitDepth(object callerObj) { int sysBitDepth = 0; HandleRef handleRefDC; HandleRef handleRefZero = new HandleRef(callerObj, IntPtr.Zero); IntPtr dc = UnsafeNativeMethods.GetDC(handleRefZero); handleRefDC = new HandleRef(callerObj, dc); sysBitDepth = UnsafeNativeMethods.GetDeviceCaps(handleRefDC, NativeMethods.BITSPIXEL); sysBitDepth *= UnsafeNativeMethods.GetDeviceCaps(handleRefDC, NativeMethods.PLANES); UnsafeNativeMethods.ReleaseDC(handleRefZero, handleRefDC); return sysBitDepth; } // returns the index of the frame that best matches the given width, height and the current // system bit depth. // // This code is taken from Winforms implementation of choosing the correct frame based on the // requirements. // // Windows rules for specifing an icon: // // 1. The icon with the closest size match. // 2. For matching sizes, the image with the closest bit depth. // 3. If there is no color depth match, the icon with the closest color depth that does not exceed the display. // 4. If all icon color depth > display, lowest color depth is chosen. // 5. color depth of > 8bpp are all equal. // 6. Never choose an 8bpp icon on an 8bpp system. // ////// Critical: Calls LinkDemand property BitsPerPixel /// TreatAsSafe: The bits per pixel info is not revealed/returned /// [SecurityCritical, SecurityTreatAsSafe] private static int GetBestMatch(ReadOnlyCollectionframes, int sysBitDepth, int width, int height) { Invariant.Assert(width != 0, "input param width should not be zero"); Invariant.Assert(height != 0, "input param height should not be zero"); // If the _sysBitDepth is 8, make it 4. Why? Because windows does not // choose a 256 color icon if the display is running in 256 color mode // because of palette flicker. // if (sysBitDepth == 8) { sysBitDepth = 4; } int bestWidth = 0; int bestHeight = 0; int bestBitDepth = 0; int bestIndex = 0; int bestDelta = 0; bool isBitmapIconDecoder = frames.Count > 0 && frames[0].Decoder is IconBitmapDecoder; // iterate each frame to see if this one is a better match than the // previous best match for (int i = 0; i < frames.Count; i++) { bool updateBestFit = false; int currentWidth = frames[i].PixelWidth; int currentHeight = frames[i].PixelHeight; int currentIconBitDepth = 0; // determine the bit-depth (# of colors) in the // current frame // // if the icon is palettized, Format.BitsPerPixel gives // the # of bits required to index into the palette (thus, // the # of colors in the palette). If it is a true // color icon, it gives the # of bits required to support // true colors. // For icons, get the Format from the Thumbnail rather than from the // BitmapFrame directly because the unmanaged icon decoder // converts every icon to 32-bit. Thumbnail.Format.BitsPerPixel // will give us the original bit depth. currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; // it looks like if nothing is specified at this point, bpp is 8... // straight from WinForm and Win32 if (currentIconBitDepth == 0) { currentIconBitDepth = 8; } // Windows rules for specifing an icon: // // 1. The icon with the closest size match. // 2. For matching sizes, the image with the closest bit depth. // 3. If there is no color depth match, the icon with the closest color depth that does not exceed the display. // 4. If all icon color depth > display, lowest color depth is chosen. // 5. color depth of > 8bpp are all equal. // 6. Never choose an 8bpp icon on an 8bpp system. // // for the first index, don't have anything to compare against so pick it if (i == 0) { updateBestFit = true; } else { int thisDelta = Math.Abs(currentWidth - width) + Math.Abs(currentHeight - height); if ((thisDelta < bestDelta) || (thisDelta == bestDelta && (currentIconBitDepth <= sysBitDepth && currentIconBitDepth > bestBitDepth || bestBitDepth > sysBitDepth && currentIconBitDepth < bestBitDepth))) { updateBestFit = true; } } if (updateBestFit) { bestWidth = currentWidth; bestHeight = currentHeight; bestBitDepth = currentIconBitDepth; bestIndex = i; bestDelta = Math.Abs(currentWidth - width) + Math.Abs(currentHeight - height); } } return bestIndex; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // File: IconHelper.cs // // Description: Static internal class implements utility functions for icon // implementation for the Window class. // // Created: 07/27/05 // // Copyright (C) 2001 by Microsoft Corporation. All rights reserved. // //--------------------------------------------------------------------------- using System; using System.Security; using System.Security.Permissions; using System.Diagnostics; using System.Collections.ObjectModel; using System.Runtime.InteropServices; using System.ComponentModel; using System.Windows; using System.Windows.Interop; using System.Windows.Media.Imaging; using System.Windows.Media; using MS.Internal; using MS.Internal.PresentationFramework; // SecurityHelper using MS.Win32; namespace MS.Internal.AppModel { internal static class IconHelper { /// /// Critical: This code elevates to unmanaged Code permission /// TreatAsSafe: There is a demand here /// ///[SecurityCritical, SecurityTreatAsSafe] internal static void GetDefaultIconHandles(object callingObj, ref NativeMethods.IconHandle largeIconHandle, ref NativeMethods.IconHandle smallIconHandle) { SecurityHelper.DemandUIWindowPermission(); IntPtr mainModuleHandle = IntPtr.Zero; string iconModuleFile = String.Empty; NativeMethods.IconHandle[] hLargeIcon = new NativeMethods.IconHandle[1]{new NativeMethods.IconHandle()}; NativeMethods.IconHandle[] hSmallIcon = new NativeMethods.IconHandle[1]{new NativeMethods.IconHandle()}; // In case we don't get any icons from the exe, we don't want to return the input values // as they could be mistaken to have come from the exe, thus, setting to default values here largeIconHandle = hLargeIcon[0]; smallIconHandle = hLargeIcon[0]; // Get the default icon from the application first. // We use GetModuleHandle(null) to get the handle to the // module that created the process. Then we call // GetModuleFileName to get the file name of that module // GetModuleHandle(null) get's the handle of module that created // the running process. GetModuleHandle does not increase the // refCount of the module and hence we don't need to call // FreeLibrary later. However, this means that in multithreaded // application some other thread can free the module and unload // from memory rendering our module handle obsolete. But, this is // not the case here and we're getting the handle to the exe. mainModuleHandle = UnsafeNativeMethods.GetModuleHandle(null); if (mainModuleHandle != IntPtr.Zero) { // find the path and file name of the module that created the process // We start with MAX_PATH as the initial buffer length. If it's UNC path // then it could be pretty big that's why we do it in a while loop with // double the size until we retrieve the entire path. // NOTE: I tried to give a UNC path greater than MAX_PATH and mscorlib // threw FileIOLoadException even before hitting any Avalon code. Seems // like greater than MAX_PATH is not currently supported by CLR. However, // since GetModuleFileName(Ex) documentation mentions that it can return // greater than MAX_PATH so we are doing the do/while loop below. System.Text.StringBuilder sb; int fileNameCopiedLength = 0; int bufferLength = 0; do { bufferLength = (bufferLength == 0 ? NativeMethods.MAX_PATH : bufferLength * 2); sb = new System.Text.StringBuilder( bufferLength ); // get module's file name fileNameCopiedLength = UnsafeNativeMethods.GetModuleFileName( new HandleRef(callingObj, mainModuleHandle), // handle to the module to retrieve the file name of sb, // buffer to copy the file name bufferLength // size of the buffer ); if (fileNameCopiedLength == 0) // error case { throw new Win32Exception(); } } while((fileNameCopiedLength == bufferLength) || (fileNameCopiedLength == (bufferLength - 1))); // GetModuleFileName(Ex) documentation is unclear regarding whether the returned value // includes the null terminator or not thus we check both borderline cases. iconModuleFile = sb.ToString(); } // The following code is run only if we successfully retrieved the file name to retrieve the // icon from. If there was an exception in the code above the method would exit after // executing the finally block. // // ExtractIconEx is not necessiated in an if statement here, but doing so // keeps PreSharp happy since we are doing something with the return value. if ((iconModuleFile != String.Empty) && (UnsafeNativeMethods.ExtractIconEx(iconModuleFile, 0, ref hLargeIcon[0], ref hSmallIcon[0], 1) <= 0)) { return; } largeIconHandle = hLargeIcon[0]; smallIconHandle = hSmallIcon[0]; } // Inputs: // callingObj -- to be used in HandleRef // bf -- BitmapFrame to be used to create HICONs from // In/Out/ref: // largeIconHandle -- to return the large HICON created // smallIconHandle -- to return the small HICON created /// /// Critical: Since it calls CreateIconHandleFromBitmapFrame /// TAS: Since it creates icons with known h/w i.e. IconWidth/Height or SmallIconWidth/Height /// ///[SecurityCritical, SecurityTreatAsSafe] internal static void GetIconHandlesFromBitmapFrame(object callingObj, BitmapFrame bf, ref NativeMethods.IconHandle largeIconHandle, ref NativeMethods.IconHandle smallIconHandle) { Invariant.Assert(bf.Decoder != null, "_icon.Decoder should never be null"); Invariant.Assert(bf.Decoder.Frames != null, "_icon.Decoder.Frames should never be null"); // sysBitDepth is used to select the correct frame among the frames that came from // the ico file int sysBitDepth = IconHelper.GetSystemBitDepth(callingObj); int largeIconIndex = IconHelper.GetBestMatch(bf.Decoder.Frames, sysBitDepth, (int)SystemParameters.IconWidth, (int)SystemParameters.IconHeight); int smallIconIndex = IconHelper.GetBestMatch(bf.Decoder.Frames, sysBitDepth, (int)SystemParameters.SmallIconWidth, (int)SystemParameters.SmallIconHeight); largeIconHandle = IconHelper.CreateIconHandleFromBitmapFrame(bf.Decoder.Frames[largeIconIndex]); smallIconHandle = IconHelper.CreateIconHandleFromBitmapFrame(bf.Decoder.Frames[smallIconIndex]); } /// /// Critical: Since it calls CreateIconCursor which is SecurityCritical. CreateIconCursor is SecurityCritical b/c /// it creates bitmaps with the input w/h etc. That width/height is passed by this method using /// sourceBitmapFrame.Pixel[Width/Height] and is not guarded. /// ///// // Creates and HICON from a bitmap frame [SecurityCritical] private static NativeMethods.IconHandle CreateIconHandleFromBitmapFrame(BitmapFrame sourceBitmapFrame) { Invariant.Assert(sourceBitmapFrame != null, "sourceBitmapFrame cannot be null here"); BitmapSource bitmapSource = sourceBitmapFrame; PixelFormat reqPixelFormat = PixelFormats.Bgra32; if (bitmapSource.Format != reqPixelFormat) { bitmapSource = new FormatConvertedBitmap(bitmapSource, reqPixelFormat, null, 0.0); } // data used by CopyPixels int w = bitmapSource.PixelWidth; int h = bitmapSource.PixelHeight; int bpp = bitmapSource.Format.BitsPerPixel; // ensuring it is in 4 byte increments since we're dealing // with ARGB fromat int stride = (bpp * w + 31) / 32 * 4; int sizeCopyPixels = stride * h; byte[] xor = new byte[sizeCopyPixels]; bitmapSource.CopyPixels(xor, stride, 0); return CreateIconCursor(xor, w, h, 0, 0, true); } // Creates a 32 bit per pixel Icon or cursor. This code is moved from framework\ms\internal\ink\pencursormanager.cs /// /// Critical: Critical as this code create a DIB section and writes data to it /// [SecurityCritical] internal static NativeMethods.IconHandle CreateIconCursor( byte[] colorArray, int width, int height, int xHotspot, int yHotspot, bool isIcon) { NativeMethods.IconHandle returnHandle = new NativeMethods.IconHandle(); // 1. We are going to generate a WIN32 color bitmap which represents the color cursor. // 2. Then we need to create a monochrome bitmap which is used as the cursor mask. // 3. At last we create a WIN32 HICON from the above two bitmaps NativeMethods.BitmapHandle colorBitmap = null; NativeMethods.BitmapHandle maskBitmap = null; try { // 1) Create the color bitmap using colorArray // Fill in the header information NativeMethods.BITMAPINFO bi = new NativeMethods.BITMAPINFO( width, // width -height, // A negative value indicates the bitmap is top-down DIB 32 // biBitCount ); bi.bmiHeader_biCompression = NativeMethods.BI_RGB; IntPtr bits = IntPtr.Zero; colorBitmap = MS.Win32.UnsafeNativeMethods.CreateDIBSection( new HandleRef(null, IntPtr.Zero), // A device context. Pass null in if no DIB_PAL_COLORS is used. ref bi, // A BITMAPINFO structure which specifies the dimensions and colors. NativeMethods.DIB_RGB_COLORS, // Specifies the type of data contained in the bmiColors array member of the BITMAPINFO structure ref bits, // An out Pointer to a variable that receives a pointer to the location of the DIB bit values IntPtr.Zero, // Handle to a file-mapping object that the function will use to create the DIB. This parameter can be null. 0 // dwOffset. This value is ignored if hSection is NULL ); if ( colorBitmap.IsInvalid || bits == IntPtr.Zero) { // Note we will release the GDI resources in the finally block. return new NativeMethods.IconHandle(IntPtr.Zero); } // Copy the color bits to the win32 bitmap Marshal.Copy(colorArray, 0, bits, colorArray.Length); // 2) Now create the mask bitmap which is monochrome byte[] maskArray = GenerateMaskArray(width, height, colorArray); Invariant.Assert(maskArray != null); maskBitmap = UnsafeNativeMethods.CreateBitmap(width, height, 1, 1, maskArray); if ( maskBitmap.IsInvalid ) { // Note we will release the GDI resources in the finally block. return new NativeMethods.IconHandle(IntPtr.Zero); } // Now create HICON from two bitmaps. NativeMethods.ICONINFO iconInfo = new NativeMethods.ICONINFO(); iconInfo.fIcon = isIcon; // fIcon == ture means creating an Icon, otherwise Cursor iconInfo.xHotspot = xHotspot; iconInfo.yHotspot = yHotspot; iconInfo.hbmMask = maskBitmap; iconInfo.hbmColor = colorBitmap; returnHandle = UnsafeNativeMethods.CreateIconIndirect(iconInfo); if ( returnHandle.IsInvalid ) { // Note we will release the GDI resources in the finally block. return new NativeMethods.IconHandle(IntPtr.Zero); } } finally { if (colorBitmap != null) { colorBitmap.Dispose(); colorBitmap = null; } if (maskBitmap != null) { maskBitmap.Dispose(); maskBitmap = null; } } return returnHandle; } // generates the mask array for the input colorArray. // The mask array is 1 bpp private static byte[] GenerateMaskArray(int width, int height, byte[] colorArray) { int nCount = width * height; // NOTICE-2005/04/26-WAYNEZEN, // Check out the notes in CreateBitmap in MSDN. The scan line has to be aliged to WORD. int bytesPerScanLine = AlignToBytes(width, 2) / 8; byte[] bitsMask = new byte[bytesPerScanLine * height]; // We are scaning all pixels in color bitmap. // If the alpha value is 0, we should set the corresponding mask bit to 1. So the pixel will show // the screen pixel. Otherwise, we should set the mask bit to 0 which causes the cursor to display // the color bitmap pixel. for ( int i = 0; i < nCount; i++ ) { // Get the i-th pixel position (hPos, vPos) int hPos = i % width; int vPos = i / width; // For each byte in 2-bit color bitmap, the lowest the bit represents the right-most display pixel. // For example the bollow mask - // 1 1 1 0 0 0 0 1 // ^ ^ // offsetBit = 0x80 offsetBit = 0x01 int byteIndex = hPos / 8; byte offsetBit = (byte)( 0x80 >> ( hPos % 8 ) ); // Now we turn the mask on or off accordingly. if ( colorArray[i * 4 + 3] /* Alpha value since it's in Args32 Format */ == 0x00 ) { // Set the mask bit to 1. bitsMask[byteIndex + bytesPerScanLine * vPos] |= (byte)offsetBit; } else { // Reset the mask bit to 0 bitsMask[byteIndex + bytesPerScanLine * vPos] &= (byte)( ~offsetBit ); } // Since the scan line of the mask bitmap has to be aligned to word. We have set all padding bits to 1. // So the extra pixel can be seen through. if ( hPos == width - 1 && width == 8 ) { bitsMask[1 + bytesPerScanLine * vPos] = 0xff; } } return bitsMask; } ////// Calculate the bits count aligned to N-Byte based on the input count /// /// The original value /// N-Byte ///the nearest bit count which is aligned to N-Byte internal static int AlignToBytes(double original, int nBytesCount) { Debug.Assert(nBytesCount > 0, "The N-Byte has to be greater than 0!"); int nBitsCount = 8 << (nBytesCount - 1); return (((int)Math.Ceiling(original) + (nBitsCount - 1)) / nBitsCount) * nBitsCount; } // returns the current system bit depth -- incdicates the # of // colors that can be shown. // // Code taken from WinForms implementation of selecting // which icon frame to use ////// Critical: Calls GetDC, ReleaseDC and GetDeviceCaps that are marked SecurityCritical /// TreatAsSafe: It is okay to return the current system bit depth /// [SecurityCritical, SecurityTreatAsSafe] private static int GetSystemBitDepth(object callerObj) { int sysBitDepth = 0; HandleRef handleRefDC; HandleRef handleRefZero = new HandleRef(callerObj, IntPtr.Zero); IntPtr dc = UnsafeNativeMethods.GetDC(handleRefZero); handleRefDC = new HandleRef(callerObj, dc); sysBitDepth = UnsafeNativeMethods.GetDeviceCaps(handleRefDC, NativeMethods.BITSPIXEL); sysBitDepth *= UnsafeNativeMethods.GetDeviceCaps(handleRefDC, NativeMethods.PLANES); UnsafeNativeMethods.ReleaseDC(handleRefZero, handleRefDC); return sysBitDepth; } // returns the index of the frame that best matches the given width, height and the current // system bit depth. // // This code is taken from Winforms implementation of choosing the correct frame based on the // requirements. // // Windows rules for specifing an icon: // // 1. The icon with the closest size match. // 2. For matching sizes, the image with the closest bit depth. // 3. If there is no color depth match, the icon with the closest color depth that does not exceed the display. // 4. If all icon color depth > display, lowest color depth is chosen. // 5. color depth of > 8bpp are all equal. // 6. Never choose an 8bpp icon on an 8bpp system. // ////// Critical: Calls LinkDemand property BitsPerPixel /// TreatAsSafe: The bits per pixel info is not revealed/returned /// [SecurityCritical, SecurityTreatAsSafe] private static int GetBestMatch(ReadOnlyCollectionframes, int sysBitDepth, int width, int height) { Invariant.Assert(width != 0, "input param width should not be zero"); Invariant.Assert(height != 0, "input param height should not be zero"); // If the _sysBitDepth is 8, make it 4. Why? Because windows does not // choose a 256 color icon if the display is running in 256 color mode // because of palette flicker. // if (sysBitDepth == 8) { sysBitDepth = 4; } int bestWidth = 0; int bestHeight = 0; int bestBitDepth = 0; int bestIndex = 0; int bestDelta = 0; bool isBitmapIconDecoder = frames.Count > 0 && frames[0].Decoder is IconBitmapDecoder; // iterate each frame to see if this one is a better match than the // previous best match for (int i = 0; i < frames.Count; i++) { bool updateBestFit = false; int currentWidth = frames[i].PixelWidth; int currentHeight = frames[i].PixelHeight; int currentIconBitDepth = 0; // determine the bit-depth (# of colors) in the // current frame // // if the icon is palettized, Format.BitsPerPixel gives // the # of bits required to index into the palette (thus, // the # of colors in the palette). If it is a true // color icon, it gives the # of bits required to support // true colors. // For icons, get the Format from the Thumbnail rather than from the // BitmapFrame directly because the unmanaged icon decoder // converts every icon to 32-bit. Thumbnail.Format.BitsPerPixel // will give us the original bit depth. currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; // it looks like if nothing is specified at this point, bpp is 8... // straight from WinForm and Win32 if (currentIconBitDepth == 0) { currentIconBitDepth = 8; } // Windows rules for specifing an icon: // // 1. The icon with the closest size match. // 2. For matching sizes, the image with the closest bit depth. // 3. If there is no color depth match, the icon with the closest color depth that does not exceed the display. // 4. If all icon color depth > display, lowest color depth is chosen. // 5. color depth of > 8bpp are all equal. // 6. Never choose an 8bpp icon on an 8bpp system. // // for the first index, don't have anything to compare against so pick it if (i == 0) { updateBestFit = true; } else { int thisDelta = Math.Abs(currentWidth - width) + Math.Abs(currentHeight - height); if ((thisDelta < bestDelta) || (thisDelta == bestDelta && (currentIconBitDepth <= sysBitDepth && currentIconBitDepth > bestBitDepth || bestBitDepth > sysBitDepth && currentIconBitDepth < bestBitDepth))) { updateBestFit = true; } } if (updateBestFit) { bestWidth = currentWidth; bestHeight = currentHeight; bestBitDepth = currentIconBitDepth; bestIndex = i; bestDelta = Math.Abs(currentWidth - width) + Math.Abs(currentHeight - height); } } return bestIndex; } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HostingEnvironment.cs
- EntityObject.cs
- ISO2022Encoding.cs
- AccessDataSource.cs
- BamlLocalizableResourceKey.cs
- pingexception.cs
- CompilerScopeManager.cs
- FunctionImportMapping.cs
- SqlCacheDependencyDatabase.cs
- FormattedText.cs
- TextEmbeddedObject.cs
- DecodeHelper.cs
- AnnotationMap.cs
- Rfc2898DeriveBytes.cs
- TextContainerChangedEventArgs.cs
- BufferedMessageWriter.cs
- ContextProperty.cs
- DocumentXmlWriter.cs
- SerializationException.cs
- NamespaceDecl.cs
- PlatformNotSupportedException.cs
- JpegBitmapEncoder.cs
- SmtpNetworkElement.cs
- IntellisenseTextBox.cs
- ScriptResourceMapping.cs
- UIElementHelper.cs
- MonthChangedEventArgs.cs
- ComponentEditorPage.cs
- OracleParameterCollection.cs
- SqlMethodCallConverter.cs
- ProxySimple.cs
- XmlBindingWorker.cs
- ClockGroup.cs
- WindowsEditBox.cs
- SyndicationDeserializer.cs
- UrlAuthorizationModule.cs
- ISAPIApplicationHost.cs
- NullableDoubleSumAggregationOperator.cs
- DbParameterCollectionHelper.cs
- InkCollectionBehavior.cs
- OpenFileDialog.cs
- ACL.cs
- PreviewControlDesigner.cs
- PropertyDescriptorGridEntry.cs
- ErrorHandler.cs
- WsdlInspector.cs
- FloaterBaseParaClient.cs
- XPathAncestorIterator.cs
- DataService.cs
- WebPartRestoreVerb.cs
- DesignerActionList.cs
- ScrollBar.cs
- StatusBarPanelClickEvent.cs
- UriParserTemplates.cs
- FileLevelControlBuilderAttribute.cs
- WaitHandleCannotBeOpenedException.cs
- TickBar.cs
- GlobalEventManager.cs
- TransformedBitmap.cs
- ErrorWrapper.cs
- DbParameterHelper.cs
- ExpressionBuilder.cs
- ThaiBuddhistCalendar.cs
- HttpModuleAction.cs
- SchemaComplexType.cs
- MenuItem.cs
- DocumentAutomationPeer.cs
- CommandCollectionEditor.cs
- ConfigurationManagerHelper.cs
- VersionConverter.cs
- HttpWriter.cs
- ApplicationBuildProvider.cs
- UnauthorizedAccessException.cs
- GB18030Encoding.cs
- ProcessHostFactoryHelper.cs
- View.cs
- IdentityHolder.cs
- WebPartPersonalization.cs
- SafeSecurityHandles.cs
- SyndicationFeed.cs
- XamlTreeBuilderBamlRecordWriter.cs
- DrawingContextDrawingContextWalker.cs
- XmlSiteMapProvider.cs
- SQLUtility.cs
- TemplateLookupAction.cs
- AtomMaterializerLog.cs
- MembershipPasswordException.cs
- ListDictionaryInternal.cs
- HttpFileCollection.cs
- ComponentTray.cs
- PriorityBindingExpression.cs
- DataGridViewColumn.cs
- XmlSchemaDatatype.cs
- ExpressionPrefixAttribute.cs
- ObjectResult.cs
- ExcCanonicalXml.cs
- XamlStream.cs
- XmlAtomicValue.cs
- PenThreadWorker.cs
- MultiPartWriter.cs