I have split the code into two primary classes. First one, FormWithNonClientArea, extends the standard Form class by adding support for non-client area messages (more on this shortly) and can be uses for various scenarios. Second one, CustomBorderForm, utilizes these messages and represents a base class for drawing graphical borders composed of several bitmap parts. It also draws a form header including icon, text and form buttons (more on this later). This way I can separate dirty plumbing required for enabling non-client drawing and actual drawing of the graphical elements. So lets see how it works.

Extending Form with Non-Client Area Painting

Each window we see on screen (be it a Form, UserControl or any other Control) is described by two rectangles: the bounds of the window and it's client area. Bounds specify the location and size of the window as a whole while the client area specifies the region inside the window that is available for client controls. By default Windows Forms allows us to access only the client part of the window. To gain access to the non-client part we need to intercept some additional windows messages. We can do this by overriding the WndProc message loop. For each message I defined dedicated method, so my WndProc method only redirects calls to this methods.

Positioning the Client Ractangle

If we are going to draw our custom borders good chances are that their size and proportions will differ from the standard ones. To correct this we need to specify a new client rectangle for the window. This is done in the WM_NCCALCSIZE message. This message can be raised in two ways. When WParam is equal to zero the LParam points to RECT structure with window bound that we should adjust to proposed client ractangle. Alternatively, when WParam value is one the LParam points to NCCALCSIZE_PARAMS strucure allowing to move the existing client area inside the window. For our purpose we will simply adjust the proposed rectangle to required coordinates.

Note that this method calls a virtual OnNonClientAreaCalcSize method taking a Rectangle that you can overwrite in your code.

Painting the non-client area

The main message responsible for painting the non-client area is the WM_NCPAINT message. The WParam for this message contains the handle to a clip region or 1 if entire window should be repainted. So to paint anything we only need to create a Graphics object from the window handle and use it as we would in the typical OnPaint method.

Now is the tricky part; If you leave it that way you quickly notice that on some occasions you still get some parts of the standard border painted over your brand new framing. That indicates that there are some other messages that cause painting in the non-client area.

The first one is the WM_SETTEXT message that transports new title for the window (stored as Text property on the Form). Apparently it also repaints the border in order to update the title bar. Of course, we still want to send out the new title so we need to pass the message to the DefWndProc method. But we will handle painting on our own.

The second culprit happens to be the WM_ACTIVATE message that is responsible for switching the window active state. Window is active when it is the top level window that you interact with and it has different border to show that. When you switch to another window the first one updates its border to indicate that it has lost the focus. The WParam of this messages holds the window active state and is 1 when border should be drawn as active and zero otherwise. We will handle the painting and skip to the DefWndProc only when window is minimized.

I agree that this is big design inconsequence and all painting should be done in one place but it is around for a long time and we must live with it. Now that we cleared this out we can get down to actual painting.

The most important thing here is to get the correct hDC handle and we wil use native GetDCEx function for that. It takes three parameters: the window handle, the clip region and option. First two we got already from the messages. As for the options the MSDN states that only WINDOW and INTERSECTRGN are needed, but other sources confirm that CACHE is required on Win9x and you need CLIPSIBLINGS to prevent painting on overlapping windows.

If we get a valid hDC we can quickly create the Graphics object using Graphics.FromHdc() method, paint our stuff and dispose it. Here it is worth noting that when we dispose a Graphics instance it will also automatically free the hDC so there is no need for calling the ReleaseDC manually.

At the begining ot this method I use native GetWindowRect function to get the correct coordinates of the window. At this point the Bounds property is not accurate and especially during resizing seems to always stay behind. Next I validate window size as obviously no painting is needed when it is empty. The actual painting should be done in the virtual OnNonClientAreaPaint method.

Removing flicker with double-buffering

Unfortunatelly painting this way is fine only as long as you don't try to resize the window. When you do you will see very unpleasant flickering. Totally not cool. We need to apply double-buffering in order to fix it and I just found a cool mechanism in .NET Framework that should help with that.

There is a class called a BufferedGraphics buried in the System.Drawing namespace. It's the same class that is used when you set DoubleBuffered flag on any control. (To be honest I haven't checked if this class existed prior to .NET 2.0). There is also a factory class called BufferedGraphicsManager that we use to create such object. The Allocate method takes either an existing Graphics object or the targetDC handle. Having an instance of BufferedGraphics we obtain a real Graphics object, do the painting as usual, and then call the Render method to draw the buffered image to the screen (presumably using some form of bit blitting).

