Link to home
Start Free TrialLog in
Avatar of Zoppo
ZoppoFlag for Germany

asked on

Problem with WM_SETFONT, character set and ComDlg32.dll Version 6

Hi everybody,

I have a problem using WM_SETFONT to set a font for controls within a dialog. In my company's application (which is a CAD like MDI application using MFC with lots of dialogs) each document can set its own font to be used for drawing and even for edit controls in dialogs - thus it's i.e. possible to set one drawing to use 'Western' character set for one document and 'Cyrillic' for another one, both can be opened at the same time and, when opening a dialog to edit an object the dialog's edit controls use the appropriate font.

This worked quite fine for a long time, but now I have to make some changes which produce problems which drive me really crazy:
1. I have to add use of new version 6 of ComDlg32.dll to improve the GUI to have a more modern look, i.e. for progress bars - I do it by adding this line:
#pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
2. I need to do the same now for some other controls (CListBox, CListCtrl, CTreeCtrl, CComboBox, CMFCComboBox within CMFCToolBar, maybe more ...)

I have problems with both requirements:
1. As soon as I use the new ComDlg32.dll the previously working change of the character set for edit controls stops working. I can set a new font to the edit controls and most attributes (i.e. I tested font name, size, width, weight, underline, italic) of the new font are used, but the applied character set isn't used!
2. With or without the new ComDlg32.dll the same as in 1. written (so I can change anything but the character set) happens for all kind of controls except edit controls (including the edit control part of comboboxes, but not its list box part).

The font changes are made by creating a new font, the character set selection is done by setting the 'LOGFONT::lfCharSet' member to an appropriate value.

I have no idea why the controls don't use the character set of the font I set with WM_SETFONT nor how it is implemented in Windows - IMO this can only be done by creating a new font as a copy from the assigned one within the drawing function where for any reason the 'lfCharSet' is not used - this is very strange.

To give a better idea what's the problem about I added a screenshot below - on the left side you can see the dialog without new ComDlg32.dll (the red marked area marks the controls where the strings are partially shown correct), on the right side it's the same dialog using new ComDlg32.dll. The string I set contains both german and cyrillic characters to demonstrate the problem. Especially the possibility to mix character sets of different languages is a very important feature.

I can only see two possible solutions:
a.) Use UNICODE
b.) Override control drawing function by either handling WM_PAINT or, where available, owner drawing

But unfortunateley we either cannot or don't want to use them because
a.) It's a very large project (it contains about 10 executables including server app, some clients, about 80 DLLs use by the executables, all together about 1-1,5 Million lines of code) which is developed over the last 12 years - porting to UNICODE IMO is a matter of some man-years and, which is more important, will break the file- and database formats which is a no-go.
b.) As told there are a lot of dialogs where this needs to be done (more than one hundred) - lots of them already use owner drawn controls so it's just about finding a solution for each kind of above mentioned controls, each of the already owner drawn controls would need extra implementation. And for use of new ComDlg32.dll we even would have to implement drawing (by handling WM_PAINT) for edit controls which I know is difficult (I tried this once and didn't get it done without at least some small drawing errors i.e. with selected text and auto scrolling (but maybe this could be solved, I'm not sure) - anyhow, this even would mean a very huge amount of work so we really would like to avoid it.

I even tried to find a way to solve this by changing locales, but 1. I didn't manage to get it working and 2. it's not really an option, because font of some controls must not be changed, i.e. static texts, buttons, captions, ...


Sorry for this very long description, but I want to give as much important information as possible.


If anyone of you has an idea what I can try to find a solution I would highly appreciate it - and I can/will give lot of extra points to any helpful comment.


If you're interested in the test application I used for the screenshot please tell me, I can post it here if needed (it's done with VS 2010).


Thanks in advance,

ZOPPO



 User generated image
Avatar of jkr
jkr
Flag of Germany image

>>porting to UNICODE IMO is a matter of some man-years

