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