public void SetBitmap(Bitmap bitmap, byte opacity) { bmpbase = bitmap.Clone() as Bitmap; if (HasChildren && DoDrawChildren) { DrawChildren(bmpbase); } /* * if (bitmap.PixelFormat != PixelFormat.Format32bppPArgb) * throw new ApplicationException("The bitmap must be 32ppp with alpha-channel."); */ // The ideia of this is very simple, // 1. Create a compatible DC with screen; // 2. Select the bitmap with 32bpp with alpha-channel in the compatible DC; // 3. Call the UpdateLayeredWindow. Bounds = new Rectangle(Location, bmpbase.Size); Size = bmpbase.Size; screenDc = User32.GetDC(this.Handle); // was IntPtr.Zero memDc = Gdi32.CreateCompatibleDC(screenDc); hBitmap = IntPtr.Zero; oldBitmap = IntPtr.Zero; //ClientSize = bitmap.Size; try { hBitmap = bmpbase.GetHbitmap(Color.FromArgb(0)); // Color.FromArgb(0);grab a GDI handle from this GDI+ bitmap oldBitmap = Gdi32.SelectObject(memDc, hBitmap); Size size = new Size(bmpbase.Width, bmpbase.Height); Point pointSource = new Point(0, 0); Point topPos = Location; Gdi32.BLENDFUNCTION blend = new Gdi32.BLENDFUNCTION(); blend.BlendOp = Gdi32.AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = opacity; blend.AlphaFormat = Gdi32.AC_SRC_ALPHA; User32.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, Gdi32.ULW_ALPHA); } finally { User32.ReleaseDC(IntPtr.Zero, screenDc); if (hBitmap != IntPtr.Zero) { Gdi32.SelectObject(memDc, oldBitmap); //Windows.DeleteObject(hBitmap); // The documentation says that we have to use the Windows.DeleteObject... but since there is no such method I use the normal DeleteObject from Win GDI and it's working fine without any resource leak. Gdi32.DeleteObject(hBitmap); } Gdi32.DeleteDC(memDc); } }
[DllImport(user32, ExactSpelling = true, SetLastError = true)] public static extern Bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, Int32 crKey, ref Gdi32.BLENDFUNCTION pblend, Gdi32.BlendMode dwFlags);