Whew, the above code looks to simple to possibly work. And indeed it doesn't. It all looks good when the window stays active, but when it gets covered by another window suddenly all of the client area gets painted in black. So there is something missing, like establishing a clip region to exclude this area from bliting. I hope that someone smarter then me could help and figure out a better way to fix this.

A not so scary ghost story

There are two more things that need to be done in order to get perfectly drawn custom border. First thing is to completely get rid of XP themes on our window. We have already taken over all painting but when themes are turned on they also might affect other aspects of window. For example thay would likely change the window shape to something non-rectangular (like adding round corners) and obviously we want to prevent this. We will use the SetWindowTheme native function with empty parameters to completely disable theming on the current window. Note however that this will only affect the window itself so you don't need to worry that you loose theming on the control placed in it's content area.

As for the second thing, I wonder how many of you heard about windows ghosting feature? I didn't know about it until recently. Quoting MSDN "Window ghosting is a Windows Manager feature that lets the user minimize, move, or close the main window of an application that is not responding." Basically when the process doesn't respond to window messages within designeted time (hangs) the Windows Manager will finally loose patience and draw the window frame by itself allowing the user to do something with the application. This can hapen when the process executes some long running task (like query or complex processing) in the same thread as the windows message loop.

In theory for a well written application that delegates all heavy processing to background workers this should never happen. But I haven't written such application yet. This feature can be disabled using DisableWindowGhosting native function but only for the entire application. Now it's your decision whether you want to present the users with consistent user experience even on these odd occasions or you can cope with some occasional quirks but let the user control the situation all the time.

Handling mouse actions

After we have positioned and painted the border it's time to make it behave like the normal one does. One such behavior is indicating whether the form is sizable when mouse moves on the border. Another is that when we double-click on the title bar the windows maximizes or restores respectively. And of course the window recognizes when mouse is over or user clicks on the form buttons (minimize, maximize, close, and help). To make this work properly we need to tell the border how all these elements are positioned on our form. This is done in the WM_NCHITTEST message. The LParam holds the screen coordinates of current mouse position. As a result we should return a hit-test code telling the system what part of window the mouse is over.

When mouse is on the border edge and the window is resizable we should return values like HTLEFT, HTTOPRIGHT or HTBOTTOM . When mosue is over one of the window buttons we return code for that buton (HTMINBUTTON, HTMAXBUTTON, HTCLOSE). To indicate that mouse hovers over the title bar we can pass the HTCAPTION value. Finally when mouse is inside the client rectangle we should return the HTCLIENT value.

Capturing mouse move is quite simple. The WM_NCMOUSEMOVE message delivers new mouse position each time it is moved over the non client area. Here, I am using the standard MouseMoveEventArgs to pass this to the virtual method.

To capture mouse click we should intercept the WM_NCLBUTTONDOWN and WM_NCLBUTTONUP messages, for the left mouse button (and similar for the other two). For all these messages the WParam contains the hit-test value that we returned when processing the WM_NCHITTEST message, and the LParam contains the screen coordinates of the mouse cursor. I'm using extended NonClientMouseEventArgs to pass all this information to the virtual method. In return the method should set the Handled flag to indicate that our application processed this message.

I started something like this a while back and never finished it. Just thought I would point out one small problem. Set the forms Opacity to less than 100% and the left and bottom edges are not drawn.

This can be overcome by creating a compatible bitmap and using bitblt via interop to draw the window to the bitmap update and then bitblt back to the window, instead of using GDI+ on a graphics object created from the Window DC.

This is awesome thanks for posting it... I've made some changes to put it in my .net 1.1 forms... Lovin it... I'm gonna try to figure out the problem with the double buffering to... Awesome work though... thanks again

then basically the OnNonClientAreaPaintBackground, and foreground paint to offScreenDC instead of e.Graphics... when they finish you paint the offScreenBmp and you got yourself easy double buffering without having to use win32 dll's...

I'm pretty sure that going the BitBlt route would be faster, but I see no effect on my application and it works beautifully...

Also of note I noticed that the method WmNCCalcSize when the NativeMethods.FALSE, was better left commented out because otherwise my version in .net 1.1 seemed to draw strange... it kept changing offsets depending on whethere that was true or false, so I just commented it out since the only time i could see it was being called was on the initial load... maybe that's a bad idea I don't really know, but for my .net 1.1 version I had to do it....

