Friday, September 26, 2008 12:01 AM
Michael S. Kaplan
When Flat is not the Standard, the System is null?
The question to the alias was simple enough:
I have an issue dealing with winform button, I want to get the font used by button by sending WM_GETFONT message, if button’s FlatStyle=Standard, it returns NULL, however if button’s FlatStyle=System, it returns the correct font handle, anyone can take a look?
According to MSDN, if WM_GETFONT returns NULL, it means system font, but I specifically set the button font to a non-system font, and this seems it’s a bug to me.
Everything is actually behaving as it was designed to, though.
What is important to remember is that Windows Forms or "WinForms" is layer on top of Windows -- sometimes a very thick layer with a lot of functionality, and other times a vey thin layer that gives the smallest amount of an illusion a it can get away with.
Now for the FlatStyle=System setting on the button, the wrappet becomes very thin -- and the OS is used to do everything, including the rendering.
While when FlatStyle=Standard is used, however, the control goes the "owner draw" route, and since Windows doesn't really need a font itself in that case (and since .NET has to have it's own managed Font object to do its own work, there is no benefit to creating an extra object and storing it when it is not needed.
Now this deisgn had very interesting consequences when WinForms was supporte don Win9x -- because it meant that FlatStyle=System would not support text of the default system code page, while FlatStyle=Standard would support any text you had the font for.
And even moving into NT-based platforms, you could easily find yourself dealing with the differences between GDI/Uniscribe being used in one case vs. GDI+ in the other.
This particular WM_GETFONT issue is an interesting side effect (the reason the questioner wanted to use the WM_GETFONT message was for a test tool that was itself using native code, trying to verify what the font was on a particular control.
And this even provides a workaround!
I mean WinForms doesn't bother setting up an object that it does not need. And I can respect that (plus you should, too).
But if your particular application does care about it, then you have no reason to stay with the limitation....
If your managed code wants to call WM_SETFONT itself by taking the Font object you have and using Font.ToHfont, it can definitely do so -- and then the font will be available to the process that wants to be using WM_GETFONT. Though keep in mind the rules that Font.ToHfont mentions:
When using this method, you must dispose of the resulting Hfont using the GDI DeleteObject method to ensure the resources are released.
This mirrors what the WM_SETFONT message says:
The application should call the DeleteObject function to delete the font when it is no longer needed; for example, after it destroys the control.
in case you weren't convinced yet. :-)
Now note that you do not necessarily have to wait until the control is destroyed -- no one is using that HFONT other than you, so you can destroy it when you are done with it. Though you should probably call WM_SETFONT with a NULL wParam just in case some other process you don't know about has similar ideas to yours and tries to use an object after you have stopped doing so.
Now moving back to these kinds of behavioral differences that pop up, where entirely different code paths get utilized based on solitary settings like the FlatStyle of a button, as I said way back in the beginning, that's by design. Though I wouldn't mind seeing more advasnced documentation cover consequences like the ones mentioned here, to make it easier to understand the results in one's application....
This blog brought to you by ি (U+09bf, aka BENGALI VOWEL SIGN I)