Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

816 lines
23 KiB

/*++
*
* WOW v1.0
*
* Copyright (c) 1991, Microsoft Corporation
*
* WKERNEL.C
* WOW32 16-bit Kernel API support
*
* History:
* Created 07-Mar-1991 by Jeff Parsons (jeffpar)
--*/
#include "precomp.h"
#pragma hdrstop
MODNAME(wkernel.c);
ULONG FASTCALL WK32RegOpenKey32(PVDMFRAME pFrame)
{
HKEY hKey, hKeyTmp;
PSZ pszKey;
PHKEY phKey;
register PREGOPENKEY3216 parg16;
ULONG ulRet;
GETARGPTR(pFrame, sizeof(REGOPENKEY3216), parg16);
hKey = (HKEY) FETCHDWORD(parg16->hKey);
GETPSZPTR(parg16->lpszSubKey, pszKey);
GETVDMPTR(parg16->phkResult, sizeof(*phKey), phKey);
ulRet = RegOpenKey(hKey, pszKey, &hKeyTmp);
STOREDWORD(*phKey, hKeyTmp);
FREEVDMPTR(phKey);
FREEPSZPTR(pszKey);
FREEARGPTR(parg16);
return ulRet;
}
ULONG FASTCALL WK32RegEnumKey32(PVDMFRAME pFrame)
{
HKEY hKey;
DWORD dwSubKey;
PSZ pszName;
DWORD cchName;
register PREGENUMKEY3216 parg16;
ULONG ulRet;
GETARGPTR(pFrame, sizeof(REGENUMKEY3216), parg16);
hKey = (HKEY) FETCHDWORD(parg16->hKey);
dwSubKey = FETCHDWORD(parg16->iSubKey);
GETPSZPTR(parg16->lpszName, pszName);
cchName = FETCHDWORD(parg16->cchName);
ulRet = RegEnumKey(hKey, dwSubKey, pszName, cchName);
FREEPSZPTR(pszName);
FREEARGPTR(parg16);
return ulRet;
}
ULONG FASTCALL WK32RegEnumValue32(PVDMFRAME pFrame)
{
HKEY hKey;
DWORD dwValue, cchValueTmp, dwTypeTmp, cbDataTmp;
PSZ pszValue;
LPDWORD lpcchValue;
LPDWORD lpdwType;
LPBYTE lpbData;
LPDWORD lpcbData;
register PREGENUMVALUE3216 parg16;
ULONG ulRet;
GETARGPTR(pFrame, sizeof(REGENUMVALUE3216), parg16);
hKey = (HKEY) FETCHDWORD(parg16->hKey);
dwValue = FETCHDWORD(parg16->iValue);
GETPSZPTR(parg16->lpszValue, pszValue);
GETVDMPTR(parg16->lpcchValue, sizeof(*lpcchValue), lpcchValue);
cchValueTmp = FETCHDWORD(*lpcchValue);
GETVDMPTR(parg16->lpdwType, sizeof(*lpdwType), lpdwType);
dwTypeTmp = FETCHDWORD(*lpdwType);
GETMISCPTR(parg16->lpbData, lpbData);
GETVDMPTR(parg16->lpcbData, sizeof(*lpcbData), lpcbData);
cbDataTmp = FETCHDWORD(*lpcbData);
ulRet = RegEnumValue(hKey, dwValue, pszValue, &cchValueTmp,
NULL, &dwTypeTmp, lpbData, &cbDataTmp);
STOREDWORD(*lpcchValue, cchValueTmp);
STOREDWORD(*lpdwType, dwTypeTmp);
STOREDWORD(*lpcbData, cbDataTmp);
FREEVDMPTR(lpcbData);
FREEMISCPTR(lpbData);
FREEVDMPTR(lpdwType);
FREEVDMPTR(lpcchValue);
FREEPSZPTR(pszValue);
FREEARGPTR(parg16);
return ulRet;
}
ULONG FASTCALL WK32RegCloseKey32(PVDMFRAME pFrame)
{
HKEY hKey;
register PREGCLOSEKEY3216 parg16;
ULONG ulRet;
GETARGPTR(pFrame, sizeof(REGCLOSEKEY3216), parg16);
hKey = (HKEY) FETCHDWORD(parg16->hKey);
ulRet = RegCloseKey(hKey);
FREEARGPTR(parg16);
return ulRet;
}
ULONG FASTCALL WK32WritePrivateProfileString(PVDMFRAME pFrame)
{
ULONG ul;
PSZ pszSection;
PSZ pszKey;
PSZ pszValue;
PSZ pszFilename;
register PWRITEPRIVATEPROFILESTRING16 parg16;
BOOL fIsWinIni;
CHAR szLowercase[MAX_PATH];
GETARGPTR(pFrame, sizeof(WRITEPRIVATEPROFILESTRING16), parg16);
GETPSZPTR(parg16->f1, pszSection);
GETPSZPTR(parg16->f2, pszKey);
GETPSZPTR(parg16->f3, pszValue);
GETPSZPTR(parg16->f4, pszFilename);
UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
strcpy(szLowercase, pszFilename);
_strlwr(szLowercase);
fIsWinIni = IS_WIN_INI(szLowercase);
// Trying to install or change default printer to fax printer?
if (fIsWinIni &&
pszSection &&
pszKey &&
pszValue &&
!_stricmp(pszSection, szDevices) &&
IsFaxPrinterWriteProfileString(pszSection, pszKey, pszValue)) {
ul = TRUE;
goto Done;
}
ul = GETBOOL16( WritePrivateProfileString(
pszSection,
pszKey,
pszValue,
pszFilename
));
if( ul != 0 &&
fIsWinIni &&
IS_EMBEDDING_SECTION( pszSection ) &&
pszKey != NULL &&
pszValue != NULL ) {
UpdateClassesRootSubKey( pszKey, pszValue);
}
Done:
FREEPSZPTR(pszSection);
FREEPSZPTR(pszKey);
FREEPSZPTR(pszValue);
FREEPSZPTR(pszFilename);
FREEARGPTR(parg16);
return ul;
}
ULONG FASTCALL WK32WriteProfileString(PVDMFRAME pFrame)
{
ULONG ul;
PSZ pszSection;
PSZ pszKey;
PSZ pszValue;
register PWRITEPROFILESTRING16 parg16;
GETARGPTR(pFrame, sizeof(WRITEPROFILESTRING16), parg16);
GETPSZPTR(parg16->f1, pszSection);
GETPSZPTR(parg16->f2, pszKey);
GETPSZPTR(parg16->f3, pszValue);
// Trying to install or change default printer to fax printer?
if (pszSection &&
pszKey &&
pszValue &&
!_stricmp(pszSection, szDevices) &&
IsFaxPrinterWriteProfileString(pszSection, pszKey, pszValue)) {
ul = TRUE;
goto Done;
}
ul = GETBOOL16( WriteProfileString(
pszSection,
pszKey,
pszValue
));
if( ( ul != 0 ) &&
IS_EMBEDDING_SECTION( pszSection ) &&
( pszKey != NULL ) &&
( pszValue != NULL ) ) {
UpdateClassesRootSubKey( pszKey, pszValue);
}
Done:
FREEPSZPTR(pszSection);
FREEPSZPTR(pszKey);
FREEPSZPTR(pszValue);
FREEARGPTR(parg16);
return ul;
}
ULONG FASTCALL WK32GetProfileString(PVDMFRAME pFrame)
{
ULONG ul;
PSZ pszSection;
PSZ pszKey;
PSZ pszDefault;
PSZ pszReturnBuffer;
UINT cchMax;
register PGETPROFILESTRING16 parg16;
GETARGPTR(pFrame, sizeof(GETPROFILESTRING16), parg16);
GETPSZPTR(parg16->f1, pszSection);
GETPSZPTR(parg16->f2, pszKey);
GETPSZPTR(parg16->f3, pszDefault);
ALLOCVDMPTR(parg16->f4, parg16->f5, pszReturnBuffer);
cchMax = INT32(parg16->f5);
if (IS_EMBEDDING_SECTION( pszSection ) &&
!WasSectionRecentlyUpdated() ) {
if( pszKey == NULL ) {
UpdateEmbeddingAllKeys();
} else {
UpdateEmbeddingKey( pszKey );
}
SetLastTimeUpdated();
} else if (pszSection &&
pszKey &&
!_stricmp(pszSection, szDevices) &&
IsFaxPrinterSupportedDevice(pszKey)) {
ul = GETINT16(GetFaxPrinterProfileString(pszSection, pszKey, pszDefault, pszReturnBuffer, cchMax));
goto FlushAndReturn;
}
ul = GETINT16(GetProfileString(
pszSection,
pszKey,
pszDefault,
pszReturnBuffer,
cchMax));
//
// Win3.1/Win95 compatibility: Zap any trailing blanks in pszDefault
// with nulls, but only if the default string was returned. To detect
// the default string being returned we need to ignore trailing blanks.
//
// Because of the high usage of this API, we only zap trailing blanks
// if a compatibility bit is turned on.
//
// This code is duplicated in thunks for GetProfileString and
// GetPrivateProfileString, update both if you make changes.
//
if ((CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) &&
pszDefault &&
pszKey
) {
int n, nLenDef;
//
// If the returned string is a prefix of the default string...
// ul is strlen(pszReturnBuffer)
//
nLenDef = strlen(pszDefault);
if (nLenDef > (int)ul &&
RtlEqualMemory(pszDefault, pszReturnBuffer, ul)) {
//
// And the only difference is trailing blanks...
//
for (n = (int)ul; n < nLenDef; n++) {
if (' ' != pszDefault[n]) {
break;
}
#ifdef DBCS
if (IsDBCSLeadByte(pszDefault[n]) {
n++;
}
#endif
}
if (n >= nLenDef) {
char szBuf[512];
//
// The returned string is the same as the default string
// without trailing blanks, but this might be coincidence,
// so see if a call with empty pszDefault returns anything.
// If it does, we don't zap because the default isn't
// being used.
//
if (0 == GetProfileString(pszSection, pszKey, "", szBuf, sizeof szBuf)) {
//
// Zap first trailing blank in pszDefault with null.
//
pszDefault[ul] = 0;
FLUSHVDMPTR(parg16->f3 + ul, 1, pszDefault + ul);
}
}
}
}
#ifdef DEBUG
//
// Make noise on the debugger if pszDefault has trailing blanks at
// this point indicating that WOWCFEX_ZAPGPPSDEFBLANKS might need
// to be turned on for this app.
//
if ( ! (CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) &&
pszKey &&
pszDefault &&
' ' == pszDefault[strlen(pszDefault) - 1]) {
char szMsg[256];
sprintf(szMsg,
"\n"
"WOW32 COMPATIBILITY ALERT: Task %.8s has trailing blanks in pszDefault to\n"
"Get[Private]ProfileString but WOWCFEX_ZAPGPPSDEFBLANKS (0x00000000 0x%08x)\n"
"is not enabled. Try enabling this bit if you're having problems.\n"
"\n",
((PTDB)SEGPTR(CURRENTPTD()->htask16,0))->TDB_ModName,
WOWCFEX_ZAPGPPSDEFBLANKS
);
OutputDebugString(szMsg);
}
#endif
FlushAndReturn:
FLUSHVDMPTR(parg16->f4, (ul + (pszSection && pszKey) ? 1 : 2), pszReturnBuffer);
FREEPSZPTR(pszSection);
FREEPSZPTR(pszKey);
FREEPSZPTR(pszDefault);
FREEVDMPTR(pszReturnBuffer);
FREEARGPTR(parg16);
RETURN(ul);
}
ULONG FASTCALL WK32GetPrivateProfileString(PVDMFRAME pFrame)
{
ULONG ul;
PSZ pszSection;
PSZ pszKey;
PSZ pszDefault;
PSZ pszReturnBuffer;
PSZ pszFilename;
DWORD cFlagsEx;
UINT cchMax;
register PGETPRIVATEPROFILESTRING16 parg16;
CHAR szLowercase[MAX_PATH];
GETARGPTR(pFrame, sizeof(GETPRIVATEPROFILESTRING16), parg16);
GETPSZPTR(parg16->f1, pszSection);
GETPSZPTR(parg16->f2, pszKey);
GETPSZPTR(parg16->f3, pszDefault);
ALLOCVDMPTR(parg16->f4, parg16->f5, pszReturnBuffer);
GETPSZPTR(parg16->f6, pszFilename);
// PC3270 (Personal communications): while installing this app it calls
// GetPrivateProfileString (sectionname, NULL, defaultbuffer, returnbuffer,
// cch = 0, filename). On win31 this call returns relevant data in return
// buffer and corresponding size as return value. On NT, since the
// buffersize(cch) is '0' no data is copied into the return buffer and
// return value is zero which makes this app abort installation.
//
// So restricted compatibility:
// if above is the case set
// cch = 64k - offset of returnbuffer;
//
// A safer 'cch' would be
// cch = GlobalSize(selector of returnbuffer) -
// (offset of returnbuffer);
// - nanduri
if (!(cchMax = INT32(parg16->f5))) {
if (pszKey == (PSZ)NULL) {
if (pszReturnBuffer != (PSZ)NULL) {
cchMax = 0xffff - (LOW16(parg16->f4));
}
}
}
UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
strcpy(szLowercase, pszFilename);
_strlwr(szLowercase);
if (IS_WIN_INI( szLowercase )) {
if (IS_EMBEDDING_SECTION( pszSection ) &&
!WasSectionRecentlyUpdated() ) {
if( pszKey == NULL ) {
UpdateEmbeddingAllKeys();
} else {
UpdateEmbeddingKey( pszKey );
}
SetLastTimeUpdated();
} else if (pszSection &&
pszKey &&
!_stricmp(pszSection, szDevices) &&
IsFaxPrinterSupportedDevice(pszKey)) {
ul = GETINT16(GetFaxPrinterProfileString(pszSection, pszKey, pszDefault, pszReturnBuffer, cchMax));
goto FlushAndReturn;
}
}
ul = GETUINT16(GetPrivateProfileString(
pszSection,
pszKey,
pszDefault,
pszReturnBuffer,
cchMax,
pszFilename));
// start comaptibility hacks
cFlagsEx = CURRENTPTD()->dwWOWCompatFlagsEx;
if(cFlagsEx & (WOWCFEX_ZAPGPPSDEFBLANKS | WOWCFEX_SAYITSNOTTHERE)) {
//
// Win3.1/Win95 compatibility: Zap any trailing blanks in pszDefault
// with nulls, but only if the default string was returned. To detect
// the default string being returned we need to ignore trailing blanks.
//
// Because of the high usage of this API, we only zap trailing blanks
// if a compatibility bit is turned on.
//
// This code is duplicated in thunks for GetProfileString and
// GetPrivateProfileString, update both if you make changes.
//
if ((cFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) && pszDefault && pszKey) {
int n, nLenDef;
//
// If the returned string is a prefix of the default string...
// ul is strlen(pszReturnBuffer)
//
nLenDef = strlen(pszDefault);
if (nLenDef > (int)ul &&
RtlEqualMemory(pszDefault, pszReturnBuffer, ul)) {
//
// And the only difference is trailing blanks...
//
for (n = (int)ul; n < nLenDef; n++) {
if (' ' != pszDefault[n]) {
break;
}
#ifdef DBCS
if (IsDBCSLeadByte(pszDefault[n]) {
n++;
}
#endif
}
if (n >= nLenDef) {
char szBuf[512];
//
// The returned string is the same as the default string
// without trailing blanks, but this might be coincidence,
// so see if a call with empty pszDefault returns anything.
// If it does, we don't zap because the default isn't
// being used.
//
if (0 == GetPrivateProfileString(pszSection, pszKey, "", szBuf, sizeof szBuf, pszFilename)) {
//
// Zap first trailing blank in pszDefault with null.
//
pszDefault[ul] = 0;
FLUSHVDMPTR(parg16->f3 + ul, 1, pszDefault + ul);
}
}
}
}
// CrossTalk 2.2 gets hung in a loop while trying to match a printer in
// their xtalk.ini file with a printer name in the PrintDlg listbox.
// There is a bug in their code for handling this that gets exposed by
// the fact that NT PrintDlg listboxes do not include the port name as
// Win3.1 & Win'95 do. We avoid the buggy code altogether with this
// hack by telling them that the preferred printer isn't stored in
// xtalk.ini. See bug #43168 a-craigj
if(cFlagsEx & WOWCFEX_SAYITSNOTTHERE) {
if(strstr(szLowercase, "xtalk.ini")) {
if(!_stricmp(pszSection, "Printer")) {
if(!_stricmp(pszKey, "Device")) {
strcpy(pszReturnBuffer, pszDefault);
ul = strlen(pszReturnBuffer);
}
}
}
}
}
#ifdef DEBUG
//
// Make noise on the debugger if pszDefault has trailing blanks at
// this point indicating that WOWCFEX_ZAPGPPSDEFBLANKS might need
// to be turned on for this app.
//
if ( ! (cFlagsEx & WOWCFEX_ZAPGPPSDEFBLANKS) &&
pszKey &&
pszDefault &&
' ' == pszDefault[strlen(pszDefault) - 1]) {
char szMsg[256];
sprintf(szMsg,
"\n"
"WOW32 COMPATIBILITY ALERT: Task %.8s has trailing blanks in pszDefault to\n"
"Get[Private]ProfileString but WOWCFEX_ZAPGPPSDEFBLANKS (0x00000000 0x%08x)\n"
"is not enabled. Try enabling this bit if you're having problems.\n"
"\n",
((PTDB)SEGPTR(CURRENTPTD()->htask16,0))->TDB_ModName,
WOWCFEX_ZAPGPPSDEFBLANKS
);
OutputDebugString(szMsg);
}
#endif
FlushAndReturn:
if (ul) {
FLUSHVDMPTR(parg16->f4, (ul + (pszSection && pszKey) ? 1 : 2), pszReturnBuffer);
LOGDEBUG(8,("GetPrivateProfileString returns '%s'\n", pszReturnBuffer));
}
#ifdef DEBUG
//
// Check for bad return on retrieving entire section by walking
// the section making sure it's full of null-terminated strings
// with an extra null at the end. Also ensure that this all fits
// within the buffer.
//
if (!pszKey) {
PSZ psz;
//
// We don't want to complain if the poorly-formed buffer was the one
// passed in as pszDefault by the caller.
//
// Although the api docs clearly state that pszDefault should never
// be null but win3.1 is nice enough to still deal with this. Delphi is
// passing pszDefault as NULL and this following code causes an
// assertion in WOW. So added the pszDefault check first.
//
// sudeepb 11-Sep-1995
if (!pszDefault || strcmp(pszReturnBuffer, pszDefault)) {
psz = pszReturnBuffer;
while (psz < (pszReturnBuffer + ul + 2) && *psz) {
psz += strlen(psz) + 1;
}
WOW32ASSERTMSGF(
psz < (pszReturnBuffer + ul + 2),
("GetPrivateProfileString of entire section returns poorly formed buffer.\n"
"pszReturnBuffer = %p, return value = %d\n",
pszReturnBuffer,
ul
));
}
}
#endif // DEBUG
FREEPSZPTR(pszSection);
FREEPSZPTR(pszKey);
FREEPSZPTR(pszDefault);
FREEVDMPTR(pszReturnBuffer);
FREEPSZPTR(pszFilename);
FREEARGPTR(parg16);
RETURN(ul);
}
ULONG FASTCALL WK32GetProfileInt(PVDMFRAME pFrame)
{
ULONG ul;
PSZ psz1;
PSZ psz2;
register PGETPROFILEINT16 parg16;
GETARGPTR(pFrame, sizeof(GETPROFILEINT16), parg16);
GETPSZPTR(parg16->f1, psz1);
GETPSZPTR(parg16->f2, psz2);
ul = GETWORD16(GetProfileInt(
psz1,
psz2,
INT32(parg16->f3)
));
//
// In HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics, there
// are a bunch of values that define the screen appearance. You can
// watch these values get updated when you go into the display control
// panel applet and change the "appearance scheme", or any of the
// individual elements. The win95 shell is different than win31 in that it
// sticks "twips" values in there instead of pixels. These are calculated
// with the following formula:
//
// twips = - pixels * 72 * 20 / cyPixelsPerInch
//
// pixels = -twips * cyPixelsPerInch / (72*20)
//
// So if the value is negative, it is in twips, otherwise it in pixels.
// The idea is that these values are device independent. NT is
// different than win95 in that we provide an Ini file mapping to this
// section of the registry where win95 does not. Now, when the Lotus
// Freelance Graphics 2.1 tutorial runs, it mucks around with the look
// of the screen, and it changes the border width of window frames by
// using SystemParametersInfo(). When it tries to restore it, it uses
// GetProfileInt("Windows", "BorderWidth", <default>), which on win31
// returns pixels, on win95 returns the default (no ini mapping), and
// on NT returns TWIPS. Since this negative number is interpreted as
// a huge UINT, then the window frames become huge. What this code
// below will do is translate the number back to pixels. [neilsa]
//
if ((CURRENTPTD()->dwWOWCompatFlagsEx & WOWCFEX_PIXELMETRICS) &&
!_stricmp(psz1, "Windows") &&
!_stricmp(psz2, "BorderWidth") &&
((INT)ul < 0)) {
HDC hDC = CreateDC("DISPLAY", NULL, NULL, NULL);
ul = (ULONG) (-(INT)ul * GetDeviceCaps(hDC, LOGPIXELSY)/(72*20));
DeleteDC(hDC);
}
FREEPSZPTR(psz1);
FREEPSZPTR(psz2);
FREEARGPTR(parg16);
RETURN(ul);
}
ULONG FASTCALL WK32GetPrivateProfileInt(PVDMFRAME pFrame)
{
ULONG ul;
PSZ psz1;
PSZ psz2;
PSZ psz4;
register PGETPRIVATEPROFILEINT16 parg16;
GETARGPTR(pFrame, sizeof(GETPRIVATEPROFILEINT16), parg16);
GETPSZPTR(parg16->f1, psz1);
GETPSZPTR(parg16->f2, psz2);
GETPSZPTR(parg16->f4, psz4);
UpdateDosCurrentDirectory(DIR_DOS_TO_NT);
ul = GETWORD16(GetPrivateProfileInt(
psz1,
psz2,
INT32(parg16->f3),
psz4
));
FREEPSZPTR(psz1);
FREEPSZPTR(psz2);
FREEPSZPTR(psz4);
FREEARGPTR(parg16);
RETURN(ul);
}
ULONG FASTCALL WK32GetModuleFileName(PVDMFRAME pFrame)
{
ULONG ul;
PSZ psz2;
register PGETMODULEFILENAME16 parg16;
HANDLE hT;
GETARGPTR(pFrame, sizeof(GETMODULEFILENAME16), parg16);
ALLOCVDMPTR(parg16->f2, parg16->f3, psz2);
if ( ISTASKALIAS(parg16->f1) ) {
ul = GetHtaskAliasProcessName(parg16->f1,psz2,INT32(parg16->f3));
} else {
hT = (parg16->f1) ? (HMODULE32(parg16->f1)) : GetModuleHandle(NULL) ;
ul = GETINT16(GetModuleFileName(hT, psz2, INT32(parg16->f3)));
}
FLUSHVDMPTR(parg16->f2, strlen(psz2)+1, psz2);
FREEVDMPTR(psz2);
FREEARGPTR(parg16);
RETURN(ul);
}
ULONG FASTCALL WK32FreeResource(PVDMFRAME pFrame)
{
ULONG ul;
register PFREERESOURCE16 parg16;
GETARGPTR(pFrame, sizeof(FREERESOURCE16), parg16);
ul = GETBOOL16(FreeResource(
HCURSOR32(parg16->f1)
));
FREEARGPTR(parg16);
RETURN(ul);
}
ULONG FASTCALL WK32GetDriveType(PVDMFRAME pFrame)
{
ULONG ul;
CHAR RootPathName[] = "?:\\";
register PGETDRIVETYPE16 parg16;
GETARGPTR(pFrame, sizeof(GETDRIVETYPE16), parg16);
// Form Root path
RootPathName[0] = (CHAR)('A'+ parg16->f1);
ul = GetDriveType (RootPathName);
// bugbug - temporariy fixed, should be removed when base changes
// its return value for non-exist drives
// Windows 3.0 sdk manaul said this api should return 1
// if the drive doesn't exist. Windows 3.1 sdk manual said
// this api should return 0 if it failed. Windows 3.1 winfile.exe
// expects 0 for noexisting drives. The NT WIN32 API uses
// 3.0 convention. Therefore, we reset the value to zero
// if it is 1.
if (ul <= 1)
ul = 0;
// DRIVE_CDROM and DRIVE_RAMDISK are not supported under Win 3.1
if ( ul == DRIVE_CDROM ) {
ul = DRIVE_REMOTE;
}
if ( ul == DRIVE_RAMDISK ) {
ul = DRIVE_FIXED;
}
FREEARGPTR(parg16);
RETURN(ul);
}