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