Why don't you use UNICODE for this dialog only? You could either call the respective APIs explicitly as UNICODE (with the trailing 'W') or separate this dialog in a DLL which is built as UNICODE.
Avatar of Zoppo

ASKER

Thanks for your response, jkr - I'll have to think about this and to discuss with my colleagues because I think this could be a lot of work to to find all dialogs in question (as told I guess there are more than 100) in all DLLs, move them to DLLs which has to be added with takeing care of dependencies and add functionality to convert between ANSI and UNICODE wherever these dialogs are used in none-UNICODE DLLs/EXEs. Further I guess it may be difficult for some dialogs used in an EXE to be moved to a DLL since they use data or functions from the the EXE. But maybe if I cannot find another solution it may be worth to do it this way.

Just now I'm testing around if it's somehow possible to do a workaround by hooking GDI text-drawing AP functions - I hope I can somehow detect those drawing operations which use the font I initially set and use this font directly there. Unfortunateley I didn't yet get it working - I found some code for hooking APIs but using it for ExtTextOutW (which seems to be the function which is used for most controls on dialogs) the ways I tried for any reason I'm still searching for often crashs. Maybe I'll ask for some help later on here ...

ZOPPO
Ah, OK - I was under the impression that it was just a single dialog, if it is more than that, my suggestion might not be as handy as I thought first...
Avatar of Zoppo

ASKER

Hi again,

now I managed to get my API hooks running and analyzed different cases where drawing text using a font with cyrillic char set works or not.

I hooked the API of all text drawing functions I know (TextOut, ExtTextOut, DrawText, DrawTextEx, TabbedTextOut) in both ANSI and UNICODE (so the ...A and ...W functions). I found that in nearly all cases only 'ExtTextOutW' is used to draw control's texts.

In my tests I use this as ANSI test string:
'ËÅÑÍÎÉ': 0xcb-0xc5-0xd1-0xcd-0xce-0xc9-0x00

Open in new window


As font (which below is shown as 'Original font') I use this for WM_SETFONT and TextOut:
Font 0x3b0a2bef:
   LONG lfHeight: 0xfffffff2 (-14)
   LONG lfWidth: 0x00000000 (0)
   LONG lfEscapement: 0x00000000 (0)
   LONG lfOrientation: 0x00000000 (0)
   LONG lfWeight: 0x00000190 (400)
   BYTE lfItalic: 0x00 (0)
   BYTE lfUnderline: 0x01 (1)
   BYTE lfStrikeOut: 0x00 (0)
   BYTE lfCharSet: 0xcc (204)
   BYTE lfOutPrecision: 0x00 (0)
   BYTE lfClipPrecision: 0x00 (0)
   BYTE lfQuality: 0x00 (0)
   BYTE lfPitchAndFamily: 0x00 (0)
   CHAR lfFaceName[LF_FACESIZE]: Times New Roman

Open in new window

Beside the drawing of the dialog caption (which is somehow strange but irrelevant since I don't need it for my app) I tested four cases which IMO are interesting - here I just list the important parts of my logging (all font-members I don't list here are identical to the members shown above):

1. Working (edit control with old ComDlg32.dll):
fuOption: 0x00000014 - string (wcslen: 6):0x0245-0x023f-0x024b-0x0247-0x0248-0x0243-0x0000-
Original font: 0x3b0a2bef
Current font: Font 0x270a2be9:
   BYTE lfUnderline: 0x00 (0)

Open in new window

2. Not working (edit control with new ComDlg32.dll):
fuOption: 0x00000014 - string (wcslen: 6):0x00c9-0x0063-0x0066-0x00cb-0x00cc-0x0065-0x0000-
Original font: 0x3b0a2bef
Current font: Font 0xad0a2bcd:
   BYTE lfUnderline: 0x00 (0)

Open in new window


