1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2007-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2016-2016 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Kern Sibbald, August 2007
24 *
25 * Note, some of the original Bareos Windows startup and service handling code
26 * was derived from VNC code that was used in apcupsd then ported to
27 * Bareos. However, since then the code has been significantly enhanced
28 * and largely rewritten.
29 *
30 * Evidently due to the nature of Windows startup code and service
31 * handling code, certain similarities remain. Thanks to the original
32 * VNC authors.
33 *
34 * This is a generic main routine, which is used by all three
35 * of the daemons. Each one compiles it with slightly different
36 * #defines.
37 */
38
39 #include "include/bareos.h"
40 #include "win32.h"
41 #include "who.h"
42 #include <signal.h>
43 #include <pthread.h>
44
45 #undef _WIN32_IE
46 #ifdef MINGW64
47 # define _WIN32_IE 0x0501
48 #else
49 # define _WIN32_IE 0x0401
50 #endif // MINGW64
51 #undef _WIN32_WINNT
52 #define _WIN32_WINNT 0x0501
53 #include <commctrl.h>
54
55
56 /* Globals */
57 HINSTANCE appInstance;
58 DWORD mainthreadId;
59 bool opt_debug = false;
60 bool have_service_api;
61 DWORD service_thread_id = 0;
62 char win_os[300];
63
64 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz);
65
66
67 #define MAX_COMMAND_ARGS 100
68 static char *command_args[MAX_COMMAND_ARGS] = { (char *)LC_APP_NAME, NULL };
69 static int num_command_args = 1;
70 static pid_t main_pid;
71 static pthread_t main_tid;
72
73 const char usage[] = APP_NAME "[/debug] [/service] [/run] [/kill] [/install] [/remove] [/help]\n";
74
75 /*
76 *
77 * Main Windows entry point.
78 *
79 * We parse the command line and either calls the main App
80 * or starts up the service.
81 */
WinMain(HINSTANCE Instance,HINSTANCE,PSTR CmdLine,int)82 int WINAPI WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, PSTR CmdLine,
83 int /*show*/)
84 {
85 char *cmdLine = CmdLine;
86 char *wordPtr, *tempPtr;
87 int i, quote;
88 OSVERSIONINFO osversioninfo;
89 osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
90
91
92 /* Save the application instance and main thread id */
93 appInstance = Instance;
94 mainthreadId = GetCurrentThreadId();
95
96 if (GetVersionEx(&osversioninfo) &&
97 osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
98 have_service_api = true;
99 }
100
101 GetWindowsVersionString(win_os, sizeof(win_os));
102
103 main_pid = getpid();
104 main_tid = pthread_self();
105
106 INITCOMMONCONTROLSEX initCC = {
107 sizeof(INITCOMMONCONTROLSEX),
108 ICC_STANDARD_CLASSES
109 };
110
111 InitCommonControlsEx(&initCC);
112
113 /*
114 * Funny things happen with the command line if the
115 * execution comes from c:/Program Files/bareos/bareos.exe
116 * We get a command line like: Files/bareos/bareos.exe" options
117 * I.e. someone stops scanning command line on a space, not
118 * realizing that the filename is quoted!!!!!!!!!!
119 * So if first character is not a double quote and
120 * the last character before first space is a double
121 * quote, we throw away the junk.
122 */
123
124 wordPtr = cmdLine;
125 while (*wordPtr && *wordPtr != ' ')
126 wordPtr++;
127 if (wordPtr > cmdLine) /* backup to char before space */
128 wordPtr--;
129 /* if first character is not a quote and last is, junk it */
130 if (*cmdLine != '"' && *wordPtr == '"') {
131 cmdLine = wordPtr + 1;
132 }
133
134 /*
135 * Build Unix style argc *argv[] for the main "Unix" code
136 * stripping out any Windows options
137 */
138
139 /* Don't NULL command_args[0] !!! */
140 for (i=1;i<MAX_COMMAND_ARGS;i++) {
141 command_args[i] = NULL;
142 }
143
144 char *pszArgs = bstrdup(cmdLine);
145 wordPtr = pszArgs;
146 quote = 0;
147 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
148 wordPtr++;
149 if (*wordPtr == '\"') {
150 quote = 1;
151 wordPtr++;
152 } else if (*wordPtr == '/') {
153 /* Skip Windows options */
154 while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
155 wordPtr++;
156 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
157 wordPtr++;
158 }
159 if (*wordPtr) {
160 while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
161 tempPtr = wordPtr;
162 if (quote) {
163 while (*tempPtr && *tempPtr != '\"')
164 tempPtr++;
165 quote = 0;
166 } else {
167 while (*tempPtr && *tempPtr != ' ')
168 tempPtr++;
169 }
170 if (*tempPtr)
171 *(tempPtr++) = '\0';
172 command_args[num_command_args++] = wordPtr;
173 wordPtr = tempPtr;
174 while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
175 wordPtr++;
176 if (*wordPtr == '\"') {
177 quote = 1;
178 wordPtr++;
179 }
180 }
181 }
182
183 /*
184 * Now process Windows command line options. Most of these options
185 * are single shot -- i.e. we accept one option, do something and
186 * Terminate.
187 */
188 for (i = 0; i < (int)strlen(cmdLine); i++) {
189 char *p = &cmdLine[i];
190
191 if (*p <= ' ') {
192 continue; /* toss junk */
193 }
194
195 if (*p != '/') {
196 break; /* syntax error */
197 }
198
199 /* Start as a service? */
200 if (strncasecmp(p, "/service", 8) == 0) {
201 return bareosServiceMain(); /* yes, run as a service */
202 }
203
204 /* Stop any running copy? */
205 if (strncasecmp(p, "/kill", 5) == 0) {
206 return stopRunningBareos();
207 }
208
209 /* Run app as user program? */
210 if (strncasecmp(p, "/run", 4) == 0) {
211 return BareosAppMain(); /* yes, run as a user program */
212 }
213
214 /* Install Bareos in registry? */
215 if (strncasecmp(p, "/install", 8) == 0) {
216 return installService(p+8); /* Pass command options */
217 }
218
219 /* Remove Bareos registry entry? */
220 if (strncasecmp(p, "/remove", 7) == 0) {
221 return removeService();
222 }
223
224 /* Set debug mode? -- causes more dialogs to be displayed */
225 if (strncasecmp(p, "/debug", 6) == 0) {
226 opt_debug = true;
227 i += 6; /* skip /debug */
228 continue;
229 }
230
231 /* Display help? -- displays usage */
232 if (strncasecmp(p, "/help", 5) == 0) {
233 MessageBox(NULL, usage, APP_DESC, MB_OK|MB_ICONINFORMATION);
234 return 0;
235 }
236
237 MessageBox(NULL, cmdLine, _("Bad Command Line Option"), MB_OK);
238
239 /* Show the usage dialog */
240 MessageBox(NULL, usage, APP_DESC, MB_OK | MB_ICONINFORMATION);
241
242 return 1;
243 }
244 return BareosAppMain();
245 }
246
247 /*
248 * Minimalist winproc when don't have tray monitor
249 */
bacWinProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)250 LRESULT CALLBACK bacWinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
251 {
252 switch (iMsg) {
253 case WM_DESTROY:
254 PostQuitMessage(0);
255 return 0;
256 }
257 return DefWindowProc(hwnd, iMsg, wParam, lParam);
258 }
259
260 /*
261 * Called as a thread from BareosAppMain()
262 * Here we handle the Windows messages
263 */
Main_Msg_Loop(LPVOID lpwThreadParam)264 void *Main_Msg_Loop(LPVOID lpwThreadParam)
265 {
266 MSG msg;
267
268 pthread_detach(pthread_self());
269
270 /*
271 * Since we are the only thread with a message loop
272 * mark ourselves as the service thread so that
273 * we can receive all the window events.
274 */
275 service_thread_id = GetCurrentThreadId();
276
277 /* Create a window to handle Windows messages */
278 WNDCLASSEX baclass;
279
280 baclass.cbSize = sizeof(baclass);
281 baclass.style = 0;
282 baclass.lpfnWndProc = bacWinProc;
283 baclass.cbClsExtra = 0;
284 baclass.cbWndExtra = 0;
285 baclass.hInstance = appInstance;
286 baclass.hIcon = NULL;
287 baclass.hCursor = NULL;
288 baclass.hbrBackground = NULL;
289 baclass.lpszMenuName = NULL;
290 baclass.lpszClassName = APP_NAME;
291 baclass.hIconSm = NULL;
292
293 RegisterClassEx(&baclass);
294
295 if (CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
296 CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
297 NULL, NULL, appInstance, NULL) == NULL) {
298 PostQuitMessage(0);
299 }
300
301 /* Now enter the Windows message handling loop until told to quit! */
302 while (GetMessage(&msg, NULL, 0,0)) {
303 TranslateMessage(&msg);
304 DispatchMessage(&msg);
305 }
306
307 /* If we get here, we are shutting down */
308
309 if (have_service_api) {
310 /* Mark that we're no longer running */
311 service_thread_id = 0;
312 /* Tell the service manager that we've stopped. */
313 ReportStatus(SERVICE_STOPPED, service_error, 0);
314 }
315 /* Tell main "Unix" program to go away */
316 TerminateApp(0);
317
318 /* Should not get here */
319 pthread_kill(main_tid, SIGTERM); /* ask main thread to Terminate */
320 sleep(1);
321 kill(main_pid, SIGTERM); /* kill main thread */
322 _exit(0);
323 }
324
325
326 /*
327 * This is the main routine for Bareos when running as an application,
328 * or after the service has started up.
329 */
BareosAppMain()330 int BareosAppMain()
331 {
332 pthread_t tid;
333 DWORD dwCharsWritten;
334
335 OSDependentInit();
336
337 /* If no arguments were given then just run */
338 if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
339 if (opt_debug) {
340 AllocConsole();
341 }
342 }
343 WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
344
345 /* Startup networking */
346 WSA_Init();
347
348 /* Set this process to be the last application to be shut down. */
349 if (p_SetProcessShutdownParameters) {
350 p_SetProcessShutdownParameters(0x100, 0);
351 }
352
353 /* Create a thread to handle the Windows messages */
354 pthread_create(&tid, NULL, Main_Msg_Loop, (void *)0);
355
356 /* Call the Unix Bareos daemon */
357 BareosMain(num_command_args, command_args);
358 PostQuitMessage(0); /* Terminate our main message loop */
359
360 WSACleanup();
361 _exit(0);
362 }
363
364
PauseMsg(const char * file,const char * func,int line,const char * msg)365 void PauseMsg(const char *file, const char *func, int line, const char *msg)
366 {
367 char buf[1000];
368 if (msg) {
369 Bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
370 } else {
371 Bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
372 }
373 MessageBox(NULL, buf, "Pause", MB_OK);
374 }
375
376 #include <windows.h>
377 #include <tchar.h>
378 #include <stdio.h>
379
380 #ifndef PRODUCT_UNLICENSED
381 #define PRODUCT_UNLICENSED 0xABCDABCD
382 #define PRODUCT_BUSINESS 0x00000006
383 #define PRODUCT_BUSINESS_N 0x00000010
384 #define PRODUCT_CLUSTER_SERVER 0x00000012
385 #define PRODUCT_DATACENTER_SERVER 0x00000008
386 #define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C
387 #define PRODUCT_DATACENTER_SERVER_CORE_V 0x00000027
388 #define PRODUCT_DATACENTER_SERVER_V 0x00000025
389 #define PRODUCT_ENTERPRISE 0x00000004
390 #define PRODUCT_ENTERPRISE_E 0x00000046
391 #define PRODUCT_ENTERPRISE_N 0x0000001B
392 #define PRODUCT_ENTERPRISE_SERVER 0x0000000A
393 #define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E
394 #define PRODUCT_ENTERPRISE_SERVER_CORE_V 0x00000029
395 #define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F
396 #define PRODUCT_ENTERPRISE_SERVER_V 0x00000026
397 #define PRODUCT_HOME_BASIC 0x00000002
398 #define PRODUCT_HOME_BASIC_E 0x00000043
399 #define PRODUCT_HOME_BASIC_N 0x00000005
400 #define PRODUCT_HOME_PREMIUM 0x00000003
401 #define PRODUCT_HOME_PREMIUM_E 0x00000044
402 #define PRODUCT_HOME_PREMIUM_N 0x0000001A
403 #define PRODUCT_HYPERV 0x0000002A
404 #define PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT 0x0000001E
405 #define PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING 0x00000020
406 #define PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY 0x0000001F
407 #define PRODUCT_PROFESSIONAL 0x00000030
408 #define PRODUCT_PROFESSIONAL_E 0x00000045
409 #define PRODUCT_PROFESSIONAL_N 0x00000031
410 #define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018
411 #define PRODUCT_SERVER_FOR_SMALLBUSINESS_V 0x00000023
412 #define PRODUCT_SERVER_FOUNDATION 0x00000021
413 #define PRODUCT_SMALLBUSINESS_SERVER 0x00000009
414 #define PRODUCT_SOLUTION_EMBEDDEDSERVER 0x00000038
415 #define PRODUCT_STANDARD_SERVER 0x00000007
416 #define PRODUCT_STANDARD_SERVER_CORE 0x0000000D
417 #define PRODUCT_STANDARD_SERVER_CORE_V 0x00000028
418 #define PRODUCT_STANDARD_SERVER_V 0x00000024
419 #define PRODUCT_STARTER 0x0000000B
420 #define PRODUCT_STARTER_E 0x00000042
421 #define PRODUCT_STARTER_N 0x0000002F
422 #define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017
423 #define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014
424 #define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015
425 #define PRODUCT_STORAGE_WORKGROUP_SERVER 0x00000016
426 #define PRODUCT_UNDEFINED 0x00000000
427 #define PRODUCT_ULTIMATE 0x00000001
428 #define PRODUCT_ULTIMATE_E 0x00000047
429 #define PRODUCT_ULTIMATE_N 0x0000001C
430 #define PRODUCT_WEB_SERVER 0x00000011
431 #define PRODUCT_WEB_SERVER_CORE 0x0000001D
432
433 #define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19
434 #define SM_SERVERR2 89
435 #define VER_SERVER_NT 0x80000000
436
437 #endif
438
439 #ifndef PRODUCT_PROFESSIONAL
440 #define PRODUCT_PROFESSIONAL 0x00000030
441 #endif
442 #ifndef VER_SUITE_STORAGE_SERVER
443 #define VER_SUITE_STORAGE_SERVER 0x00002000
444 #endif
445 #ifndef VER_SUITE_COMPUTE_SERVER
446 #define VER_SUITE_COMPUTE_SERVER 0x00004000
447 #endif
448
449 /* Unknown value */
450 #undef VER_SUITE_WH_SERVER
451 #define VER_SUITE_WH_SERVER -1
452
453
454 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
455 typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
456
457 /*
458 * Get Windows version display string
459 */
GetWindowsVersionString(LPTSTR osbuf,int maxsiz)460 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz)
461 {
462 OSVERSIONINFOEX osvi;
463 SYSTEM_INFO si;
464 PGNSI pGNSI;
465 PGPI pGPI;
466 BOOL bOsVersionInfoEx;
467 DWORD dwType;
468
469 memset(&si, 0, sizeof(SYSTEM_INFO));
470 memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
471
472 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
473
474 if (!(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)))
475 return 1;
476
477 // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
478
479 pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
480 "GetNativeSystemInfo");
481 if (pGNSI) {
482 pGNSI(&si);
483 } else {
484 GetSystemInfo(&si);
485 }
486
487 if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion > 4) {
488 bstrncpy(osbuf, TEXT("Microsoft "), maxsiz);
489
490 /*
491 * Test for the specific product.
492 */
493 switch (osvi.dwMajorVersion) {
494 case 6:
495 switch (osvi.dwMinorVersion) {
496 case 0:
497 if (osvi.wProductType == VER_NT_WORKSTATION) {
498 bstrncat(osbuf, TEXT("Windows Vista "), maxsiz);
499 } else {
500 bstrncat(osbuf, TEXT("Windows Server 2008 "), maxsiz);
501 }
502 break;
503 case 1:
504 if (osvi.wProductType == VER_NT_WORKSTATION) {
505 bstrncat(osbuf, TEXT("Windows 7 "), maxsiz);
506 } else {
507 bstrncat(osbuf, TEXT("Windows Server 2008 R2 "), maxsiz);
508 }
509 break;
510 case 2:
511 if (osvi.wProductType == VER_NT_WORKSTATION) {
512 bstrncat(osbuf, TEXT("Windows 8 "), maxsiz);
513 } else {
514 bstrncat(osbuf, TEXT("Windows Server 2012 "), maxsiz);
515 }
516 break;
517 default:
518 bstrncat(osbuf, TEXT("Windows Unknown Release "), maxsiz);
519 break;
520 }
521
522 pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo");
523 if (pGPI) {
524 pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
525 } else {
526 dwType = PRODUCT_HOME_BASIC;
527 }
528
529 switch (dwType) {
530 case PRODUCT_ULTIMATE:
531 bstrncat(osbuf, TEXT("Ultimate Edition"), maxsiz);
532 break;
533 case PRODUCT_PROFESSIONAL:
534 bstrncat(osbuf, TEXT("Professional"), maxsiz);
535 break;
536 case PRODUCT_HOME_PREMIUM:
537 bstrncat(osbuf, TEXT("Home Premium Edition"), maxsiz);
538 break;
539 case PRODUCT_HOME_BASIC:
540 bstrncat(osbuf, TEXT("Home Basic Edition"), maxsiz);
541 break;
542 case PRODUCT_ENTERPRISE:
543 bstrncat(osbuf, TEXT("Enterprise Edition"), maxsiz);
544 break;
545 case PRODUCT_BUSINESS:
546 bstrncat(osbuf, TEXT("Business Edition"), maxsiz);
547 break;
548 case PRODUCT_STARTER:
549 bstrncat(osbuf, TEXT("Starter Edition"), maxsiz);
550 break;
551 case PRODUCT_CLUSTER_SERVER:
552 bstrncat(osbuf, TEXT("Cluster Server Edition"), maxsiz);
553 break;
554 case PRODUCT_DATACENTER_SERVER:
555 bstrncat(osbuf, TEXT("Datacenter Edition"), maxsiz);
556 break;
557 case PRODUCT_DATACENTER_SERVER_CORE:
558 bstrncat(osbuf, TEXT("Datacenter Edition (core installation)"), maxsiz);
559 break;
560 case PRODUCT_ENTERPRISE_SERVER:
561 bstrncat(osbuf, TEXT("Enterprise Edition"), maxsiz);
562 break;
563 case PRODUCT_ENTERPRISE_SERVER_CORE:
564 bstrncat(osbuf, TEXT("Enterprise Edition (core installation)"), maxsiz);
565 break;
566 case PRODUCT_ENTERPRISE_SERVER_IA64:
567 bstrncat(osbuf, TEXT("Enterprise Edition for Itanium-based Systems"), maxsiz);
568 break;
569 case PRODUCT_SMALLBUSINESS_SERVER:
570 bstrncat(osbuf, TEXT("Small Business Server"), maxsiz);
571 break;
572 case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
573 bstrncat(osbuf, TEXT("Small Business Server Premium Edition"), maxsiz);
574 break;
575 case PRODUCT_STANDARD_SERVER:
576 bstrncat(osbuf, TEXT("Standard Edition"), maxsiz);
577 break;
578 case PRODUCT_STANDARD_SERVER_CORE:
579 bstrncat(osbuf, TEXT("Standard Edition (core installation)"), maxsiz);
580 break;
581 case PRODUCT_WEB_SERVER:
582 bstrncat(osbuf, TEXT("Web Server Edition"), maxsiz);
583 break;
584 }
585 break;
586 case 5:
587 switch (osvi.dwMinorVersion) {
588 case 2:
589 if (GetSystemMetrics(SM_SERVERR2)) {
590 bstrncat(osbuf, TEXT("Windows Server 2003 R2 "), maxsiz);
591 } else if (osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER) {
592 bstrncat(osbuf, TEXT("Windows Storage Server 2003"), maxsiz);
593 } else if (osvi.wSuiteMask & VER_SUITE_WH_SERVER) {
594 bstrncat(osbuf, TEXT("Windows Home Server"), maxsiz);
595 } else if (osvi.wProductType == VER_NT_WORKSTATION &&
596 si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
597 bstrncat(osbuf, TEXT("Windows XP Professional x64 Edition"), maxsiz);
598 } else {
599 bstrncat(osbuf, TEXT("Windows Server 2003 "), maxsiz);
600 }
601
602 /*
603 * Test for the server type.
604 */
605 if (osvi.wProductType != VER_NT_WORKSTATION) {
606 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
607 if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
608 bstrncat(osbuf, TEXT("Datacenter Edition for Itanium-based Systems"), maxsiz);
609 } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
610 bstrncat(osbuf, TEXT("Enterprise Edition for Itanium-based Systems"), maxsiz);
611 }
612 } else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
613 if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
614 bstrncat(osbuf, TEXT("Datacenter x64 Edition"), maxsiz);
615 } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
616 bstrncat(osbuf, TEXT("Enterprise x64 Edition"), maxsiz);
617 } else {
618 bstrncat(osbuf, TEXT("Standard x64 Edition"), maxsiz);
619 }
620 } else {
621 if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER) {
622 bstrncat(osbuf, TEXT("Compute Cluster Edition"), maxsiz);
623 } else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
624 bstrncat(osbuf, TEXT("Datacenter Edition"), maxsiz);
625 } else if(osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
626 bstrncat(osbuf, TEXT("Enterprise Edition"), maxsiz);
627 } else if (osvi.wSuiteMask & VER_SUITE_BLADE) {
628 bstrncat(osbuf, TEXT("Web Edition"), maxsiz);
629 } else {
630 bstrncat(osbuf, TEXT("Standard Edition"), maxsiz);
631 }
632 }
633 }
634 break;
635 case 1:
636 bstrncat(osbuf, TEXT("Windows XP "), maxsiz);
637 if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
638 bstrncat(osbuf, TEXT("Home Edition"), maxsiz);
639 } else {
640 bstrncat(osbuf, TEXT("Professional"), maxsiz);
641 }
642 break;
643 case 0:
644 bstrncat(osbuf, TEXT("Windows 2000 "), maxsiz);
645 if (osvi.wProductType == VER_NT_WORKSTATION) {
646 bstrncat(osbuf, TEXT("Professional"), maxsiz);
647 } else {
648 if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
649 bstrncat(osbuf, TEXT("Datacenter Server"), maxsiz);
650 } else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
651 bstrncat(osbuf, TEXT("Advanced Server"), maxsiz);
652 } else {
653 bstrncat(osbuf, TEXT("Server"), maxsiz);
654 }
655 }
656 break;
657 }
658 break;
659 default:
660 break;
661 }
662
663 /*
664 * Include service pack (if any) and build number.
665 */
666 if (_tcslen(osvi.szCSDVersion) > 0) {
667 bstrncat(osbuf, TEXT(" ") , maxsiz);
668 bstrncat(osbuf, osvi.szCSDVersion, maxsiz);
669 }
670
671 char buf[80];
672
673 snprintf(buf, 80, " (build %d)", (int)osvi.dwBuildNumber);
674 bstrncat(osbuf, buf, maxsiz);
675
676 if (osvi.dwMajorVersion >= 6) {
677 if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
678 bstrncat(osbuf, TEXT(", 64-bit"), maxsiz);
679 else if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL)
680 bstrncat(osbuf, TEXT(", 32-bit"), maxsiz);
681 }
682
683 return true;
684 } else {
685 bstrncpy(osbuf, "Unknown Windows version.", maxsiz);
686 return true;
687 }
688 }
689