When Flat is not the Standard, the System is null?

by Michael S. Kaplan, published on 2008/09/26 03:01 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2008/09/26/8965526.aspx


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)

bahgat mashaly on 31 Dec 2010 2:53 PM:

many thanks for that Article.

but what can i do if i want to get font of control in other applications ?

Michael S. Kaplan on 31 Dec 2010 3:26 PM:

Other managed applications that are doing this, from your native application? Just have the managed applications make the change in this article....

Bahgat Mashaly on 1 Jan 2011 9:02 AM:

many thanks for your reply  

try to make google translate any ware so i I want to get a word under the mouse I was able to do that with textbox and richtextbox but not with other control i tray to simulate that control as richtextbox or textbox by get size ,location and font of that control then call ScreenToClient so the other control FlatStyle my be System or standard As you are a professional person and I am a newbie what do you think in my steps?? Is there a better way??and how to solve this problem ?

I'm using c# to do this

Michael S. Kaplan on 1 Jan 2011 9:34 AM:

Wanting to get the text has almost nothing to do with getting the font, so I'm not sure I see the connection, to be honest. Given that your goal is to translate, the font you want to use is the on supporting the TARGET language you are translating into, not the SOURCE language. So why would you ever want to the font to be the same?

Bahgat Mashaly on 1 Jan 2011 11:18 AM:

i want to get the font to get the mouse  position of that text , then i can get the word under the mouse

if i use any other font the mouse position my be Refers to another word

Michael S. Kaplan on 1 Jan 2011 5:29 PM:

That's where I disagree with your approach. Having knowledge of what font is used does not give some magical way to read the text -- in the case of complex scripts this is patently obvious, but even in other cases such an approach will fail.

In any case, there is no supported/supportable solution anyway to get the info in this specific, as I said. So even if the approach was productive, it is not always feasible. And that is even before we bring the plethorea of WINDOWLESS controls that exist, too.

Radhika on 4 Jan 2011 12:39 AM:

Thanks for the Article.

I need to get textsize and width of UI controls like Button, Labels of any application.

Tried WM_GETFONT but throws exception saying only TrueType fonts are supported. What should be done to get any type of fonts? Please help

Michael S. Kaplan on 4 Jan 2011 12:53 AM:

There is no one method to support even every Win32 application, let alone every other kind of application that exists.

Radhika on 4 Jan 2011 1:53 AM:

Would you be able to give pointers for retriving font information of WPF applications or Winform Applications.? I'm trying for both and not an issue if it points to different procedure.


Michael S. Kaplan on 5 Jan 2011 6:54 AM:

That sounds more like something for the Suggestion Box, though as a question it is so broad that there are real problems delivering on it....

go to newer or older post, or back to index or month or day