Problem solve Get help with specific problems with your technologies, process and projects.

Painting in the non-client area

I would like to paint in the Windows non-client area (caption bar, etc.). It seems to me the user has to use API GDI functions only. I'm guessing the cause is: Microsft doesn't want the user violate the common GUI representation so they didn't give us .NET classes to let us perform this task easily. Is there any way (without using API GDI functions) to paint in the non-client area?
This is a two-part answer. To paint the non-client areas of a window, you will need to be able to subclass the window and capture the various window messages regarding that address non-client painting needs of the target window. If this is your window, you shouldn't have all that much trouble gaining access to the messages as you will just need to override the WndProc method of the window class. This is made terribly easy in .NET.

However, if you are trying to paint the non-client areas of windows that are out of process, and that you do not own, you will need to resort to the good old Windows API. You will need to install a global system hook, like the WH_GETMESSAGE hook and capture the messages as they arrive at the target window, and handle them yourself with your own painting code. You will need to resort to the GDI Api functions, or create a managed library using .NET classes to handle your drawing functions. So in that regard, yes you could do it without completely relying on the unmanaged GDI functions, but at some level you will need unmanaged functions to get the hooks installed.

The default windowing system will handle painting of all non-client areas without any help from you, and they handle quite a good deal of rather complex drawing. This is not for the slight of heart, and will be prone to very difficult debugging sessions if you go the route of hooking other windows. System wide or global hooks are notoriously hard to debug, and have extremely adverse effects on the system as a whole if not implemented properly and in a safe fashion. A very good example of a program suite that does just this is the line of products by Stardock. The Object desktop and Object bar apps implement system wide hooks to "skin" the look and feel of your windows by drawing the non-client areas of all the windows in the system. If you've ever ran programs like this you will know that they are often bug ridden and prone to strange crashes and errors.

You should also note that in order to implement the needed system wide hooks you will have to use a language that supports function exporting, such as C/C++ or Delphi. C#, VB, and others are not capable of building unmanaged dlls that export the needed functions to interface with the hooking subsystem at a global level in certain cases. You may want to argue that point, and yes I have seen implementations of app wide hooks written in managed code like C#, but for system wide hooks, you will take a severe performance hit as the dll containing the hooking functions will be loaded into every process in the system. This is known as dll injection.

Dll injection can be no big deal if done properly, but loading a managed dll that brings with it other runtimes, or that needs further just in time compiling is simply going to bog down the system, and never perform as well as a properly written unmanaged C dll of the same nature.

If you are serious about trying to create a non-client drawing application, weigh these topics I've laid out before you very carefully as you consider your options. Get familiar with C/C++ or Delphi, and learn your window messages first. Also, start out by just trying to override the default non-client painting of windows in your own process, thereby eliminating the need for hooks to get at the messages. Trying to learn this stuff in small increments will eventually save you a large headache and keep you on track to your final goal.

Good luck!

Dig Deeper on C# programming language

Start the conversation

Send me notifications when other members comment.

Please create a username to comment.