by Michael S. Kaplan, published on 2005/04/01 03:02 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2005/04/01/404454.aspx
There are times that simplifying a model can make one's life easier. And there are times that it does not....
In such cases, the motives may be pure (sometimes I have my doubts) but the people who do the work should not feel that they are really fulfilling some sort of higher purpose.
One of the times that it does not necessarily help is when dealing with font charset values (whether StdFont.Charset, IFont::get_Charset/IFont::put_Charset, or LOGFONT.lfCharSet) and code page values, the mapping between them is a huge pain in the ass and the simplified model becomes really hard to map back and forth. Especially when they did not do the few things that they really should have done to support what they were really getting at -- script distinctions -- and they named it after something that everyone else calls a code page in HTTP and other places. More on this another day.
Another time is the attempt to map code page values and LCIDs, using LCIDs as a way to determine the code page to use for conversion. Whether one does it in the LCID parameter of OLE Automation methods or in Visual Basic's StrComp/StrConv/Split/Filter/Replace/Join/Instr/InstrRev functions, this attempt to overload two very different concepts hurts a lot more than it helps, in core ways. More on this another day, too.
And yet another time is the actual topic of today's post -- the IMEMode Enumeration used by WinForms controls (inherited by many other control types).
The enumeration has a lot of members:
Member name | Description |
Alpha | Alphanumeric single-byte characters(SBC). This setting is valid for Korean and Japanese IME only. |
AlphaFull | Alphanumeric double-byte characters. This setting is valid for Korean and Japanese IME only. |
Disable | The IME is disabled. With this setting, the users cannot turn the IME on from the keyboard, and the IME floating window is hidden. |
Hangul | Hangul SBC. This setting is valid for the Korean IME only. |
HangulFull | Hangul DBC. This setting is valid for the Korean IME only. |
Hiragana | Hiragana DBC. This setting is valid for the Japanese IME only. |
Inherit | Inherits the IME mode of the parent control. |
Katakana | Katakana DBC. This setting is valid for the Japanese IME only. |
KatakanaHalf | Katakana SBC. This setting is valid for the Japanese IME only. |
NoControl | None (Default). |
Off | The IME is off. This mode indicates that the IME is off, meaning that the object behaves the same as English entry mode. This setting is valid for Japanese, Simplified Chinese, and Traditional Chinese IME only. |
On | The IME is on. This value indicates that the IME is on and characters specific to Chinese or Japanese can be entered. This setting is valid for Japanese, Simplified Chinese, and Traditional Chinese IME only. |
They are inheriting a whole lot of functionality here, aren't they? It handles turning the IME on or off, whether it is disabled, the mode it sits in, and maybe even the context setting.
Now whether this is a genuine attempt to simplify a complex area or a desire to put a confusing set of topics in one place to shuffle them to the back of the bus is not the relevant point here (I suspect the former, I have heard at least one EA Microsoft basher who has claimed the latter, but you know how I feel about the bashing types!).
Say you are porting a legacy application that uses the various functions There are no really good charts that map how these various properties map to ImmCreateContext, ImmAssociateContext, ImmGetContext, ImmReleaseContext, ImmDestroyContext, ImmGetOpenStatus, ImmSetOpenStatus, ImmGetConversionStatus, and ImmSetConversionStatus, is there? Remember that WinForms that functionality is really wrapping these APIs, so obviously someone has these mappings somewhere.
Some of these functions cover topics so complex that the Platform SDK gives them their own topics (like Input Context). Though if you saw the hellacious code the WinForms devs had to write for their simplification, you would likely appreciate their efforts, even if you did need to understand the mappings!
Say you need to know which flags can be combined and which ones must not be (a crucial issue that you must have the data for when you have a single enumeration that feeds back to multiple different APIs such as this one). Where is the documentation for this? Saying which settings are valid for which IMEs may be interesting to some, but knowing that some cannot interact at all due to their identity (Inherit is -1, NoControl is 0).
Knowing that none of them can actually in fact be combined would also be handy since they are not bitmask values --- the values are -1 to 10. Imagine some slightly-too-clever developer tries to combine NoControl with some other value and a quick cast? Or worse Inherit? Talk about hidden bugs!
Maybe FxCop needs to get involved here to avoid that sort of problem1 ....
Especially since for some of these values, having a flag value would make a lot of sense -- like for the half/full distinction that splits Alpha/Hangul/KatakanaHalf from AlphaFull/HangulFull/Katakana/Hiragana. Even if they were going to have "summary" members that combined values, they could have had them made up of constituent parts that would make using the members in such a way for people who wanted/needed the information.
A colleague of mine asked me if I could perhaps point him at some reference that would point out the mapping between this property and the various IMM API functions. I walked into the task thinking about doing a really cool post that did a total mapping between all of the above IMM APIs and the IMEMode Enumeration-using property, between the various IMM notification messages and the Control.IMEModeChanged event.
I came up for air and hour later with a headache and decided to write this diatribe of a post, instead.
I may try to finish up that mapping at some point, but it is a bit too much at the moment. Sorry, Benson!
So next time you look at simplifying an interface that you feel is too complex, or if you try to map a simplified version of an interface to a new location because you are mapping some of the functionality, please consider not doing this. Use actual inheritance if you can, or just the same interface if you can't, and keep the model consistent.
Or, if you can't do any of that, at least consider a migration topic that documents the various mappings for those who need them. And do it right when you are writing the code since it is much harder to jump in later and figure it all out.
(I will give other examples of this issue, with the mappings if I can unravel them, another day. Teasers: controls wrapped by WinForms and the limitations that are inherited like "The WinForms DateTimePicker and MonthCalendar do not support culture settings", simplified versions of NLS functionality like lstrcmp)
1 - Perhaps they already are; Michael Fanning and the rest of the FxCop team's obsession with trying to root out potential misuses of the .NET Framework has me convinced that anyone not running this tool is unwilling to have a team of managed experts do code reviews of their stuff, for free! Would you want to work with (or worse, for) such a person?
This post brought to you by the term "이동" (U+c774 and U+b3d9)
Two Hangul Syllables which together suggest the meaning of "transfer" or "movement"