Creating Non-Rectangular Splash Screen - using Alpha Channel

For one of my apps that I created and I will be posting that soon, I wanted to have a splash screen just like the common desktop apps have. So that began my quest for a non-rectangular window. Fortunately WPF does have the capability, but my first attempt was using a Win32 Form and it came out pretty well. It takes a 32 bit bitmap and displays it within a form. So depending on the shape of the image you have a window. So lets look at the code.

 class Splash : Form{public Splash(Bitmap bitmap){   // Window settings   this.TopMost = true;   this.ShowInTaskbar = false;   this.Size = bitmap.Size;   this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;   this.Show();    // Must be called before setting bitmap   this.SelectBitmap(bitmap);   this.BackColor = Color.Red;   this.Click += new EventHandler(Splash_Click);   this.MouseClick += new MouseEventHandler(Splash_MouseClick);}void Splash_MouseClick(object sender, MouseEventArgs e){   this.Close();}void Splash_Click(object sender, EventArgs e){}// Sets the current bitmappublic void SelectBitmap(Bitmap bitmap) {   // Does this bitmap contain an alpha channel?   if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)   {      throw new ApplicationException("The bitmap must be 32bpp with alpha-channel.");   }   // Get device contexts   IntPtr screenDc = APIHelp.GetDC(IntPtr.Zero);   IntPtr memDc = APIHelp.CreateCompatibleDC(screenDc);   IntPtr hBitmap = IntPtr.Zero;   IntPtr hOldBitmap = IntPtr.Zero;   try    {      // Get handle to the new bitmap and select it into the current device context      hBitmap = bitmap.GetHbitmap(Color.FromArgb(0));      hOldBitmap = APIHelp.SelectObject(memDc, hBitmap);      // Set parameters for layered window update      APIHelp.Size newSize = new APIHelp.Size(bitmap.Width, bitmap.Height); // Size window to match bitmap      APIHelp.Point sourceLocation = new APIHelp.Point(0, 0);      APIHelp.Point newLocation = new APIHelp.Point(this.Left, this.Top); // Same as this window      APIHelp.BLENDFUNCTION blend = new APIHelp.BLENDFUNCTION();      blend.BlendOp = APIHelp.AC_SRC_OVER; // Only works with a 32bpp bitmap      blend.BlendFlags = 0; // Always 0      blend.SourceConstantAlpha = 255; // Set to 255 for per-pixel alpha values      blend.AlphaFormat = APIHelp.AC_SRC_ALPHA; // Only works when the bitmap contains an alpha channel      // Update the window      APIHelp.UpdateLayeredWindow(Handle, screenDc, ref newLocation, ref newSize,         memDc, ref sourceLocation, 0, ref blend, APIHelp.ULW_ALPHA);   }   finally    {      // Release device context      APIHelp.ReleaseDC(IntPtr.Zero, screenDc);      if (hBitmap != IntPtr.Zero)       {         APIHelp.SelectObject(memDc, hOldBitmap);         APIHelp.DeleteObject(hBitmap); // Remove bitmap resources      }      APIHelp.DeleteDC(memDc);   }}protected override CreateParams CreateParams {   get    {      // Add the layered extended style (WS_EX_LAYERED) to this window      CreateParams createParams = base.CreateParams;      createParams.ExStyle |= APIHelp.WS_EX_LAYERED;      return createParams;   }}// Let Windows drag this window for us (thinks its hitting the title bar of the window)protected override void WndProc(ref Message message) {   if (message.Msg == APIHelp.WM_NCHITTEST)    {      // Tell Windows that the user is on the title bar (caption)      message.Result= (IntPtr)APIHelp.HTCAPTION;   }   else   {      base.WndProc(ref message);   }}} // Class to assist with Win32 API callsclass APIHelp {// Required constantspublic const Int32 WS_EX_LAYERED = 0x80000;public const Int32 HTCAPTION = 0x02;public const Int32 WM_NCHITTEST = 0x84;public const Int32 ULW_ALPHA = 0x02;public const byte AC_SRC_OVER = 0x00;public const byte AC_SRC_ALPHA = 0x01; public enum Bool {   False = 0,   True = 1} [StructLayout(LayoutKind.Sequential)]public struct Point {   public Int32 x;   public Int32 y;   public Point(Int32 x, Int32 y) { this.x = x; this.y = y; }} [StructLayout(LayoutKind.Sequential)]public struct Size {   public Int32 cx;   public Int32 cy;   public Size(Int32 cx, Int32 cy) { this.cx = cx; this.cy = cy; }} [StructLayout(LayoutKind.Sequential, Pack = 1)]struct ARGB {   public byte Blue;   public byte Green;   public byte Red;   public byte Alpha;} [StructLayout(LayoutKind.Sequential, Pack = 1)]public struct BLENDFUNCTION {   public byte BlendOp;   public byte BlendFlags;   public byte SourceConstantAlpha;   public byte AlphaFormat;} [DllImport("user32.dll", 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 BLENDFUNCTION pblend, Int32 dwFlags);[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]public static extern IntPtr CreateCompatibleDC(IntPtr hDC);[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]public static extern IntPtr GetDC(IntPtr hWnd);[DllImport("user32.dll", ExactSpelling = true)]public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]public static extern Bool DeleteDC(IntPtr hdc);[DllImport("gdi32.dll", ExactSpelling = true)]public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]public static extern Bool DeleteObject(IntPtr hObject);}

The code has comments which are self explanatory. Its much simpler in Avalon but before delving into it, I wanted to show how it can be possibly done using alpha channels.

PS:the above code is taken from one of the bloggers. Cant seem to remember the person.. Blame my memory .. ;)