I need a fast way to draw an overlay on a screen with transparency support. I've done a lot of searching and found one potential solution (which has its own problems) and another solution that does not fit my requirements; specifically transparency support.
I'll start with the latter and then touch on the former.
Solution 1
Using a borderless form with a TransparencyKey, this is one of the most recommended solutions I've found and the least helpful.
This solution works by having a new Form, have it borderless, set the background to something like Colour.White
and set the TransparencyKey
to the same colour, have it be fullscreen and topmost, and maybe set some other options to have it act invisible to the mouse and keyboard.
The problem with this solution is that it does not support transparency; it will only 'knock out' colours exactly the same as the TransparencyKey
and as such anything with even the slightest difference will be shown throwing the idea of having translucent objects on the screen out the window.
Solution 2
Use P/Invoke and GDI+ to get (GetDC
& Graphics.FromHdc
), actually draw to, and then release (ReleaseDC
) the desktop.
For what it does it works quite well, unfortunately however there are some problems.
First of all; calling it once will quite obviously only draw it once and as such if the screen refreshes at all after being drawn it will disappear, I do not understand how to fix this and if this is the best solution I'll most definitely need help with this issue.
Second of all; GDI+ is insanely slow with this method using a translucent Brush and FillRectangle
and I honestly can't blame it, however I require it to be done quite fast; a requirement which GDI+ apparently cannot fufill.
In conclusion; I require a method of drawing an overlay over a screen that has transparency support, if the second method is the method I should be using how can I draw with a translucent brush fast enough that it's not a problem and how would I have it update so that it wont disappear after the screen refreshes, and if it's not the method I should be using please specify what method I should be using.
The solution is not in your list. Solution #3 is to use UpdateLayeredWindow with a bitmap with an alpha channel. When updating the bitmap, you must paint only the areas that need updating, and use the fastest bitmap format (pre-multiplied ARBG). Here is an example of some graphics I created using solution #2, which seems fast enough: Translucent clock and calculator
Here are some more details. We have a class called GdiBuffer, containing a GDI handle field and a DC handle field (both encapsulated in classes, GdiHandle and DCHandle). It is initialized in the following way:
The Bitmap is a GDI+ bitmap. This means we _deviceContext is now representing both the GDI+ bitmap, and something we can use in GDI.
When it is time to update the screen, we pass a Form into the method in GdiBuffer that can update the screen:
To use our GdiBuffer internally:
The _graphics field is where we actually draw.