Thank you all for your kind comments. Mick I think I've seen your examples and I'm aware of this problem. I just didn't needed semi-transparent window yet ;-)

As for double-bufferring I guess it has to be done with the Bitblt and thats why I used the BufferedGraphics class which should encapsulate this. However this works strange so I have do this manually. Can anyone help with that?

I have just finished porting this to .NET 1.x. As expected there werent many problems. The most troubles I had with resource files (I love the new resource handling tools in VS2005). I have published updated release on projectdistributor. Please read notes at the end of second part of the article for some details.

Well I figured out why it was acting funny using the non BitBlt double buffer... that code works you still need the InvalidateWindow() method call though... but it gets rid of the flicker of the non client area...

Sorry for the double post but I just checked out the issue Mick talked about and with the non BitBlt double buffering I put in mine, it still draws all the borders just fine with lower than 100% opacity... the non buffered is another story...

I cleaned up my double buffering so you don't have to do all that overriding BS... here's the snippet I got it from another object I'm using in my form... only problem now is that the non client area is double buffered... but for some reason when things are dragged over the client area it messes up horribly drawing what has been dragged over it...

Just running some more tests on this, and double buffered or not, there is something missing in the code to redraw the client area when it needs to be invalidated while a window is dragged over it... the double buffer I just posted above does get rid of the flicker of the text, etc. in the titlebar and borders, but if anyone is going to use this as is, they better keep it with TopMost = true... I'd love to find someway to fix this I just don't even know what causes it...

alright the code above doesn't work right either.... I changed it to this and it works... there is probably a way to determine the region of the form that needs to be invalidated but this is a crude way of making the controls repaint when something is dragged over the custom form, border or not...

only way I know of fixing the window dragged over the top issue... and it still has a set back because if the form doesn't have any controls on it, the actual form itself still paints what was dragged over it... so hell I'm just gonna make sure I fill my forms with a panel ;)

I don't know if I've helped here or not but I hope I haven't been a pest

Does anyone have vb.net version of this? I have successfully converted the project with the conversion tool and fixed the compile errors, but left some things unfunctional (borders not painting). Caption bar does paint. Also if you add a menu control to the form it does not show at runtime, and paints incorrectly in design time.

Sorry Enes, to keep you waiting (I had vacations). I haven't tried this on VB and can't help you much as I don't know much of this language. The only thing I can suggest is that you compile the project in C# and then reference the assembly in your VB project. You could than just change inheritance parent of your forms.

Most excellent source! You have saved me HOURS of work. I do, however, have something to point out: When you disable a caption button (say the maximize button) the event still fires when you click it. I simpy added the following code to the DepressButton function:

Hi Will,
I'm glad that my article could help you, and many others. I still intend to fix and update the sources (I need to find the cure for transparancy and double-buffering issues) and finish the article but right now my day-to-day schadule is packed to its limits. Still thanks for pointing the error. If you find anything else please send it here. I'm also curious what use have you found to this code and would be happy if you could send me some screenshots.

After playing with it for a bit, (and failing) I've decided to simply go the BitBlt route. This fixes all previously mentioned clipping and transparency issues on v1.1 for me.(current application hasn't been ported to 2.0 yet.) The code update doesn't take much, just a few additions to the NativeMethods, and yet another version of the PaintNonClientArea event-raising block. Here is my quicky PaintNonClientArea code to get it started: [NativeMethod additions should be easy: copy n paste from msdn :)]

Not much to it eh? Just keep in mind to add error trapping for those interops. Probably gonna tcf that block.

I'm currently using your class to *skin* my secure chat app - and since it's in pieces at the moment I don't have any screen shots for ya. [Should be done in a week] Although, once I'm done - your class will get some solid alpha testing while I alpha the new version. ha. I'll post feedback as it develops.

Thanks for the update. I should try this as the time allows. This code is already heavy tested for several months in the business project I work on. Till now it didn't cause any unexpected errors or memory leaks. You should be aware however that it doesn't work well on Windows 2003 Server (it doesn't crash but the border simply don't draw). I don't expect my customers to use it on this platform but you should at least provide some fallback solution (turn on the standard borders). Anyway, let me know if you have any other suggestions or requirements.

Awsome stuff, I've been playing with it all night and see a lot of potential for it with my stuff. Hopefully we can get around that Windows 2003 Server issue though :)

