by Michael S. Kaplan, published on 2005/10/31 00:01 -08:00, original URI: http://blogs.msdn.com/michkap/archive/2005/10/31/486870.aspx
(Although the title may suggest it to some people, this is not a post about whether I should be giving my ex-girlfriend a call; it is not!)
There are many functions in the Windows API set that have Ex or Ex-style varations that get added.
In lots of cases, the Ex version acts as extension, and extends the functionality of the original function. But in some cases it is simply one that changes the functionality in a particular way.
So it is important not to try to pick the one to call by assuming that the old function just calls the new one.
Sometimes such an assumption will work -- TextOutW basically just calls ExtTextOutW, and FindResourceW does little more than call FindResourceExW. And in most cases on NT platforms the "A" functions convert and call their "W" equivalents.
But other times, it will not -- ToUnicode and ToUnicodeEx actually both call the same internal function and thus all you get for trying to short circuit what appears to be the wrapper is that you push an extra 4-8 bytes of stack.
The code for the Unicode and ANSI versions of CharNext are entirely different bits of code, trying to solve entirely different kinds of issues. You will actually cause more problems than you solve by trying to convert yourself and calling one of them.
And many people feel like you need a spirit dancer, a Magic 8-Ball and a ouija board if you want to know the difference between GetTextExtentPoint, GetTextExtentPoint32 and GetTextExtentExPoint, or between the EnumFonts, EnumFontFamilies, and EnumFontFamiliesEx functions. Every time you think you get a handle on the differences in the Platform SDK documentation, a topic like this one or this one makes you start wondering again.
Now on top of all that, in a particular very special case, the Ex version is actually a wrapper around the non-Ex version.
That case is GetStringTypeA, GetStringTypeW, and GetStringTypeEx, the main subjects of this post.
These three functions have an interesting, some would say the professional equivalent of sordid, history.
You see, there is no GetStringType function in the documentation or the header files, because the decorated functions (GetStringTypeA and GetStringTypeW) take different parameters -- the former takes an LCID and the latter does not.
The story varies when asking oldtimers about how this all came about.
Perhaps more will chime in, ones without bias especially welcome -- bias clearly is what makes so many people have such different recollections!
But the most consistent story I have been able to glean from various sources is that GetStringTypeW was done by the NT team for NT 3.1 and GetStringTypeA was done by the Win9x team for Win95. Now NT 3.1 shipped first, and it was only when the Win95 project hit this bit of code that the need for an LCID became obvious. The NT team could not change their function signature and the 9x team could not proceed without a context for the conversion, so they split the difference and kept them separate, and Win95/NT 3.5 both shipped with the GetStringTypeEx function.
(No one could recall if NT 3.1 ever was supposed to support a GetStringTypeA that had no LCID parameter, but I have checked the NT 3.1 kernel32.dll and it did not export such a function (the NT 3.5 version matches the current function, as the documentation indicates). One person hypothesized that the Win9x issue came up in time to yank out the LCID-less GetStringTypeA but too late to change GetStringTypeW, but admitted that this was pure guessing!)
Now, looking at all of the functions to explain what they do:
Now 'uses the locale' means looking it up in our list of 'loaded' locales, an if it is not there, loading it and adding it to that list. Maybe GetStringTypeExW could have skipped looking at the locale (since it does not use it) but it was not written that way originally (at this point who knows what kind of dependencies might be in customer code, so we can't change the behavior.
Notice what happened here though -- GetStringTypeW (which technically came first) is the main function, and the other two that came later are the wrappers that are doing extra work just to call the original function. The other functions provide no additional funtionality unless you want to consider it as a confusing way to get IsValidLocale-esque functionality (which seems crazy, but is the reason we can't take out the behavior, unfortunately).
So, the answer to the original question "To Ex or not to Ex?" in this case is (ironically enough, just as with the ex-girlfriend?) probably not to Ex. And for the wider question, it is probably better to decide based on the functionality you need and not on which one looks newer, unless you have someone writing a blog entry to explain why you might want to do something different.
And how often does that really happen, anyway? :-)
This post brought to you by "¿" (U+00bf, INVERTED QUESTION MARK)
# PatriotB on Monday, October 31, 2005 4:07 AM:
# Michael S. Kaplan on Monday, October 31, 2005 7:20 AM:
# Skywing on Monday, October 31, 2005 11:19 AM:
# Michael S. Kaplan on Monday, October 31, 2005 11:21 AM:
# Vorn on Monday, October 31, 2005 2:05 PM:
# Michael S. Kaplan on Monday, October 31, 2005 9:07 PM:
# Yuhong Bao on Thursday, December 29, 2005 3:12 PM:
# Michael S. Kaplan on Thursday, December 29, 2005 3:19 PM:
go to newer or older post, or back to index or month or day