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(ReadOnlyCollection frames, 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(ReadOnlyCollection frames, 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
- Window.cs
- XmlBinaryReader.cs
- BamlRecordReader.cs
- SingleResultAttribute.cs
- ToolStripDropTargetManager.cs
- ResourceDictionaryCollection.cs
- BoolExpr.cs
- CopyNamespacesAction.cs
- DataGridViewComboBoxEditingControl.cs
- RtfToXamlReader.cs
- JsonServiceDocumentSerializer.cs
- WebPartConnectionCollection.cs
- CryptoConfig.cs
- safesecurityhelperavalon.cs
- DBCommand.cs
- ParameterToken.cs
- OleDbParameterCollection.cs
- EntityStoreSchemaFilterEntry.cs
- PassportAuthenticationEventArgs.cs
- InputProcessorProfiles.cs
- EntitySqlQueryBuilder.cs
- AudioSignalProblemOccurredEventArgs.cs
- CacheMemory.cs
- CodeStatement.cs
- XmlSchemaAll.cs
- NameTable.cs
- RelatedPropertyManager.cs
- SpinWait.cs
- ErrorWrapper.cs
- XpsFilter.cs
- EntityConnectionStringBuilderItem.cs
- TypographyProperties.cs
- ToolboxComponentsCreatingEventArgs.cs
- InputLanguageSource.cs
- XmlStreamStore.cs
- PrinterUnitConvert.cs
- TextFormatterImp.cs
- OutputCacheProfile.cs
- XmlValueConverter.cs
- PolicyLevel.cs
- DataGridState.cs
- DataSourceXmlElementAttribute.cs
- HtmlTableCell.cs
- LoadItemsEventArgs.cs
- XmlLinkedNode.cs
- DrawingGroupDrawingContext.cs
- OrthographicCamera.cs
- DataServiceExpressionVisitor.cs
- ConnectionManagementSection.cs
- UInt64.cs
- ByteRangeDownloader.cs
- CodeDomSerializerException.cs
- RtfToken.cs
- DebugHandleTracker.cs
- BufferedGraphicsManager.cs
- OneOfConst.cs
- EventLogPermissionAttribute.cs
- Condition.cs
- XmlHelper.cs
- TableCell.cs
- HtmlElement.cs
- MustUnderstandSoapException.cs
- ToolboxItemSnapLineBehavior.cs
- FaultContext.cs
- GroupPartitionExpr.cs
- DetailsViewPagerRow.cs
- QuestionEventArgs.cs
- SqlCommandBuilder.cs
- StateRuntime.cs
- COAUTHINFO.cs
- Int64Converter.cs
- SerializationEventsCache.cs
- FrameworkName.cs
- ContractListAdapter.cs
- RadioButton.cs
- XmlCharCheckingWriter.cs
- DocumentPage.cs
- AttributeTable.cs
- HScrollProperties.cs
- CategoryNameCollection.cs
- dbdatarecord.cs
- SqlDataReaderSmi.cs
- ClientOptions.cs
- DetailsViewPagerRow.cs
- HtmlGenericControl.cs
- Dynamic.cs
- HttpListenerRequestUriBuilder.cs
- XmlWhitespace.cs
- DataServiceEntityAttribute.cs
- ListBox.cs
- MsmqAppDomainProtocolHandler.cs
- Adorner.cs
- StylusCaptureWithinProperty.cs
- QilVisitor.cs
- VisualTreeUtils.cs
- TextWriterTraceListener.cs
- TextDecorations.cs
- HelpEvent.cs
- RoleGroup.cs
- SessionParameter.cs