0

There should be a way to correctly show the alpha channel of a BackgroundImage(32bpp) on a transparent Form by invoking user32/gdi32.dll. I want to show the borders of a white logo with glowing borders(blurred) in a transparent Form window.
In the past I only called user32.dll parameters to control the opacity of images in a transparent Form window, but my solution didn't support most alpha channel values of a .png image.
Now I included a new solution using Layered Windows in the code below, but it has no effect on the BackgroundImage. I assume what I tried yet to reference my BackgroundImage with the layered window code is not a valid method?

using System;
using System.IO;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

namespace BgImage32bppbgra
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            // controlled by LayeredWindows? // this.TransparencyKey = System.Drawing.SystemColors.Control;
            this.BackgroundImage = Image.FromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"bgIMG1\bgIMG1.png"));

            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.ShowInTaskbar = false;
            this.Load += BgImage32bppbgra_Load;
        }

        void BgImage32bppbgra_Load(object sender, EventArgs e)
        {
            this.Size = this.BackgroundImage.Size;
            this.TopMost = true;
        }

    /// --- Control Format32bppArgb transparent alpha channel with LayeredWindows ULW_ALPHA Blend

        protected override CreateParams CreateParams
        {
            get
            {
            // Add WS_EX_LAYERED extended style
            CreateParams createParams = base.CreateParams;
            if (!DesignMode)
            createParams.ExStyle |= WS_EX_LAYERED;
            return createParams;
            }
        }

        public void BG(Bitmap BackgroundImage)
        {
            BG(BackgroundImage, 255);
        }

        public void BG(Bitmap BackgroundImage, int opacity)
        {
            IntPtr screenDc = GetDC(IntPtr.Zero);
            IntPtr memDc = CreateCompatibleDC(screenDc);
            IntPtr hBitmap = IntPtr.Zero;
            IntPtr hOldBitmap = IntPtr.Zero;

            try
            {
            // Get handle to the new bitmap.
            hBitmap = BackgroundImage.GetHbitmap(Color.FromArgb(0));
            hOldBitmap = SelectObject(memDc, hBitmap);

            // params for layered window update
            Size newSize = new Size(BackgroundImage.Width, BackgroundImage.Height);
            Point sourceLocation = new Point(0, 0);
            Point newLocation = new Point(this.Left, this.Top);
            BLENDFUNCTION blend = new BLENDFUNCTION();
            blend.BlendOp = AC_SRC_OVER;
            blend.BlendFlags = 0;
            blend.SourceConstantAlpha = (byte)opacity;
            blend.AlphaFormat = AC_SRC_ALPHA;

            // layered window update
            UpdateLayeredWindow(this.Handle, screenDc, ref newLocation, ref newSize, memDc, ref sourceLocation, 0, ref blend, ULW_ALPHA);
              // this.Handle        = Handle to the layered window
              // screenDc           = Handle to the screen DC
              // ref newLocation    = New screen position of the layered window
              // ref newSize        = New size of the layered window
              // memDc              = Handle to the layered window surface DC
              // ref sourceLocation = Location of the layer in the DC
              // 0                  = Color key of the layered window
              // ref blend          = Transparency of the layered window
              // ULW_ALPHA          = Use blend as the blend function
            }
            finally
            {
            // release context
            ReleaseDC(IntPtr.Zero, screenDc);
            if (hBitmap != IntPtr.Zero)
            {
              SelectObject(memDc, hOldBitmap);
              DeleteObject(hBitmap);
            }
              DeleteDC(memDc);
            }
        }

        const Int32 WS_EX_LAYERED = 0x80000;
        const Int32 HTCAPTION = 0x02;
        const Int32 WM_NCHITTEST = 0x84;
        const Int32 ULW_ALPHA = 0x02;
        const byte AC_SRC_OVER = 0x00;
        const byte AC_SRC_ALPHA = 0x01;

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        struct BLENDFUNCTION
        {
            public byte BlendOp;
            public byte BlendFlags;
            public byte SourceConstantAlpha;
            public byte AlphaFormat;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        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", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr CreateCompatibleDC(IntPtr hDC);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr GetDC(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool DeleteDC(IntPtr hdc);

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool DeleteObject(IntPtr hObject);
    }
}
taraz
  • 117
  • 2
  • 8
  • This feature is covered by a popular [Codeproject.com project](https://www.codeproject.com/Articles/20758/Alpha-Blended-Windows-Forms). It is not otherwise very suitable for Winforms designs, you can't use a lot of the built-in controls anymore since you paint themselves with 24bpp GDI calls. WPF doesn't have a problem with it. – Hans Passant Nov 02 '19 at 13:59
  • OK thanks, nothing new for me though. I remember that I was looking at this project you mentioned, but it didn't help me much with referencing the GDI calls directly with the BackgroundImage. Could someone focus on the code in this topic if possible and tell me the problem? I came up with the below example mostly by reading topics here on stackoverflow. In theory the code below should contain everything to display my white BackgroundImage properly. I just need a valid method to reference everything with my image. – taraz Nov 02 '19 at 14:28

0 Answers0