0

I'm developing an exe where I need to have a transparent background. I have made the image in Photoshop and it has all the neat stuff (shadows/opacity, reflection etc).

I have been struggling to get it working using TransparentColor+BackColor+Background Image, but I always end up with some pixel not being transparent. So I switched to UpdateLayeredWindow which works fine, but no control is being drawn now.

Here is some of my code

 private void Form1_Load(object sender, EventArgs e)
 {
 UpdateFormDisplay(this.BackgroundImage);
 }
 protected override void OnPaint(PaintEventArgs e)
 {
 UpdateFormDisplay(this.BackgroundImage);
 }
 public void UpdateFormDisplay(Image backgroundImage)
 {
 IntPtr screenDc = API.GetDC(IntPtr.Zero);
 IntPtr memDc = API.CreateCompatibleDC(screenDc);
 IntPtr hBitmap = IntPtr.Zero;
 IntPtr oldBitmap = IntPtr.Zero;
 try
 {
 //Display-image
 Bitmap bmp = new Bitmap(backgroundImage);
 hBitmap = bmp.GetHbitmap(Color.FromArgb(0)); //Set the fact that background is transparent
 oldBitmap = API.SelectObject(memDc, hBitmap);
 //Display-rectangle
 Size size = bmp.Size;
 Point pointSource = new Point(0, 0);
 Point topPos = new Point(this.Left, this.Top);
 //Set up blending options
 API.BLENDFUNCTION blend = new API.BLENDFUNCTION();
 blend.BlendOp = API.AC_SRC_OVER;
 blend.BlendFlags = 0;
 blend.SourceConstantAlpha = 255;
 blend.AlphaFormat = API.AC_SRC_ALPHA;
 API.UpdateLayeredWindow(this.Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, API.ULW_ALPHA);
 //Clean-up
 bmp.Dispose();
 API.ReleaseDC(IntPtr.Zero, screenDc);
 if (hBitmap != IntPtr.Zero)
 {
 API.SelectObject(memDc, oldBitmap);
 API.DeleteObject(hBitmap);
 }
 API.DeleteDC(memDc);
 }
 catch (Exception)
 {
 }
 }

Here are some images to explain better

enter image description here

enter image description here

Rohit Gupta
4,27723 gold badges36 silver badges47 bronze badges
asked Oct 25, 2013 at 13:45
13
  • You need to call base.OnPaint(e); from within your overrided OnPaint. Commented Oct 25, 2013 at 13:51
  • Did you call it after or before UpdateFormDisplay? Commented Oct 25, 2013 at 13:54
  • I tried both none seem to work Commented Oct 25, 2013 at 13:58
  • size should be the unmanaged struct SIZE. Commented Oct 25, 2013 at 14:02
  • 1
    @user2920222 try placing the UpdateFormDisplay in the OnPaintBackground instead? BTW, you shouldn't try customizing winforms too much, if you want a better solution, try using WPF. Commented Oct 25, 2013 at 14:28

1 Answer 1

1

If you want to use regular control inside layered window that uses UpdateLayeredWindow API, you need to override control's OnPaint method to redirect drawing to off-screen bitmap which you later use with UpdateLayeredWindow method to update window look.

If you don't want to dig into controls code, or don't have much custom made controls, WM_PRINT message could be used to force controls to paint themselves into provided device context. Classic window subclassing (SetWindowLong/GetWindowLong) for catching moments when controls invalidate themselves is useful, but may be slightly dangerous - you have to watch for callback chain.

Finally, you can use lightweight (windowless) controls. They use form message queue to receive events and draw themselves, so only form drawing code modifications are necessary. Some of standard winforms controls support this mode.

answered Oct 14, 2015 at 23:41
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.