/// <summary> /// Creates a handle to a PARGB32 bitmap from an Icon. /// </summary> /// <param name="iconHandle">The handle to the icon.</param> /// <param name="iconSize">The iconSize of the icon.</param> /// <returns>A PARGB32 bitmap with the contents of the icon, including transparency.</returns> public static IntPtr CreatePARGB32HBitmap(IntPtr iconHandle, Size iconSize) { // Make sure we're ready for buffered painting. // TODO: Really we only need to do this once per thread, so an improvement // might be to have a manager create this as required per thread. Uxtheme.BufferedPaintInit(); // Create a compatible device context to work with. var deviceContextHandle = Gdi32.CreateCompatibleDC(IntPtr.Zero); if (deviceContextHandle == IntPtr.Zero) { return(IntPtr.Zero); } // Now create a 32 bit bitmap of the appropriate size, getting it's bits and handle. IntPtr bits; IntPtr hBitmap; if (!Create32BitHBITMAP(deviceContextHandle, iconSize, out bits, out hBitmap)) { Gdi32.DeleteDC(deviceContextHandle); return(IntPtr.Zero); } // Select the bitmap, keeping track of the old one. If this fails, // delete the device context and return a null handle. var oldBitmapHandle = Gdi32.SelectObject(deviceContextHandle, hBitmap); if (oldBitmapHandle == IntPtr.Zero) { Gdi32.DeleteDC(deviceContextHandle); return(IntPtr.Zero); } // Create paint params that represent our alpha blending. var bfAlpha = new BLENDFUNCTION { BlendOp = AC_SRC_OVER, BlendFlags = 0, SourceConstantAlpha = 255, AlphaFormat = AC_SRC_ALPHA }; var paintParams = new BP_PAINTPARAMS(); paintParams.cbSize = (uint)Marshal.SizeOf(paintParams); paintParams.dwFlags = BPPF_ERASE; paintParams.pBlendFunction = Marshal.AllocHGlobal(Marshal.SizeOf(bfAlpha)); Marshal.StructureToPtr(bfAlpha, paintParams.pBlendFunction, false); // Create the pointer that'll hold the device context to the buffer, set the icon rectangle. IntPtr bufferDeviceContextHandle; var iconRect = new RECT(0, 0, iconSize.Width, iconSize.Height); // Create a paint buffer handle. var paintBufferHandle = Uxtheme.BeginBufferedPaint(deviceContextHandle, ref iconRect, BP_BUFFERFORMAT.BPBF_DIB, ref paintParams, out bufferDeviceContextHandle); // Free the memory we allocated for the blend function. Marshal.FreeHGlobal(paintParams.pBlendFunction); // If we created a paint buffer successfully, we can draw the icon into it. if (paintBufferHandle != IntPtr.Zero) { // Try and draw the icon. if (Gdi32.DrawIconEx(bufferDeviceContextHandle, 0, 0, iconHandle, iconSize.Width, iconSize.Height, 0, IntPtr.Zero, (int)DI_NORMAL)) { // Now convert the buffer we've painted into PARGB32, meaning we'll end up // with a PARGB32 bitmap. ConvertBufferToPARGB32(paintBufferHandle, deviceContextHandle, iconHandle, iconSize); } // This will write the buffer contents to the destination bitmap. Uxtheme.EndBufferedPaint(paintBufferHandle, true); } // Select the old bitmpa and delete the device context. Gdi32.SelectObject(deviceContextHandle, oldBitmapHandle); Gdi32.DeleteDC(deviceContextHandle); // We're done with buffered painting. Uxtheme.BufferedPaintUnInit(); // Baddabing-baddabom, PARGB32. return(hBitmap); }