AVICAP32.DLL sucks (from the MSLU point of view)
by Michael S. Kaplan, published on 2005/04/13 16:15 -04:00, original URI: http://blogs.msdn.com/b/michkap/archive/2005/04/13/407912.aspx
It is all about perspective.
I am sure there are people who look at this DLL as being the answer to their prayers in terms of providing helpful interface to AVI capabilities.
But from my point of view, it kind of sucks. :-(
The other day someone with the handle PRR posted the following to the microsoft.public.platformsdk.mslayerforunicode newsgroup:
Problem description: If unicows.lib is included in the project, floating point control word may become invalid during program startup on Windows 98/95 machines (not tested on ME).
Compiler platform: MS VS.NET 2003 Pro, Platform SDK Feb 2003, Unicows.dll 1.1.3790, Win XP Pro, P4@2.4G, 1G RAM,
Steps to repro:
- Create new Win32 Console Application (default settings).
- Under Project Property Pages dialog choose Release configuration
- Add following to Linker/Command line:
/nod:kernel32.lib /nod:advapi32.lib /nod:user32.lib /nod:gdi32.lib /nod:shell32.lib /nod:comdlg32.lib
/nod:version.lib /nod:mpr.lib /nod:rasapi32.lib /nod:winmm.lib /nod:winspool.lib /nod:vfw32.lib
/nod:secur32.lib /nod:oleacc.lib /nod:oledlg.lib /nod:sensapi.lib unicows.lib kernel32.lib advapi32.lib
user32.lib gdi32.lib shell32.lib comdlg32.lib version.lib mpr.lib rasapi32.lib winmm.lib winspool.lib
vfw32.lib secur32.lib oleacc.lib oledlg.lib sensapi.lib
- Modify main cpp file to following:
#include "stdafx.h"
#include <stdio.h>
#include <float.h>
int _tmain(int argc, _TCHAR* argv[])
{
printf("%x\n", _control87(0, 0));
return 0;
}
- Compile the Release project and run on Win98SE PC.
Output: 40003
Expected output: 9001f
The problem was reproduced on machine, which has a clean install of Win95OSR2 + clean upgrade to Win98SE. It does not happen all the time. If program should return 9001f, reboot Win98 and try again.
Note: It does not matter, whether project uses Multi-byte or Unicode charset.
Note: As soon as unicows.lib is removed from project, program starts acting as expected.
Now for the record, it is not MSLU that is doing this. In order to have maximum compatibility with every version of Win9x (including Windows 95), there is no dependency whatsoever on the C Runtime. So it is defnitely not setting the floating point stuff. It is actually harder to do this than I realized, but Phil Lucido helped me shed the dependency while still using stuff like structured exception handling....
Now I knew this issue had come up before but honestly could not remember what it was. Luckily, Ted (who unlike me remembered this issue) came to the rescue with the answer for PRR, and a workaround:
The thing that actually destroys the floating point is avicap32.dll which unicows.dll is dependent on. Several searches will come up with information about this.
The solution is to create your own AVICAP32.DLL stub DLL that sits in the same folder as unicows.dll (if you don't rely on functionality in that DLL).
The problem is that unicows.lib is statically linked to many of the system DLLs that it has to call for the functions it wraps, and AVICAP32.DLL does indeed change these settings in the process. Whether you wanted it to or not.
Now this DLL only has two APIs that MSLU wraps: capCreateCaptureWindow and capGetDriverDescription. For all of the trouble that they cause with this floating point crap, I wish no one had noticed these two APIs that were missed for so long (they were added to MSLU on March 24, 2001 and I doubt anyone has actually used the wrappers since then, beyond the meager tests I wrote!).
Back then, I had toyed with the idea of delay loading all of the DLLs and functions being called, but somewhere in the 15+ DLLs and 550+ APIs it just seemed like an excessive amount of work. And it never ended up happening. It probably should have happened for this one DLL/two functions to work around the floating point problem, but it is not really worth rev'ing the DLL for that one change. I'll put it on the list of things to triage, if and when....
This post brought to you by "ಊ" (U+0c8a, a.k.a. KANNADA LETTER UU)
A letter that is selcom seen on Win9x but well represented in the Tunga font that ships with Windows XP and Server 2003!
# Steve Loughran on 15 Apr 2005 5:53 AM:
OK,
I'm going to take up your request for comments with something vaguely off topic but win9x related. No, its not a support call "my obscuro 312 printer doesnt work on win95, please help".
But its this: where do you get your legacy win9x images from? Cos there is apparently nowhere on MSDN Universal Subscriptions to get ISO images for the OS releases, and hence no way to bring up new system images under VMWare or VPC unless you have old CDs around. Do you treasure the CDs from the elder days, or what?
Steve
(who has a my-app-doesnt-work-on-win98 call that he's ignoring right now)
# Michael S. Kaplan on 15 Apr 2005 7:04 AM:
I don't realy install in9x myself these days, as I have a laptop that can boot into about thirty different versions of it in different languages. :-)
But when I used to, I would do full installs from a share that had the builds. I am sure I have old CDs somewhere from prior PC purchases, but I never keep track of where they are. :-)
While MSDN Universal does not have ISO images, I believe the Win9x versions are there, somewhere....
# James Todd on 16 Apr 2005 1:34 PM:
Thanks for the information! This exact problem has been driving me up the wall and I couldn't figure out what in the world was changing the control word. Interestingly the non-optimized version of my program doesn't reproduce the problem, even though both debug and release are linking with unicows.lib.
I do have one question about Ted's workaround. Does the stubbed AVICAP32.dll need to actually export the two functions capCreateCaptureWindow and capGetDriverDescription, or can the dll export nothing?
As an alternate workaround, is it sufficient to reset the control word ourselves early in main() by calling _control87 with _CW_DEFAULT as the first parameter?
Thanks again,
James
# Michael S. Kaplan on 16 Apr 2005 2:54 PM:
James -- I believe if your application does not call any of those APIs, it can have nothing in them, since it will never be called anyway. If you use AVICAP32.DLL that can cause problems though, so make sure you are not using any of the APIs from that DLL. :-)
You should be able to change the setting yourself any time after they have changed it in their code. The "dueling DLLs configuring" scenario works as long as you are the last one to change the setting!
# James Todd on 19 Apr 2005 5:06 PM:
Thanks Michael. I've implemented my workaround by setting the control word myself early in my main(). There's one weird thing though: The control word doesn't always seem to be wrong by the time main() starts. Do you expect it to always be wrong, or are there other variable that affect whether or not the control word is wrong by the time the user program's main() starts?
It feels like a thread race condition, but that doesn't feel right either since floating point control words are per-thread state.
# Michael S. Kaplan on 20 Apr 2005 11:58 AM:
To tell you the truth, I am not sure. But you are right that it seems like a race condition.
# James Todd on 28 Apr 2005 6:46 PM:
As an addendum to this workaround, in my experience I had to actually put stubbed versions of the functions capCreateCaptureWindowA and capGetDriverDescriptionA into my dll. Once I did that all seemed to be well. If I didn't actually stub out the functions and have them exported from my dll, then the fix didn't take. I'm not sure why, but stubbing out the actual functions was easy enough.
To save others time, here's the quick and dirty stubbed code. I exported the two functions from the dll by linkinking in an old-school .def file.
#include <vfw.h>
extern "C" {
HWND WINAPI capCreateCaptureWindowA(
LPCSTR lpszWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWnd,
int nID
)
{
return NULL;
}
BOOL WINAPI capGetDriverDescriptionA(
UINT wDriverIndex,
LPSTR lpszName,
INT cbName,
LPSTR lpszVer,
INT cbVer
)
{
return false;
}
}
# Michael S. Kaplan on 28 Apr 2005 7:15 PM:
James, that makes sense -- those are the two functions that we call, so it makes sense that it would fail if they were not there in the .LIB.
Thanks for posting this! :-)
# James Todd on 2 May 2005 12:38 PM:
Sorry to keep beating this dead horse... Can you tell me which version of unicows.dll first wrapped avicap32.dll and thus had this floating point bug?
I'm looking at unicows.dll version 1.0.3665, and I see that it does have a dependency on avicap32.dll, so I would expect it to also have this issue. Is am I safe in assuming that any unicows.dll that is dependent on avicap32.dll will have this bug?
Thanks again,
James
# Michael S. Kaplan on 2 May 2005 1:29 PM:
They were checked into the project in March of 2001, so other than early beta versions, they have always been there.
I have no idea when or if changes were made (or if it was always there) in avicap32.DLL to alter the setting.
# James Todd on 3 May 2005 2:35 PM:
Actually nevermind. 1.0.3665 does have the issue as well, as expected.
James
Yuhong Bao on 30 Dec 2010 2:05 AM:
"I don't realy install in9x myself these days, as I have a laptop that can boot into about thirty different versions of it in different languages. :-) "
How do you do this? Do you use WinBoot?
Michael S. Kaplan on 30 Dec 2010 7:51 AM:
It was an internal program provided by test. of course the MSLU virtual test machine is no more at this point....
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
go to newer or older post, or back to index or month or day