3. Not working (button control with old ComDlg32.dll):
fuOption: 0x00000010 - string (wcslen: 6):0x00c9-0x0063-0x0066-0x00cb-0x00cc-0x0065-0x0000-
Original font: 0x3b0a2bef
Current font: Font 0xb30a455b:
   BYTE lfUnderline: 0x00 (0)

Open in new window


4. Working (Drawing text with 'TextOut' in WM_PAINT handler):
fuOption: 0x00001000 - string (wcslen: 11):0x041b-0x0415-0x0421-0x041d-0x041e-0x0419-0x3ca3-
Original font: 0x3b0a2bef
Current font: Font 0x3b0a2bef:
   BYTE lfUnderline: 0x01 (1)

Open in new window

(If someone wants it I can attach log with complete output of LOGFONT members as TXT file, but you can believe me all other members are equal in any case)
   
A strange thing is that the passed string differs 4 times:
1. 	0x0245-0x023f-0x024b-0x0247-0x0248-0x0243-0x0000
2./3. 	0x00c9-0x0063-0x0066-0x00cb-0x00cc-0x0065-0x0000
4. 	0x041b-0x0415-0x0421-0x041d-0x041e-0x0419-0x3ca3

Open in new window

The two not working cases 2. and 3. are nearly equal (2. has the 'ETO_CLIPPED' fuOption set, 3. hasn't). In both cases the text drawn on the controls is the same as the above shown ANSI text.

Between the working cases 1. and 4. the differences I found are:
a.) the strings passed are different.
b.) only in 4. the font selected into the DC is the same as that one I created.
c.) the fuOption is different, with 4. the flag 'ETO_IGNORELANGUAGE' is set. This I guess is the reason why both work allthough the passed string differs. Interesting: If I add code to remove this flag and call the original 'ExtTextOutW' it my hook function is directly called again with a new (identical) font selected into the DC and the 'ETO_IGNORELANGUAGE' set again repeatedly until stack overflow. This makes me think that somehow the original 'ExtTextOutW' finds from analyzing the passed string how it has to be drawn.
d.) the result of 'wcslen' differs (!) - this IMO is very strange since I thought always UNICODE strings are passed so 'wcslen' should always return the same length 6 (which is always passed correctly via 'cbCount' argument).

Further a strange thing is the underline thing:
a.) for both working cases I see the text underlined allthough in 1. the 'lfUnderline' of the current font is 0.
b.) for both none-working cases 'lfUnderline' is even 0, but most controls draw the text underlined too (only static text are drawn none-underlined).


My big problem now is that I don't really have much experience with UNICODE/MBCS - I think it I could manage to convert the string passed in case 2. and 3. back to the original '0xcb-0xc5-0xd1-0xcd-0xce-0xc9-0x00' and next to one of the two representations used with 1. or 4. I could solve my problem.


If someone has an idea if/how it's possible to convert that string correctly it would be great.


Thanks,

ZOPPO
Avatar of Zoppo

ASKER

PS: Please excuse that I posted such a long comment again, but this IMO strange behavior drives me crazy so I still think it's better to post more info instead of posting to less info ...
Avatar of Zoppo

ASKER

Addition: Using WideCharToMultiByte and MultiByteToWideChar with codepage 1251 I am able to convert the string passed in 4.) to the original string and back again to the passed string. Unfortunateley I'm not able yet to do the same with the 3 other cases. I even tried WideCharToMultiByte with a loop for all possible codepage codes, but without success. I have no idea which kind of string-/encoding is used there ...
ASKER CERTIFIED SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Zoppo

ASKER

ok, after long time working on this I found some kind of a solution I can live with. I decided that for different char sets it's ok to have proporional fonts as a waorkaround for the edit-control-selection problem mentioned in my last post. Further I found the API to hook to solve that size-calculation problem.

I tried to upload my test project here but unfortunateley some file types aren't allowed - if anyone is interested in seeing my solution please contact me ...

I'll send a close request for this question.

Thanks anyway, best regards,

ZOPPO
Avatar of Zoppo

ASKER

I found a suitable solution myself ...