Anyway, I have a problem I haven't been able to get around with the Maximize/Restore button. Try Maximize and Restore back-and-forth; the Restore button doesn't show like it should. this.WindowState keeps returning Normal...Or is it just me?

Actually, I think I haven't tested the code that changes appearance of maximize/restore button as I didn't have alternative graphics for it in my skin.

The problem was that I was checking the WindowsState during NC_CALCSIZE message and it was still in Normal state when Window was being maximized. To fix this I added yet another handling method for the WM_SYSCOMMAND message. Now I switch the button appearances on the SC_MAXIMIZE and SC_RESTORE commands. Strangely it occurs that when you double-click on the title bar the codes are slightly different.

Anyway, I just uploaded the updated code to ProjectDistributor. It also includes the solution to double-buffering issues provided by Codeable. Big thanks to all of you for helping me out with this project.

Andrew,
Have you actually tested this on Windows Vista! ? I think I read somewhere that it is bassed on Windows 2003 kernel so there might be problems with that as well. For now it is safe to assume it only works on Windows XP. However, I think it could work on Windows 2000 as well.

Hey - I was lucky enough to get the chance to look at this again. Have you implemented a custom MainMenu yet? Or are you working on one? I've managed to get the MainMenu bar working (draws, and supports skin switching on/off) with a bit of hacky gdi and extending the client area. It's only my development build though, and needs to be done properly (with bitmap support.. etc etc) -- I just don't want to write the additional code if it has already been done for this class. And if it hasn't - no prob. I'll get right on it. I'll be watchin' for a comment.

