Why does MSLU wrap ________ ?

by Michael S. Kaplan, published on 2005/05/04 07:13 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2005/05/04/414562.aspx


Most of the APIs that MSLU wraps are on the list for obvious reasons. But in that huge list, there are several that are not....

1) There is, for example, the GetProcAddress function. It takes a string, but never a Unicode string, on NT or otherwise. So why would it need to be wrapped?

Well, it turns out that the GetMonitorInfo function, defined in multimon.h, is not just a simple prototype. There is a bunch of complex code in it that conditionally calls various APIs, including GetProcAddress, to get a function pointer to replace any call to GetMonitorInfo. Because of this, MSLU could not wrap the GetMonitorInfo function, because the wrapper would never be used. The only way to allow the to wrapper to work was to wrap GetProcAddress and look for where someone was trying to retrieve the address of GetMonitorInfoA or GetMonitorInfoW!

2) And then there is the EnableWindow function, which does not even take a string. Why on earth would MSLU need to wrap it?

Back in the early days, MSLU was eager to convince people who had Unicode layers of their own to consider switching to MSLU. As a part of that, it picked up several bug fixes from other layers so that people would not have to feel like they were losing functionality for switching. One of those layers was the "VSAnsi" layer used by Visual Studio, which had an EnableWindow fix best described in a comment in the MSLU source code:

        // We wrap this API in order to get consistent behavior on both
        // NT and Win9x. It seems that on NT, any non-zero value of bEnable
        // will enable the window.  Based on empirical data, Win9x seems to
        // look at only the low 16 bits of bEnable.  This causes a problem,
        // for example, if the caller passes a count of items with the intent
        // to enable a window when the count is >0.  That will fail when the
        // count is a multiple of 64K, but will be nearly impossible to find
        // and fix the problem. See Visual Studio 7 ###### for an example
        // of such a bug.

Now there were not many APIs that were taken to this kind of extreme, but the VSAnsi library was at that time owned by Lars Bergstrom (a very smart developer) and was probably the second most useful source of interesting buglets for MSLU to fix while wrapping (right after Office, which had a vitual monopoly on interesting Win9x GDI bug fixes that even external customers had found by spluenking through the exports in the MSO library, over the years). Given the unique expertise the wrapper code writing seemed to require, Lars and I probably did a ton of code reviews of each others' work before MSLU and the VSAnsi that shipped in VS 7.0 first got released. The EnableWindow bug fix was one of those little extra bug fixes that we picked up.

3) Then there are the FindResourceW and FindResourceExW functions. Now note that Unicode versions of these functions actually exist on Win9x, so there is no good reason to wrap them, right?

Well, actually, wrong. Both APIs took resource type and name parameters that could be either strings or numbers, but there was a bug in Windows 95 and Windows 98 (fixed in Windows Me) where in some cases the LocalFree function was being called on the parameter even though the LocalAlloc function was never called to allocate the string (it was a passed in parameter). This would potentially corrupt the heap. So MSLU would do the extra work to copy string parameters to stack variables, because an attempt to call LocalFree on a stack variable would simply fail with a last error of ERROR_INVALID_HANDLE. On Windows Me it would just call the OS directly since the bug had been fixed....

 

This post brought to you by "ㆆ" (U+3186, a.k.a. HANGUL LETTER YEORINHIEUH)


# Michael S. Kaplan on 4 May 2005 5:23 AM:

I could be going senile, but I believe Raymond Chen was the one who tracked down the bug in FindResourceExW when it was fixed in Windows Me.

I do know he is the one who suggested to me the clever stack workaround for the problem which MSLU used to rehabilitate the function years later, though. :-)

# Dean Harding on 4 May 2005 8:22 AM:

How come GetMonitorInfo is so complex? From the documentation, it looks like all it should do is copy info from an internal data structure to the user's buffer... ?

# Michael S. Kaplan on 4 May 2005 8:38 AM:

I believe the complexities were due to an attempt to handle platform differences transparently in the header file, so you could call code the same way without worrying about the all multimon support changes.

Yuhong Bao on 10 Oct 2007 10:53 PM:

"but there was a bug in Windows 95 and Windows 98 (fixed in Windows Me) where in some cases the LocalFree function was being called on the parameter even though the LocalAlloc function was never called to allocate the string (it was a passed in parameter). This would potentially corrupt the heap. So MSLU would do the extra work to copy string parameters to stack variables, because an attempt to call LocalFree on a stack variable would simply fail with a last error of ERROR_INVALID_HANDLE."

Why not use LocalAlloc to allocate a buffer and copy a string to it?

Michael S. Kaplan on 11 Oct 2007 12:09 AM:

Because we wouldn't always know when it was freed and when it was not across the various versons of Windows without writing a much more complex wrapper -- this way MSLU could have simpler code that would work in all versions....

Yuhong Bao on 9 Nov 2008 4:12 AM:

// NT and Win9x. It seems that on NT, any non-zero value of bEnable
// will enable the window.  Based on empirical data, Win9x seems to
// look at only the low 16 bits of bEnable.  This causes a problem,

Do you know that the majority of USER32 and GDI32 functions in Win9x thunks to the 16-bit USER and GDI? I think what is happening here is that during thunking, bEnable got truncated to 16-bit and so EnableWindow can only look at the low 16-bits.

Michael S. Kaplan on 9 Nov 2008 8:42 AM:

While much of what you say is true for USER, it is largely untrue for GDI...

Yuhong Bao on 2 May 2009 11:44 PM:

"I think what is happening here is that during thunking, bEnable got truncated to 16-bit and so EnableWindow can only look at the low 16-bits."

In fact, that is why the thunk compiler provides a special bool type. Because if you use the int type for BOOLs in thunk scripts, things like this can happen.


Please consider a donation to keep this archive running, maintained and free of advertising.
Donate €20 or more to receive an offline copy of the whole archive including all images.

referenced by

2012/08/01 When my decisions come back to haunt me (and/or others!)

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