[KERNEL32]: Cleanup and fix multiple bugs in the Version APIs. Code is neater, more efficient, and more compatible.

svn path=/trunk/; revision=52990
This commit is contained in:
Alex Ionescu 2011-07-28 23:58:29 +00:00
parent 72904b8f1f
commit 59ccf2a927

View file

@ -8,107 +8,63 @@
*/ */
#include <k32.h> #include <k32.h>
#include <reactos/buildno.h>
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
DEBUG_CHANNEL(kernel32ver);
#define UNICODIZE1(x) L##x
#define UNICODIZE(x) UNICODIZE1(x)
static UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version");
static UNICODE_STRING ValName = RTL_CONSTANT_STRING(L"ReportAsWorkstation");
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
VOID
static VOID NTAPI
SetRosSpecificInfo(LPOSVERSIONINFOW lpVersionInformation) SetRosSpecificInfo(IN LPOSVERSIONINFOEXW VersionInformation)
{ {
PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = NULL; CHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = (PVOID)Buffer;
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
DWORD ReportAsWorkstation = 0; DWORD ReportAsWorkstation = 0;
HANDLE hKey; HANDLE hKey;
DWORD dwSize; DWORD dwSize;
INT ln, maxlen;
NTSTATUS Status; NTSTATUS Status;
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version");
UNICODE_STRING ValName = RTL_CONSTANT_STRING(L"ReportAsWorkstation");
TRACE("Setting Ros Specific version info\n"); InitializeObjectAttributes(&ObjectAttributes,
&KeyName,
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
if (!lpVersionInformation) /* Don't change anything if the key doesn't exist */
return; Status = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
if (NT_SUCCESS(Status))
/* Only the EX version has a product type */
if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW))
{ {
/* Allocate memory for our reg query */ /* Get the value from the registry and make sure it's a 32-bit value */
dwSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD); Status = NtQueryValueKey(hKey,
kvpInfo = (PKEY_VALUE_PARTIAL_INFORMATION)HeapAlloc(GetProcessHeap(), 0, dwSize); &ValName,
if (!kvpInfo) KeyValuePartialInformation,
return; kvpInfo,
sizeof(Buffer),
InitializeObjectAttributes(&ObjectAttributes, &dwSize);
&KeyName, if ((NT_SUCCESS(Status)) &&
OBJ_OPENIF | OBJ_CASE_INSENSITIVE, (kvpInfo->Type == REG_DWORD) &&
NULL, (kvpInfo->DataLength == sizeof(DWORD)))
NULL);
/* Don't change anything if the key doesn't exist */
Status = NtOpenKey(&hKey,
KEY_READ,
&ObjectAttributes);
if (NT_SUCCESS(Status))
{ {
/* Get the value from the registry */ /* Is the value set? */
Status = NtQueryValueKey(hKey, ReportAsWorkstation = *(PULONG)kvpInfo->Data;
&ValName, if ((VersionInformation->wProductType == VER_NT_SERVER) &&
KeyValuePartialInformation, (ReportAsWorkstation))
kvpInfo,
dwSize,
&dwSize);
if (NT_SUCCESS(Status))
{ {
/* It should be a DWORD */ /* It is, modify the product type to report a workstation */
if (kvpInfo->Type == REG_DWORD) VersionInformation->wProductType = VER_NT_WORKSTATION;
{ DPRINT1("We modified the reported OS from NtProductServer to NtProductWinNt\n");
/* Copy the value for ease of use */
RtlMoveMemory(&ReportAsWorkstation,
kvpInfo->Data,
kvpInfo->DataLength);
/* Is the value set? */
if (((LPOSVERSIONINFOEXW)lpVersionInformation)->wProductType == VER_NT_SERVER &&
ReportAsWorkstation)
{
/* It is, modify the product type to report a workstation */
((LPOSVERSIONINFOEXW)lpVersionInformation)->wProductType = VER_NT_WORKSTATION;
TRACE("We modified the reported OS from NtProductServer to NtProductWinNt\n");
}
}
} }
}
NtClose(hKey); /* Close the handle */
} NtClose(hKey);
}
HeapFree(GetProcessHeap(), 0, kvpInfo);
}
/* Append a reactos specific string to the szCSDVersion string ... very hackish ... */
/* FIXME: Does anything even use this??? I think not.... - Ged */
ln = wcslen(lpVersionInformation->szCSDVersion) + 1;
maxlen = (sizeof(lpVersionInformation->szCSDVersion) / sizeof(lpVersionInformation->szCSDVersion[0]) - 1);
if(maxlen > ln)
{
PWCHAR szVer = lpVersionInformation->szCSDVersion + ln;
RtlZeroMemory(szVer, (maxlen - ln + 1) * sizeof(WCHAR));
wcsncpy(szVer,
L"ReactOS " UNICODIZE(KERNEL_VERSION_STR) L" (Build " UNICODIZE(KERNEL_VERSION_BUILD_STR) L")",
maxlen - ln);
}
} }
/* /*
* @implemented * @implemented
*/ */
@ -116,20 +72,13 @@ DWORD
WINAPI WINAPI
GetVersion(VOID) GetVersion(VOID)
{ {
PPEB pPeb = NtCurrentPeb(); PPEB Peb = NtCurrentPeb();
DWORD nVersion; DWORD Result;
nVersion = MAKEWORD(pPeb->OSMajorVersion, pPeb->OSMinorVersion); Result = MAKELONG(MAKEWORD(Peb->OSMajorVersion, Peb->OSMinorVersion),
(Peb->OSPlatformId ^ 2) << 14);
/* behave consistently when posing as another operating system build number */ Result |= LOWORD(Peb->OSBuildNumber) << 16;
if(pPeb->OSPlatformId != VER_PLATFORM_WIN32_WINDOWS) return Result;
nVersion |= ((DWORD)(pPeb->OSBuildNumber)) << 16;
/* non-NT platform flag */
if(pPeb->OSPlatformId != VER_PLATFORM_WIN32_NT)
nVersion |= 0x80000000;
return nVersion;
} }
/* /*
@ -137,100 +86,28 @@ GetVersion(VOID)
*/ */
BOOL BOOL
WINAPI WINAPI
GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) GetVersionExW(IN LPOSVERSIONINFOW lpVersionInformation)
{ {
NTSTATUS Status; NTSTATUS Status;
LPOSVERSIONINFOEXW lpVersionInformationEx;
if(lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) && if ((lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW)) &&
lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW)) (lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW)))
{ {
/* for some reason win sets ERROR_INSUFFICIENT_BUFFER even if it is large
enough but doesn't match the exact sizes supported, ERROR_INVALID_PARAMETER
would've been much more appropriate... */
SetLastError(ERROR_INSUFFICIENT_BUFFER); SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE; return FALSE;
} }
Status = RtlGetVersion((PRTL_OSVERSIONINFOW)lpVersionInformation); Status = RtlGetVersion((PRTL_OSVERSIONINFOW)lpVersionInformation);
if(NT_SUCCESS(Status)) if (Status == STATUS_SUCCESS)
{ {
/* ReactOS specific changes */ if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW))
SetRosSpecificInfo(lpVersionInformation);
return TRUE;
}
return FALSE;
}
/*
* @implemented
*/
BOOL
WINAPI
GetVersionExA(LPOSVERSIONINFOA lpVersionInformation)
{
OSVERSIONINFOEXW viw;
RtlZeroMemory(&viw, sizeof(viw));
switch(lpVersionInformation->dwOSVersionInfoSize)
{
case sizeof(OSVERSIONINFOA):
viw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
break;
case sizeof(OSVERSIONINFOEXA):
viw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
break;
default:
/* for some reason win sets ERROR_INSUFFICIENT_BUFFER even if it is large
enough but doesn't match the exact sizes supported, ERROR_INVALID_PARAMETER
would've been much more appropriate... */
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
if(GetVersionExW((LPOSVERSIONINFOW)&viw))
{
ANSI_STRING CSDVersionA;
UNICODE_STRING CSDVersionW;
/* copy back fields that match both supported structures */
lpVersionInformation->dwMajorVersion = viw.dwMajorVersion;
lpVersionInformation->dwMinorVersion = viw.dwMinorVersion;
lpVersionInformation->dwBuildNumber = viw.dwBuildNumber;
lpVersionInformation->dwPlatformId = viw.dwPlatformId;
/* convert the win version string */
RtlInitUnicodeString(&CSDVersionW, viw.szCSDVersion);
CSDVersionA.Length = 0;
CSDVersionA.MaximumLength = sizeof(lpVersionInformation->szCSDVersion);
CSDVersionA.Buffer = lpVersionInformation->szCSDVersion;
RtlUnicodeStringToAnsiString(&CSDVersionA, &CSDVersionW, FALSE);
/* convert the ReactOS version string */
CSDVersionW.Buffer = viw.szCSDVersion + CSDVersionW.Length / sizeof(WCHAR) + 1;
CSDVersionW.MaximumLength = sizeof(viw.szCSDVersion) - (CSDVersionW.Length + sizeof(WCHAR));
CSDVersionW.Length = wcslen(CSDVersionW.Buffer) * sizeof(WCHAR);
CSDVersionA.Buffer = lpVersionInformation->szCSDVersion + CSDVersionA.Length + 1;
CSDVersionA.MaximumLength = sizeof(lpVersionInformation->szCSDVersion) - (CSDVersionA.Length + 1);
CSDVersionA.Length = 0;
RtlUnicodeStringToAnsiString(&CSDVersionA, &CSDVersionW, FALSE);
/* copy back the extended fields */
if(viw.dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW))
{ {
((LPOSVERSIONINFOEXA)lpVersionInformation)->wServicePackMajor = viw.wServicePackMajor; lpVersionInformationEx = (PVOID)lpVersionInformation;
((LPOSVERSIONINFOEXA)lpVersionInformation)->wServicePackMinor = viw.wServicePackMinor; lpVersionInformationEx->wReserved = 0;
((LPOSVERSIONINFOEXA)lpVersionInformation)->wSuiteMask = viw.wSuiteMask;
((LPOSVERSIONINFOEXA)lpVersionInformation)->wProductType = viw.wProductType; /* ReactOS specific changes */
((LPOSVERSIONINFOEXA)lpVersionInformation)->wReserved = viw.wReserved; SetRosSpecificInfo(lpVersionInformationEx);
} }
return TRUE; return TRUE;
@ -239,65 +116,108 @@ GetVersionExA(LPOSVERSIONINFOA lpVersionInformation)
return FALSE; return FALSE;
} }
/*
* @implemented
*/
BOOL
WINAPI
GetVersionExA(IN LPOSVERSIONINFOA lpVersionInformation)
{
OSVERSIONINFOEXW VersionInformation;
LPOSVERSIONINFOEXA lpVersionInformationEx;
UNICODE_STRING CsdVersionW;
NTSTATUS Status;
ANSI_STRING CsdVersionA;
if ((lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA)) &&
(lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXA)))
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
VersionInformation.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
if (!GetVersionExW((LPOSVERSIONINFOW)&VersionInformation)) return FALSE;
/* Copy back fields that match both supported structures */
lpVersionInformation->dwMajorVersion = VersionInformation.dwMajorVersion;
lpVersionInformation->dwMinorVersion = VersionInformation.dwMinorVersion;
lpVersionInformation->dwBuildNumber = VersionInformation.dwBuildNumber;
lpVersionInformation->dwPlatformId = VersionInformation.dwPlatformId;
if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA))
{
lpVersionInformationEx = (PVOID)lpVersionInformation;
lpVersionInformationEx->wServicePackMajor = VersionInformation.wServicePackMajor;
lpVersionInformationEx->wServicePackMinor = VersionInformation.wServicePackMinor;
lpVersionInformationEx->wSuiteMask = VersionInformation.wSuiteMask;
lpVersionInformationEx->wProductType = VersionInformation.wProductType;
lpVersionInformationEx->wReserved = VersionInformation.wReserved;
}
/* Convert the CSD string */
RtlInitEmptyAnsiString(&CsdVersionA,
lpVersionInformation->szCSDVersion,
sizeof(lpVersionInformation->szCSDVersion));
RtlInitUnicodeString(&CsdVersionW, VersionInformation.szCSDVersion);
Status = RtlUnicodeStringToAnsiString(&CsdVersionA, &CsdVersionW, FALSE);
return (NT_SUCCESS(Status));
}
/* /*
* @implemented * @implemented
*/ */
BOOL BOOL
WINAPI WINAPI
VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation, VerifyVersionInfoW(IN LPOSVERSIONINFOEXW lpVersionInformation,
DWORD dwTypeMask, IN DWORD dwTypeMask,
DWORDLONG dwlConditionMask) IN DWORDLONG dwlConditionMask)
{ {
NTSTATUS Status; NTSTATUS Status;
Status = RtlVerifyVersionInfo((PRTL_OSVERSIONINFOEXW)lpVersionInformation, Status = RtlVerifyVersionInfo((PRTL_OSVERSIONINFOEXW)lpVersionInformation,
dwTypeMask, dwTypeMask,
dwlConditionMask); dwlConditionMask);
switch(Status) switch (Status)
{ {
case STATUS_INVALID_PARAMETER: case STATUS_INVALID_PARAMETER:
SetLastError(ERROR_BAD_ARGUMENTS); SetLastError(ERROR_BAD_ARGUMENTS);
return FALSE; return FALSE;
case STATUS_REVISION_MISMATCH: case STATUS_REVISION_MISMATCH:
SetLastError(ERROR_OLD_WIN_VERSION); DPRINT1("ReactOS returning version mismatch. Investigate!\n");
return FALSE; SetLastError(ERROR_OLD_WIN_VERSION);
return FALSE;
default: default:
/* RtlVerifyVersionInfo shouldn't report any other failure code! */ /* RtlVerifyVersionInfo shouldn't report any other failure code! */
ASSERT(NT_SUCCESS(Status)); ASSERT(NT_SUCCESS(Status));
/* ReactOS specific changes */
SetRosSpecificInfo((LPOSVERSIONINFOW)lpVersionInformation);
return TRUE; return TRUE;
} }
} }
/* /*
* @implemented * @implemented
*/ */
BOOL BOOL
WINAPI WINAPI
VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation, VerifyVersionInfoA(IN LPOSVERSIONINFOEXA lpVersionInformation,
DWORD dwTypeMask, IN DWORD dwTypeMask,
DWORDLONG dwlConditionMask) IN DWORDLONG dwlConditionMask)
{ {
OSVERSIONINFOEXW viex; OSVERSIONINFOEXW viex;
/* NOTE: szCSDVersion is ignored, we don't need to convert it to Unicode */
viex.dwOSVersionInfoSize = sizeof(viex); viex.dwOSVersionInfoSize = sizeof(viex);
viex.dwMajorVersion = lpVersionInformation->dwMajorVersion; viex.dwMajorVersion = lpVersionInformation->dwMajorVersion;
viex.dwMinorVersion = lpVersionInformation->dwMinorVersion; viex.dwMinorVersion = lpVersionInformation->dwMinorVersion;
viex.dwBuildNumber = lpVersionInformation->dwBuildNumber; viex.dwBuildNumber = lpVersionInformation->dwBuildNumber;
viex.dwPlatformId = lpVersionInformation->dwPlatformId; viex.dwPlatformId = lpVersionInformation->dwPlatformId;
/* NOTE: szCSDVersion is ignored, we don't need to convert it to unicode */
viex.wServicePackMajor = lpVersionInformation->wServicePackMajor; viex.wServicePackMajor = lpVersionInformation->wServicePackMajor;
viex.wServicePackMinor = lpVersionInformation->wServicePackMinor; viex.wServicePackMinor = lpVersionInformation->wServicePackMinor;
viex.wSuiteMask = lpVersionInformation->wSuiteMask; viex.wSuiteMask = lpVersionInformation->wSuiteMask;
viex.wProductType = lpVersionInformation->wProductType; viex.wProductType = lpVersionInformation->wProductType;
viex.wReserved = lpVersionInformation->wReserved; viex.wReserved = lpVersionInformation->wReserved;
return VerifyVersionInfoW(&viex, dwTypeMask, dwlConditionMask); return VerifyVersionInfoW(&viex, dwTypeMask, dwlConditionMask);
} }