[KERNEL32]: While working on the CMAKE branch, Amine and myself discovered a rather...
[reactos.git] / reactos / dll / win32 / kernel32 / misc / version.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/misc/version.c
5 * PURPOSE: Version functions
6 * PROGRAMMER: Ariadne (ariadne@xs4all.nl)
7 Ged Murphy (gedmurphy@reactos.org)
8 */
9
10 #include <k32.h>
11 #include <reactos/buildno.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #define UNICODIZE1(x) L##x
16 #define UNICODIZE(x) UNICODIZE1(x)
17
18 static UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\ReactOS\\Settings\\Version");
19 static UNICODE_STRING ValName = RTL_CONSTANT_STRING(L"ReportAsWorkstation");
20
21 /* FUNCTIONS ******************************************************************/
22
23
24 static VOID
25 SetRosSpecificInfo(LPOSVERSIONINFOW lpVersionInformation)
26 {
27 PKEY_VALUE_PARTIAL_INFORMATION kvpInfo = NULL;
28 OBJECT_ATTRIBUTES ObjectAttributes;
29 DWORD ReportAsWorkstation = 0;
30 HANDLE hKey;
31 DWORD dwSize;
32 INT ln, maxlen;
33 NTSTATUS Status;
34
35 TRACE("Setting Ros Specific version info\n");
36
37 if (!lpVersionInformation)
38 return;
39
40 /* Only the EX version has a product type */
41 if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW))
42 {
43 /* Allocate memory for our reg query */
44 dwSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD);
45 kvpInfo = (PKEY_VALUE_PARTIAL_INFORMATION)HeapAlloc(GetProcessHeap(), 0, dwSize);
46 if (!kvpInfo)
47 return;
48
49 InitializeObjectAttributes(&ObjectAttributes,
50 &KeyName,
51 OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
52 NULL,
53 NULL);
54
55 /* Don't change anything if the key doesn't exist */
56 Status = NtOpenKey(&hKey,
57 KEY_READ,
58 &ObjectAttributes);
59 if (NT_SUCCESS(Status))
60 {
61 /* Get the value from the registry */
62 Status = NtQueryValueKey(hKey,
63 &ValName,
64 KeyValuePartialInformation,
65 kvpInfo,
66 dwSize,
67 &dwSize);
68 if (NT_SUCCESS(Status))
69 {
70 /* It should be a DWORD */
71 if (kvpInfo->Type == REG_DWORD)
72 {
73 /* Copy the value for ease of use */
74 RtlMoveMemory(&ReportAsWorkstation,
75 kvpInfo->Data,
76 kvpInfo->DataLength);
77
78 /* Is the value set? */
79 if (((LPOSVERSIONINFOEXW)lpVersionInformation)->wProductType == VER_NT_SERVER &&
80 ReportAsWorkstation)
81 {
82 /* It is, modify the product type to report a workstation */
83 ((LPOSVERSIONINFOEXW)lpVersionInformation)->wProductType = VER_NT_WORKSTATION;
84 TRACE("We modified the reported OS from NtProductServer to NtProductWinNt\n");
85 }
86 }
87 }
88
89 NtClose(hKey);
90 }
91
92 HeapFree(GetProcessHeap(), 0, kvpInfo);
93 }
94
95
96 /* Append a reactos specific string to the szCSDVersion string ... very hackish ... */
97 /* FIXME: Does anything even use this??? I think not.... - Ged */
98 ln = wcslen(lpVersionInformation->szCSDVersion) + 1;
99 maxlen = (sizeof(lpVersionInformation->szCSDVersion) / sizeof(lpVersionInformation->szCSDVersion[0]) - 1);
100 if(maxlen > ln)
101 {
102 PWCHAR szVer = lpVersionInformation->szCSDVersion + ln;
103 RtlZeroMemory(szVer, (maxlen - ln + 1) * sizeof(WCHAR));
104 wcsncpy(szVer,
105 L"ReactOS " UNICODIZE(KERNEL_VERSION_STR) L" (Build " UNICODIZE(KERNEL_VERSION_BUILD_STR) L")",
106 maxlen - ln);
107 }
108 }
109
110
111 /*
112 * @implemented
113 */
114 DWORD
115 WINAPI
116 GetVersion(VOID)
117 {
118 PPEB pPeb = NtCurrentPeb();
119 DWORD nVersion;
120
121 nVersion = MAKEWORD(pPeb->OSMajorVersion, pPeb->OSMinorVersion);
122
123 /* behave consistently when posing as another operating system build number */
124 if(pPeb->OSPlatformId != VER_PLATFORM_WIN32_WINDOWS)
125 nVersion |= ((DWORD)(pPeb->OSBuildNumber)) << 16;
126
127 /* non-NT platform flag */
128 if(pPeb->OSPlatformId != VER_PLATFORM_WIN32_NT)
129 nVersion |= 0x80000000;
130
131 return nVersion;
132 }
133
134 /*
135 * @implemented
136 */
137 BOOL
138 WINAPI
139 GetVersionExW(LPOSVERSIONINFOW lpVersionInformation)
140 {
141 NTSTATUS Status;
142
143 if(lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) &&
144 lpVersionInformation->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW))
145 {
146 /* for some reason win sets ERROR_INSUFFICIENT_BUFFER even if it is large
147 enough but doesn't match the exact sizes supported, ERROR_INVALID_PARAMETER
148 would've been much more appropriate... */
149 SetLastError(ERROR_INSUFFICIENT_BUFFER);
150 return FALSE;
151 }
152
153 Status = RtlGetVersion((PRTL_OSVERSIONINFOW)lpVersionInformation);
154 if(NT_SUCCESS(Status))
155 {
156 /* ReactOS specific changes */
157 SetRosSpecificInfo(lpVersionInformation);
158
159 return TRUE;
160 }
161
162 return FALSE;
163 }
164
165
166 /*
167 * @implemented
168 */
169 BOOL
170 WINAPI
171 GetVersionExA(LPOSVERSIONINFOA lpVersionInformation)
172 {
173 OSVERSIONINFOEXW viw;
174
175 RtlZeroMemory(&viw, sizeof(viw));
176
177 switch(lpVersionInformation->dwOSVersionInfoSize)
178 {
179 case sizeof(OSVERSIONINFOA):
180 viw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
181 break;
182
183 case sizeof(OSVERSIONINFOEXA):
184 viw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
185 break;
186
187 default:
188 /* for some reason win sets ERROR_INSUFFICIENT_BUFFER even if it is large
189 enough but doesn't match the exact sizes supported, ERROR_INVALID_PARAMETER
190 would've been much more appropriate... */
191 SetLastError(ERROR_INSUFFICIENT_BUFFER);
192 return FALSE;
193 }
194
195 if(GetVersionExW((LPOSVERSIONINFOW)&viw))
196 {
197 ANSI_STRING CSDVersionA;
198 UNICODE_STRING CSDVersionW;
199
200 /* copy back fields that match both supported structures */
201 lpVersionInformation->dwMajorVersion = viw.dwMajorVersion;
202 lpVersionInformation->dwMinorVersion = viw.dwMinorVersion;
203 lpVersionInformation->dwBuildNumber = viw.dwBuildNumber;
204 lpVersionInformation->dwPlatformId = viw.dwPlatformId;
205
206 /* convert the win version string */
207 RtlInitUnicodeString(&CSDVersionW, viw.szCSDVersion);
208
209 CSDVersionA.Length = 0;
210 CSDVersionA.MaximumLength = sizeof(lpVersionInformation->szCSDVersion);
211 CSDVersionA.Buffer = lpVersionInformation->szCSDVersion;
212
213 RtlUnicodeStringToAnsiString(&CSDVersionA, &CSDVersionW, FALSE);
214
215 /* convert the ReactOS version string */
216 CSDVersionW.Buffer = viw.szCSDVersion + CSDVersionW.Length / sizeof(WCHAR) + 1;
217 CSDVersionW.MaximumLength = sizeof(viw.szCSDVersion) - (CSDVersionW.Length + sizeof(WCHAR));
218 CSDVersionW.Length = wcslen(CSDVersionW.Buffer) * sizeof(WCHAR);
219 CSDVersionA.Buffer = lpVersionInformation->szCSDVersion + CSDVersionA.Length + 1;
220 CSDVersionA.MaximumLength = sizeof(lpVersionInformation->szCSDVersion) - (CSDVersionA.Length + 1);
221 CSDVersionA.Length = 0;
222
223 RtlUnicodeStringToAnsiString(&CSDVersionA, &CSDVersionW, FALSE);
224
225 /* copy back the extended fields */
226 if(viw.dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW))
227 {
228 ((LPOSVERSIONINFOEXA)lpVersionInformation)->wServicePackMajor = viw.wServicePackMajor;
229 ((LPOSVERSIONINFOEXA)lpVersionInformation)->wServicePackMinor = viw.wServicePackMinor;
230 ((LPOSVERSIONINFOEXA)lpVersionInformation)->wSuiteMask = viw.wSuiteMask;
231 ((LPOSVERSIONINFOEXA)lpVersionInformation)->wProductType = viw.wProductType;
232 ((LPOSVERSIONINFOEXA)lpVersionInformation)->wReserved = viw.wReserved;
233 }
234
235 return TRUE;
236 }
237
238 return FALSE;
239 }
240
241
242 /*
243 * @implemented
244 */
245 BOOL
246 WINAPI
247 VerifyVersionInfoW(LPOSVERSIONINFOEXW lpVersionInformation,
248 DWORD dwTypeMask,
249 DWORDLONG dwlConditionMask)
250 {
251 NTSTATUS Status;
252
253 Status = RtlVerifyVersionInfo((PRTL_OSVERSIONINFOEXW)lpVersionInformation,
254 dwTypeMask,
255 dwlConditionMask);
256 switch(Status)
257 {
258 case STATUS_INVALID_PARAMETER:
259 SetLastError(ERROR_BAD_ARGUMENTS);
260 return FALSE;
261
262 case STATUS_REVISION_MISMATCH:
263 SetLastError(ERROR_OLD_WIN_VERSION);
264 return FALSE;
265
266 default:
267 /* RtlVerifyVersionInfo shouldn't report any other failure code! */
268 ASSERT(NT_SUCCESS(Status));
269
270 /* ReactOS specific changes */
271 SetRosSpecificInfo((LPOSVERSIONINFOW)lpVersionInformation);
272
273 return TRUE;
274 }
275 }
276
277
278 /*
279 * @implemented
280 */
281 BOOL
282 WINAPI
283 VerifyVersionInfoA(LPOSVERSIONINFOEXA lpVersionInformation,
284 DWORD dwTypeMask,
285 DWORDLONG dwlConditionMask)
286 {
287 OSVERSIONINFOEXW viex;
288
289 viex.dwOSVersionInfoSize = sizeof(viex);
290 viex.dwMajorVersion = lpVersionInformation->dwMajorVersion;
291 viex.dwMinorVersion = lpVersionInformation->dwMinorVersion;
292 viex.dwBuildNumber = lpVersionInformation->dwBuildNumber;
293 viex.dwPlatformId = lpVersionInformation->dwPlatformId;
294 /* NOTE: szCSDVersion is ignored, we don't need to convert it to unicode */
295 viex.wServicePackMajor = lpVersionInformation->wServicePackMajor;
296 viex.wServicePackMinor = lpVersionInformation->wServicePackMinor;
297 viex.wSuiteMask = lpVersionInformation->wSuiteMask;
298 viex.wProductType = lpVersionInformation->wProductType;
299 viex.wReserved = lpVersionInformation->wReserved;
300
301 return VerifyVersionInfoW(&viex, dwTypeMask, dwlConditionMask);
302 }