I've been trying to port this to vb.net version, and now i'm just stuck with borders not always painting(mostly when resizing the form, borders just stay in the client area and don't resize with the form). Since i compared class by class, i couldn't find any difference, except that i don't know in C# what (IntPtr)1 is. Here's a sub as an example:

A small fix: when you press the resize,close or minimize button and move the mouse while holding the button it causes the window to resize,close or minimize respectively. Also when you hold one of the buttons the cpu spikes to 100%, and we don't want this.
Here's the fix for both of these:
1. add done = false; to depressbutton function

Codeable,
No, I haven't done any work with menus. In my current project we don't use traditional menus so there was no need to customize them. But you are right that that this would be huge benefit for anyone to make them consistent with borders and other screen elements. If you have started any work on this and would like to share it I would be happy to include it in this project and help you make them work. I think that we should include support for customized statusbar as well.

Enes M.,
Thanks for your feedback and bug fixes. I will test this out and include with the next release. As for the IntPtr it is "A platform-specific type that is used to represent a pointer or a handle." In C# it can be cast to and from an integer. But it should be all the same if use a constructor like you did. Do you still have problems in VB? You can always try to compile this in C# and reference in your VB project as external assembly. Then you can override the CustomDrawnForm class as needed.

I guess this is XP only otherwise. That might change though considering that it "sorta' rendered", meaning that there is something there trying. Still pretty cool to have as an XP feature to my software either way!

Wow this, like many others, has saved me a bunch of time. This really isnt my area of expertise so it has been a learning curve for me which is great. The main problem I'm having is probably really trivial as well. When I change the img's used for the borders they dont change the application. Sounds fairly silly, I know. Even If I remove them all together, its still the original appearence, not even a error. Any suggestions would be muchly appreciated.

Alrighty :D, i fixed my simple little problem. It was my Resource1.resx file, I just recreated it using the link on the next page. Hopefully I can contribute to this little project as much as everyone else. I know i'll be ripping through the code here in the next little while.

I'm glad the code was useful for you. At first I though your problem was that you can't change the form's appearance at runtime. I never though this should be needed so the Appearance is read only once when form is constructed. But if you think such feature would be required we can try to add it. Now, I don't fully understand what your problem was and how you fixed. Could you explain?

I'm really sorry but I still haven't got time to take a look at your code (I have hard time at work and was out of town for the weekend), but you are at top of my personal to-do list. I will try to include your code in next release.

I was trying to replace the images with my own. But the Resources1.resx was not updating. So It was still using the images you sent with your code. I fixed this by recreating the .resx file manualy using the tools you mentioned on the next page.

I think I will see if there is a way to tap into the Form's implementation of the main menu and shift it south a bit. It would be much nicer to simply override the onpaint methods of the menu's and items. Then you could include a CustomMenuItem object and have this thing be the "Class to rule them all" haha.

Success! I was able to move the windows generated MainMenu down to the "appropriate" area. I did it in a spike, so no code samples yet (but you won't believe how easy it was). I will write it up this weekend using performance friendly customdraw instead of the hacky virtualmenuitems. Who need sleep!?

Hi,
I am currently trying as a fun project more then anything else to code a 'areo glass' effect around the NC Area of a window, much like in the upcoming vista.
The goal is to use per pixel alpha blended bitmaps. First attemps show them as black, and not showing the background at all (go figure). Using UpdateLayeredWindow will allow us to update the regions we want to paint. The only problem with this apart from effeciency is the fact that you have to set the Extended style of the form to
cp.ExStyle |= 0x00080000; // WS_EX_LAYERED
This will prevent the rest of the form from painting.

This is where I am stuck right now, if anyone has any comments or wishes to see the source that I currently have, drop me a mail at tim.akehurst@noos.fr.

Doing this under XP/2000 is possible. . WindowsBlinds will support the glass look and feel for Windows XP in their next release.

I've read your article and you mentioned a problem with the BufferedGraphics object:

"...It all looks good when the window stays active, but when it gets covered by another window suddenly all of the client area gets painted in black. So there is something missing, like establishing a clip region to exclude this area from bliting. I hope that someone smarter then me could help and figure out a better way to fix this."

I don't know whether you've resolved this issue yet. In any way, I think you are refering to an issue I've also stumbled upon. BufferedGraphics.Render uses BitBlt internally, which ignores GDI+ clipping regions. I've filed this issue on ProductSupport:

Hi, I have strange problem with your sample code... when I rebuild it while the Design of the DemoForm.cs is open, it changes its size! Something adds some width and height to the form. I am using VS 2005 with .net 2.0

This is an excellent job, and has really helped me develop the custom look that my bosses require. Unfortunately, I have run into a strange problem that only occurs when setting the Theme in windows to be the Classic Windows theme. If this is set, and you disable custom borders, and then reenable them, the behavior shows up. What happens is that the default windows controls are drawn over the custom controls in the upper-right corner of the screen when you move the mouse over the resizable borders. Also, if you have a larger than normal title bar, a line is drawn where the bottom of the default titlebar would be. The controls are also drawn on minimize/maximize. I ran Spy++ on the form, and it seems that the windows controls are being drawn in WM_SETCURSOR when the mouse is moved over the border, but it must be drawn in WM_MAXIMIZE and WM_RESTORE for the other two messages. I am running VS 2005, btw.

Abe,
Thanks for the excellent bug report. Following your instructions I was able to reproduce the problem. However currently I'm working on another projects and it would be hard for me to find time to look into this one. As I wrote in the article Windows tries to optimize paintinc non-client area and there are some undocumented places outside WM_NCPAINT where parts of borders are painted. I need to capture all these massages and handle on my own instead of DefProc.

Just Confirmed that the form resize problme does not happen in VS2003. There must be something VS2005 is doing in design mode to show the cool new non-client stuff that also causes the size of form to change. Too bad. If anyone finds a fix for this please post...

Hi
I tried the demo and it is awsome.
Actually I wanted to ask if you were aware of the redimensioning problem ocuring when you press on the Taskbar's application Icon several time.
In fact if you try to do so you'll see the form size increasing, and I couldn't figure out why.
Do you have some clue about the reason?

Regarding 'redimensioning' I'm only aware of some problems when designing forms in VS 2005. Please tell me more of the issue: what .NET and Windows version you use, and do you use XP themes or windows classic.

I use XP themes and Visual Studio 2005.
But it isn't happening at design time but at run time:
if I click on the icon in the task bar to reduce or restor the app window, and I repeat the operation several time, the window size increase.
I tried to modify your source code to set the caption height to SystemInformation.CaptionHeight to see if something would change, but without any success.

Hi all,
In case you haven't noticed I just uploaded new release. It fixed several issues reported above (yes, it fixes the redmiensioning bug in designer). So go ahead, download it, and let me know what else needs to be done here.

Hi szymon, great work!
I have a strange problem. When i use your form as mdi child, it seems that i can't touch the header of these forms, i can't move them, minimize or maximize them or even close them.

The only thing it does is when i am at the 3/4 (x-coordinate) at the header (just before the three buttons) the cursor transforms from pointer to WE-resizer...

But I found a littile bit of problem when designing windows form inheriting your class in .net 1.1.

When I add a mainMenu item it get rendered a liitle bit lower of its usual position, just underneath the titlebar! Most amazing thing is that when I run it the menu completely disappeared from the form though it is visible in design mode!!!!

What does the problem lies beneath? PLease any one give me any idea to solve it.
my email: anidotnet@gmail.com

Wing,
This project was orignaly written for .NET 2.0 and I haven't encountered any issues with the new ToolStripMenus. So one solution I recommend is to migrate to 2.0. However, some time ago I recived code for improved menus from Codeable (see discussion above). I haven't included this in my project but if you send me your email I can post it for you.

Some of you have had the same problem as me, and that is the fact that when using Mdi forms the child form seems to lose all of the form resize functionality and the control buttons do not work.

After a little delving into this code, and learning far more about Windows Message loops and wndproc than I ever wanted to know I have found the problem.

The problem is that the code takes the current screen position and then translate that into the current window position, this works for all normal forms, however, it does not work for anything inside the mdi container, as the co-ordinate system is all wrong.

Here is some code that can be added, my project has some panels and menus and stuff, so the locations of these have to be taken into account, and I have not fully worked out how I am going to implement this yet, so this is just a hack!!!

public Point PointToWindow(Point screenPoint)
{
if(this.MdiParent != null)
{
//work out the area

When in DesignMode you set the WindowState on "Maximized"
the Restore button is not shown (still Maximize).
I have tryed past in Load event this.WindowState = FormWindowState.Maximized; and this is the same problem. Can You Fix it?

Hi,
Your last release is not Compleable. When you unzip the file to Directotry -> open The solution -> Build Solution - make Error "Resourfe file Properties\Resources.resx" cannot be found.

And I have found a new bug:
Let Find "//TODO: should I also Release the hDC??"
the answer is YES You must in both cases (doubleBufer with/without). This bug is nice to see in TaskManager:
when you let show the GDI object column, you can see that the number of GDI object stil increased while repainting (and while mouseMoving over caption buttons).
Whe you use the "ReleaseDC" all work fine.

This release also introduces form style librares (aka skin files) and built-in form style editor. Hopefuly this weekend I should write an article explaining how it works. But I'm sure you will figure this out easily and I hope you like.

First of all I would like to thank you Szymon für your great solution. I've learned much more from it than I have expected.

I know, you are discussing about the .net2.0 version of this solution. But I only have the .net1.1 available, so I have to use Codeables menu implementation if I want to have a MainMenu in my form. But I have a big problem with it. While the user32 function TrackMenuPoupEx tracks the mouse movement on the MainMenu, it throws an NullReferenceException after a while when moving between serveral menu items. Marshal.GetLastWin32Error says: Win32Error 6 - Which means "The handle is invalid". After this Exception the MainManu only pops up again when I restart the application.

I've experienced this error on different operating systems and am not able to fix it, because I do not have the skills like you and do not know how to deal with the win32 api.

If anyone has the same error, I would be happy to get some support from you. I'll also be glad with a workaround or any hint to more information about that issue.

Long time no post here! I haven't worked on this in a while, I do have a fully functional class still functional without those errors... (I use it in the chat program I also haven't touched in months) I'm not sure what I did since it was a long time ago - but I'll look into this weekend, review all the comments since my last post, and show everyone what I have.

thanks that you have noticed my bug report. I must add that the exception is released during changing between the menu entries of a main menu element (thus during the TrackPopupMenuEx function blocks). I used the Code from http://www.parslow.plus.com/VirtualMenu. I hope i didn't took the wrong one? At least I haven't found another location of your main menu implementation in this faq.

I looked over my code! After running into that same exception that was mentioned [and because "fixing" that bug would require me to write around the windows api] I opted to replace my menu implementation with a different model. You can find my source, with a sample here: http://files.codeable.net/skinnedform/.

Thank you for the bug fix Codable! Now everything functions marvelously on WinXP. :)

My request concerned also to the .net 1,1 framework.

I would have to still mark one, when I tried out the SkinnedForm on a Win2000 computer with the last service pack, I have to state that with one click on the form the NonClientArea drawing is dropping out. Also the transparency of the corners disappears after resizing the form.

Looks as if this will become a larger building site. I think it would be too much you to ask to develop the whole solution also for the other operating system versions. It would be really great if you could tell me the resources to your skills concerning the WinAPI programming calls.
But shurely I will have to be occupied with it for a while. (mail@[myDomainName])

If you have still time and desire, to test the SkinnedForm also for Win2000 and Win98, I would be very grateful. If you want to, I also can send you then my way to maitain SkinThemes (similar as in the new 5.0 version of Szymons .NET2.0 implementation.).

Cosmo & Codeable,
Thanks guys for the big effort you put to make it work on other systems. I didn't expect to spin such big discussion. What would you say to join our efforts and maintain this solution as single project? If you agree I will try to setup project for this on SF or CodePlex.

Nice, that sounds good. But it seems that this project must splitt into 2 different subprojects because of the difference between the .net1.1 and the .net2.0 implementations. Codable changed many parts of your Code...

And I still have to learn a lot about the WinAPI, so that I can help you effectively.
But I have a very good working knowledge of C#.NET in Version 1.1.
I could test everything intensivly and can give improvement suggestions.

1) when I set the WindowState on Maximized - the maximalization work not properly. The window begin not at top the screen and when you Close the form and run again and close and run... the top borde is traweling up and down with fixed steps.

2) When is the WindowState set on Normal - it`s funny to. Try maximize and restore from maximize (manytime) and look on height of the Window - it still increasing the Height of window.

David,
Thanks for reporting this. Currently I'm in the process of moving the project to CodePlex so we can get some decent version control and issue trucking. I also hope to get some help from you guys :-)

Hi,
I just wanted to let you know that the resizing problem is still there. Start the demo form of the project, resize it so that you can monitor the changes easily and then do minimize/restore for a few times. You can see that the form grows slightly each time.
I've narrowed the problem to WM_NCCALCSIZE message handler. When you remove this handler the form is restored correctly. Also it seems that the difference between the client area as calculated by windows and the client area calculated manualy is exactly the amount that the form is increased by when it is restored.

Hi,
Just one more thing. My guess is that when window manager sends WM_NCCALCSIZE message, takes the client rectangle that this message returns, increases it by the size of the non-client area (which, I guess, depends on the window style) and then sets the new size of the window.
One option would be to somehow tell windows the size of the non-client area in relation to the client area so that it recalculates the new size correctly (idealy the window manager should set the size of the form through Form.ClientSize and we would have no problems :( )
Second option is to somehow know that the window manager is setting the size of the form because of the 'restore window' command and then set the correct size ourselves.
Well I do not know that much about WinAPI to know where to start looking, hopefully you will have some ideas.

It seems the nuances of working AROUND the winAPI are starting to catch up with us! Remember, with this model we are still "letting" the OS do most of the work, then we add our own special features. It won't be easy! Bear with us.

I've compiled the code and done some playing around with the resulting window. After a couple of minutes, I realized Minimize, Maximize, and Close button didn't behave like standard ones. Hold the mouse pointer over any of those buttons and press the left mouse button down. You don't even need to release the button (click) for the button to activate. The normal behavior should be to activate only when the button is clicked. That is, the mouse can move anywhere once a "mousedown" is done on a button. If the button is released outside of the button it "mousedowned on", nothing happens. If the button is still being held down and the mouse returns to the button, the button activates on "mouseup".

Location of the MDI child is position inside MdiClient control. SO relative positioning must be done according location of that control. How to get that control you can see inside FindMDIClient method written below.
To get position of button inside Caption bar you have to translate coords between screen and client coordinate systems.
Note that docked controls are not inside MdiClient control.

private MdiClient _mdiClient = null;
private void FindMDIClient(Form parentForm)
{
if (_mdiClient != null)
return;
// Get the MdiClient from the parent form.
for (int i = 0; i < parentForm.Controls.Count; i++)
{
// If the form is an MDI container, it will contain an MdiClient control
// just as it would any other control.
_mdiClient = parentForm.Controls[i] as MdiClient;
if (_mdiClient != null)
{
// The MdiClient control was found.
// ...
//

About NativeMethods... (sorry for my english)"this is private .NET class and can not be used inside your project." i don`t understant how cand i use this library if i can`t 'use it inside my project' :|

can anyone show a lil bit from a source code (with this NativeMethode)? :| I`m searching from a while and i can`t find anything

If you fail to trap the undocumented message WM_NCUAHDRAWCAPTION (0xAE), it is possible that Windows XP will draw the caption buttons over your custom caption. This can often be seen when moving the mouse into a popup window for the first time, although the custom caption may need to be shorter than standard to see it.