1 /*
2    Bacula(R) - The Network Backup Solution
3 
4    Copyright (C) 2000-2020 Kern Sibbald
5 
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8 
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13 
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16 
17    Bacula(R) is a registered trademark of Kern Sibbald.
18  */
19 
20 /*
21  *
22  *  Kern Sibbald, August 2007
23  *
24  * Note, some of the original Bacula Windows startup and service handling code
25  *  was derived from VNC code that was used in apcupsd then ported to
26  *  Bacula.  However, since then the code has been significantly enhanced
27  *  and largely rewritten.
28  *
29  * Evidently due to the nature of Windows startup code and service
30  *  handling code, certain similarities remain. Thanks to the original
31  *  VNC authors.
32  *
33  * This is a generic main routine, which is used by all three
34  *  of the daemons. Each one compiles it with slightly different
35  *  #defines.
36  *
37  */
38 
39 #define LOCKMGR_COMPLIANT
40 #include "bacula.h"
41 #include "win32.h"
42 #include <signal.h>
43 #include <pthread.h>
44 
45 #include <commctrl.h>
46 
47 
48 /* Globals */
49 HINSTANCE appInstance;
50 DWORD mainthreadId;
51 bool opt_debug = false;
52 bool have_service_api;
53 DWORD service_thread_id = 0;
54 char win_os[300];
55 
56 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz);
57 
58 
59 #define MAX_COMMAND_ARGS 100
60 static char *command_args[MAX_COMMAND_ARGS] = {(char *)LC_APP_NAME, NULL};
61 static int num_command_args = 1;
62 static pid_t main_pid;
63 static pthread_t main_tid;
64 
65 const char usage[] = APP_NAME "[/debug] [/service] [/run] [/kill] [/install] [/remove] [/help]\n";
66 
67 /*
68  *
69  * Main Windows entry point.
70  *
71  * We parse the command line and either calls the main App
72  *   or starts up the service.
73  */
WinMain(HINSTANCE Instance,HINSTANCE,PSTR CmdLine,int)74 int WINAPI WinMain(HINSTANCE Instance, HINSTANCE /*PrevInstance*/, PSTR CmdLine,
75                    int /*show*/)
76 {
77    char *cmdLine = CmdLine;
78    char *wordPtr, *tempPtr;
79    int i, quote;
80    OSVERSIONINFO osversioninfo;
81    osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
82 
83    /* Save the application instance and main thread id */
84    appInstance = Instance;
85    mainthreadId = GetCurrentThreadId();
86 
87    if (GetVersionEx(&osversioninfo) &&
88        osversioninfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
89       have_service_api = true;
90    }
91 
92    GetWindowsVersionString(win_os, sizeof(win_os));
93 
94    main_pid = getpid();
95    main_tid = pthread_self();
96 
97    INITCOMMONCONTROLSEX initCC = {
98       sizeof(INITCOMMONCONTROLSEX),
99       ICC_STANDARD_CLASSES
100    };
101 
102    InitCommonControlsEx(&initCC);
103 
104    /*
105     * Funny things happen with the command line if the
106     * execution comes from c:/Program Files/bacula/bacula.exe
107     * We get a command line like: Files/bacula/bacula.exe" options
108     * I.e. someone stops scanning command line on a space, not
109     * realizing that the filename is quoted!!!!!!!!!!
110     * So if first character is not a double quote and
111     * the last character before first space is a double
112     * quote, we throw away the junk.
113     */
114 
115    wordPtr = cmdLine;
116    while (*wordPtr && *wordPtr != ' ')
117       wordPtr++;
118    if (wordPtr > cmdLine)      /* backup to char before space */
119       wordPtr--;
120    /* if first character is not a quote and last is, junk it */
121    if (*cmdLine != '"' && *wordPtr == '"') {
122       cmdLine = wordPtr + 1;
123    }
124 
125    /*
126     * Build Unix style argc *argv[] for the main "Unix" code
127     *  stripping out any Windows options
128     */
129 
130    /* Don't NULL command_args[0] !!! */
131    for (i=1;i<MAX_COMMAND_ARGS;i++) {
132       command_args[i] = NULL;
133    }
134 
135    char *pszArgs = bstrdup(cmdLine);
136    wordPtr = pszArgs;
137    quote = 0;
138    while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
139       wordPtr++;
140    if (*wordPtr == '\"') {
141       quote = 1;
142       wordPtr++;
143    } else if (*wordPtr == '/') {
144       /* Skip Windows options */
145       while (*wordPtr && (*wordPtr != ' ' && *wordPtr != '\t'))
146          wordPtr++;
147       while  (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
148          wordPtr++;
149    }
150    if (*wordPtr) {
151       while (*wordPtr && num_command_args < MAX_COMMAND_ARGS) {
152          tempPtr = wordPtr;
153          if (quote) {
154             while (*tempPtr && *tempPtr != '\"')
155                tempPtr++;
156             quote = 0;
157          } else {
158             while (*tempPtr && *tempPtr != ' ')
159             tempPtr++;
160          }
161          if (*tempPtr)
162             *(tempPtr++) = '\0';
163          command_args[num_command_args++] = wordPtr;
164          wordPtr = tempPtr;
165          while (*wordPtr && (*wordPtr == ' ' || *wordPtr == '\t'))
166             wordPtr++;
167          if (*wordPtr == '\"') {
168             quote = 1;
169             wordPtr++;
170          }
171       }
172    }
173 
174    /*
175     * Now process Windows command line options. Most of these options
176     *  are single shot -- i.e. we accept one option, do something and
177     *  terminate.
178     */
179    for (i = 0; i < (int)strlen(cmdLine); i++) {
180       char *p = &cmdLine[i];
181 
182       if (*p <= ' ') {
183          continue;                    /* toss junk */
184       }
185 
186       if (*p != '/') {
187          break;                       /* syntax error */
188       }
189 
190       /* Start as a service? */
191       if (strncasecmp(p, "/service", 8) == 0) {
192          return baculaServiceMain();      /* yes, run as a service */
193       }
194 
195       /* Stop any running copy? */
196       if (strncasecmp(p, "/kill", 5) == 0) {
197          return stopRunningBacula();
198       }
199 
200       /* Run app as user program? */
201       if (strncasecmp(p, "/run", 4) == 0) {
202          return BaculaAppMain();         /* yes, run as a user program */
203       }
204 
205       /* Install Bacula in registry? */
206       if (strncasecmp(p, "/install", 8) == 0) {
207          return installService(p+8);    /* Pass command options */
208       }
209 
210       /* Remove Bacula registry entry? */
211       if (strncasecmp(p, "/remove", 7) == 0) {
212          return removeService();
213       }
214 
215       /* Set debug mode? -- causes more dialogs to be displayed */
216       if (strncasecmp(p, "/debug", 6) == 0) {
217          opt_debug = true;
218          i += 6;                /* skip /debug */
219          continue;
220       }
221 
222       /* Display help? -- displays usage */
223       if (strncasecmp(p, "/help", 5) == 0) {
224          MessageBox(NULL, usage, APP_DESC, MB_OK|MB_ICONINFORMATION);
225          return 0;
226       }
227 
228       MessageBox(NULL, cmdLine, _("Bad Command Line Option"), MB_OK);
229 
230       /* Show the usage dialog */
231       MessageBox(NULL, usage, APP_DESC, MB_OK | MB_ICONINFORMATION);
232 
233       return 1;
234    }
235    return BaculaAppMain();
236 }
237 
238 #ifndef HAVE_TRAY_MONITOR
239 /* Minimalist winproc when don't have tray monitor */
bacWinProc(HWND hwnd,UINT iMsg,WPARAM wParam,LPARAM lParam)240 LRESULT CALLBACK bacWinProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
241 {
242    switch (iMsg) {
243    case WM_DESTROY:
244       PostQuitMessage(0);
245       return 0;
246    }
247    return DefWindowProc(hwnd, iMsg, wParam, lParam);
248 }
249 #endif
250 
251 
252 /*
253  * Called as a thread from BaculaAppMain()
254  * Here we handle the Windows messages
255  */
Main_Msg_Loop(LPVOID lpwThreadParam)256 void *Main_Msg_Loop(LPVOID lpwThreadParam)
257 {
258    MSG msg;
259 
260    pthread_detach(pthread_self());
261 
262    /*
263     * Since we are the only thread with a message loop
264     * mark ourselves as the service thread so that
265     * we can receive all the window events.
266     */
267    service_thread_id = GetCurrentThreadId();
268 
269 #ifdef HAVE_TRAY_MONITOR
270    /* Create tray icon & menu if we're running as an app */
271    trayMonitor *monitor = new trayMonitor();
272    if (monitor == NULL) {
273       PostQuitMessage(0);
274    }
275 
276 #else
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 #endif
301 
302    /* Now enter the Windows message handling loop until told to quit! */
303    while (GetMessage(&msg, NULL, 0,0) ) {
304       TranslateMessage(&msg);
305       DispatchMessage(&msg);
306    }
307 
308    /* If we get here, we are shutting down */
309 
310 #ifdef HAVE_TRAY_MONITOR
311    if (monitor != NULL) {
312       delete monitor;
313    }
314 #endif
315 
316    if (have_service_api) {
317       /* Mark that we're no longer running */
318       service_thread_id = 0;
319       /* Tell the service manager that we've stopped. */
320       ReportStatus(SERVICE_STOPPED, service_error, 0);
321    }
322    /* Tell main "Unix" program to go away */
323    terminate_app(0);
324 
325    /* Should not get here */
326    pthread_kill(main_tid, SIGTERM);   /* ask main thread to terminate */
327    sleep(1);
328    kill(main_pid, SIGTERM);           /* kill main thread */
329    _exit(0);
330 }
331 
332 /*
333  * This is the main routine for Bacula when running as an application,
334  *  or after the service has started up.
335  */
BaculaAppMain()336 int BaculaAppMain()
337 {
338    pthread_t tid;
339    DWORD dwCharsWritten;
340 
341    OSDependentInit();
342    /* If no arguments were given then just run */
343    if (p_AttachConsole == NULL || !p_AttachConsole(ATTACH_PARENT_PROCESS)) {
344       if (opt_debug) {
345          AllocConsole();
346       }
347    }
348 
349    WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "\r\n", 2, &dwCharsWritten, NULL);
350 
351    /* Startup networking */
352    WSA_Init();
353 
354    /* Set this process to be the last application to be shut down. */
355    if (p_SetProcessShutdownParameters) {
356       p_SetProcessShutdownParameters(0x100, 0);
357    }
358 
359    /* Create a thread to handle the Windows messages */
360    pthread_create(&tid, NULL,  Main_Msg_Loop, (void *)0);
361 
362    /* Call the Unix Bacula daemon */
363    BaculaMain(num_command_args, command_args);
364    PostQuitMessage(0);                /* terminate our main message loop */
365 
366    WSACleanup();
367    _exit(0);
368 }
369 
370 
pause_msg(const char * file,const char * func,int line,const char * msg)371 void pause_msg(const char *file, const char *func, int line, const char *msg)
372 {
373    char buf[1000];
374    if (msg) {
375       bsnprintf(buf, sizeof(buf), "%s:%s:%d %s", file, func, line, msg);
376    } else {
377       bsnprintf(buf, sizeof(buf), "%s:%s:%d", file, func, line);
378    }
379    MessageBox(NULL, buf, "Pause", MB_OK);
380 }
381 
382 #include <tchar.h>
383 #include <stdio.h>
384 
385 #ifndef PRODUCT_UNLICENSED
386 #define PRODUCT_UNLICENSED 0xABCDABCD
387 #define PRODUCT_BUSINESS 0x00000006
388 #define PRODUCT_BUSINESS_N 0x00000010
389 #define PRODUCT_CLUSTER_SERVER 0x00000012
390 #define PRODUCT_DATACENTER_SERVER 0x00000008
391 #define PRODUCT_DATACENTER_SERVER_CORE 0x0000000C
392 #define PRODUCT_DATACENTER_SERVER_CORE_V 0x00000027
393 #define PRODUCT_DATACENTER_SERVER_V 0x00000025
394 #define PRODUCT_ENTERPRISE 0x00000004
395 #define PRODUCT_ENTERPRISE_E 0x00000046
396 #define PRODUCT_ENTERPRISE_N 0x0000001B
397 #define PRODUCT_ENTERPRISE_SERVER 0x0000000A
398 #define PRODUCT_ENTERPRISE_SERVER_CORE 0x0000000E
399 #define PRODUCT_ENTERPRISE_SERVER_CORE_V 0x00000029
400 #define PRODUCT_ENTERPRISE_SERVER_IA64 0x0000000F
401 #define PRODUCT_ENTERPRISE_SERVER_V 0x00000026
402 #define PRODUCT_HOME_BASIC 0x00000002
403 #define PRODUCT_HOME_BASIC_E 0x00000043
404 #define PRODUCT_HOME_BASIC_N 0x00000005
405 #define PRODUCT_HOME_PREMIUM 0x00000003
406 #define PRODUCT_HOME_PREMIUM_E 0x00000044
407 #define PRODUCT_HOME_PREMIUM_N 0x0000001A
408 #define PRODUCT_HYPERV 0x0000002A
409 #define PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT 0x0000001E
410 #define PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING 0x00000020
411 #define PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY 0x0000001F
412 #define PRODUCT_PROFESSIONAL 0x00000030
413 #define PRODUCT_PROFESSIONAL_E 0x00000045
414 #define PRODUCT_PROFESSIONAL_N 0x00000031
415 #define PRODUCT_SERVER_FOR_SMALLBUSINESS 0x00000018
416 #define PRODUCT_SERVER_FOR_SMALLBUSINESS_V 0x00000023
417 #define PRODUCT_SERVER_FOUNDATION 0x00000021
418 #define PRODUCT_SMALLBUSINESS_SERVER 0x00000009
419 #define PRODUCT_SOLUTION_EMBEDDEDSERVER 0x00000038
420 #define PRODUCT_STANDARD_SERVER 0x00000007
421 #define PRODUCT_STANDARD_SERVER_CORE 0x0000000D
422 #define PRODUCT_STANDARD_SERVER_CORE_V 0x00000028
423 #define PRODUCT_STANDARD_SERVER_V 0x00000024
424 #define PRODUCT_STARTER 0x0000000B
425 #define PRODUCT_STARTER_E 0x00000042
426 #define PRODUCT_STARTER_N 0x0000002F
427 #define PRODUCT_STORAGE_ENTERPRISE_SERVER 0x00000017
428 #define PRODUCT_STORAGE_EXPRESS_SERVER 0x00000014
429 #define PRODUCT_STORAGE_STANDARD_SERVER 0x00000015
430 #define PRODUCT_STORAGE_WORKGROUP_SERVER  0x00000016
431 #define PRODUCT_UNDEFINED 0x00000000
432 #define PRODUCT_ULTIMATE 0x00000001
433 #define PRODUCT_ULTIMATE_E 0x00000047
434 #define PRODUCT_ULTIMATE_N 0x0000001C
435 #define PRODUCT_WEB_SERVER 0x00000011
436 #define PRODUCT_WEB_SERVER_CORE 0x0000001D
437 
438 #define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM 0x19
439 #define SM_SERVERR2 89
440 #define VER_SERVER_NT 0x80000000
441 
442 #define PRODUCT_CLUSTER_SERVER_V 0x00000040
443 #define PRODUCT_ENTERPRISE_EVALUATION 0x00000048
444 #define PRODUCT_ENTERPRISE_N_EVALUATION 0x00000054
445 #define PRODUCT_HOME_PREMIUM_SERVER 0x00000022
446 #define PRODUCT_HOME_SERVER 0x00000013
447 #define PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE 0x0000002E
448 #define PRODUCT_STORAGE_EXPRESS_SERVER_CORE 0x0000002B
449 #define PRODUCT_STORAGE_STANDARD_SERVER_CORE 0x0000002C
450 #define PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER 0x00000060
451 #define PRODUCT_STORAGE_WORKGROUP_SERVER_CORE 0x0000002D
452 #define PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER 0x0000005F
453 #define PRODUCT_CORE 0x00000065
454 #define PRODUCT_CORE_COUNTRYSPECIFIC 0x00000063
455 #define PRODUCT_CORE_N 0x00000062
456 #define PRODUCT_CORE_SINGLELANGUAGE 0x00000064
457 #define PRODUCT_DATACENTER_EVALUATION_SERVER 0x00000050
458 #define PRODUCT_DATACENTER_A_SERVER_CORE 0x00000091
459 #define PRODUCT_STANDARD_A_SERVER_CORE 0x00000092
460 #define PRODUCT_EDUCATION 0x00000079
461 #define PRODUCT_EDUCATION_N 0x0000007A
462 #define PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL 0x0000003C
463 #define PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC 0x0000003E
464 #define PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT 0x0000003B
465 #define PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC 0x0000003D
466 #define PRODUCT_MOBILE_CORE 0x00000068
467 #define PRODUCT_MOBILE_ENTERPRISE 0x00000085
468 #define PRODUCT_MULTIPOINT_PREMIUM_SERVER 0x0000004D
469 #define PRODUCT_MULTIPOINT_STANDARD_SERVER 0x0000004C
470 #define PRODUCT_PRO_WORKSTATION 0x000000A1
471 #define PRODUCT_PRO_WORKSTATION_N 0x000000A2
472 #define PRODUCT_PROFESSIONAL_WMC 0x00000067
473 #define PRODUCT_SB_SOLUTION_SERVER 0x00000032
474 #define PRODUCT_SB_SOLUTION_SERVER_EM 0x00000036
475 #define PRODUCT_SERVER_FOR_SB_SOLUTIONS 0x00000033
476 #define PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM 0x00000037
477 #define PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE 0x0000003F
478 #define PRODUCT_STANDARD_EVALUATION_SERVER 0x0000004F
479 #define PRODUCT_STANDARD_SERVER_SOLUTIONS 0x00000034
480 #define PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE 0x00000035
481 #endif
482 
483 /* Windows 10 */
484 #ifndef PRODUCT_ENTERPRISE_S
485 #define PRODUCT_ENTERPRISE_S 0x0000007D
486 #define PRODUCT_ENTERPRISE_S_EVALUATION 0x00000081
487 #define PRODUCT_ENTERPRISE_S_N 0x0000007E
488 #define PRODUCT_ENTERPRISE_S_N_EVALUATION 0x00000082
489 #endif
490 #define PRODUCT_IOTUAP 0x0000007B
491 #define PRODUCT_IOTUAPCOMMERCIAL 0x00000083
492 
493 #define PRODUCT_DATACENTER_A_SERVER_CORE 0x00000091
494 #define PRODUCT_PRO_WORKSTATION 0x000000A1
495 #define PRODUCT_PRO_WORKSTATION_N 0x000000A2
496 #define PRODUCT_STANDARD_A_SERVER_CORE 0x00000092
497 
498 
499 
500 
501 #ifndef PRODUCT_PROFESSIONAL
502 #define PRODUCT_PROFESSIONAL 0x00000030
503 #endif
504 #ifndef VER_SUITE_STORAGE_SERVER
505 #define VER_SUITE_STORAGE_SERVER 0x00002000
506 #endif
507 #ifndef VER_SUITE_COMPUTE_SERVER
508 #define VER_SUITE_COMPUTE_SERVER 0x00004000
509 #endif
510 
511 /* Unknown value */
512 #ifndef VER_SUITE_WH_SERVER
513 #define VER_SUITE_WH_SERVER -1
514 #endif
515 
516 typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO);
517 typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
518 
519 /*
520  * Get Windows version display string
521  */
GetWindowsVersionString(LPTSTR osbuf,int maxsiz)522 bool GetWindowsVersionString(LPTSTR osbuf, int maxsiz)
523 {
524    OSVERSIONINFOEX osvi;
525    SYSTEM_INFO si;
526    PGNSI pGNSI;
527    PGPI pGPI;
528    BOOL bOsVersionInfoEx;
529    DWORD dwType;
530 
531    memset(&si, 0, sizeof(SYSTEM_INFO));
532    memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
533 
534    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
535 
536    if( !(bOsVersionInfoEx = GetVersionEx ((OSVERSIONINFO *) &osvi)) )
537       return 1;
538 
539    // Call GetNativeSystemInfo if supported or GetSystemInfo otherwise.
540 
541    pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
542            "GetNativeSystemInfo");
543    if (pGNSI) {
544       pGNSI(&si);
545    } else {
546       GetSystemInfo(&si);
547    }
548 
549    if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && osvi.dwMajorVersion > 4) {
550       bstrncpy(osbuf, TEXT("Microsoft "), maxsiz);
551 
552       // Test for the specific product.
553 
554       if (osvi.dwMajorVersion == 10) {
555          if (osvi.dwMinorVersion == 0) {
556             if (osvi.wProductType == VER_NT_WORKSTATION)
557                 bstrncat(osbuf, TEXT("Windows 10 "), maxsiz);
558             else
559                 bstrncat(osbuf, TEXT("Windows Server 2016 " ), maxsiz);
560          }
561 
562          pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
563             "GetProductInfo");
564 
565          if (pGPI) {
566             pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
567          } else {
568             dwType = PRODUCT_HOME_BASIC;
569          }
570 
571          switch (dwType) {
572             case PRODUCT_ULTIMATE:
573                bstrncat(osbuf, TEXT("Ultimate Edition" ), maxsiz);
574                break;
575             case PRODUCT_PROFESSIONAL:
576                bstrncat(osbuf, TEXT("Professional" ), maxsiz);
577                break;
578             case PRODUCT_HOME_PREMIUM:
579                bstrncat(osbuf, TEXT("Home Premium Edition" ), maxsiz);
580                break;
581             case PRODUCT_HOME_BASIC:
582                bstrncat(osbuf, TEXT("Home Basic Edition" ), maxsiz);
583                break;
584             case PRODUCT_ENTERPRISE:
585                bstrncat(osbuf, TEXT("Enterprise Edition" ), maxsiz);
586                break;
587             case PRODUCT_BUSINESS:
588                bstrncat(osbuf, TEXT("Business Edition" ), maxsiz);
589                break;
590             case PRODUCT_BUSINESS_N:
591                bstrncat(osbuf, TEXT("Business Edition N" ), maxsiz);
592                break;
593             case PRODUCT_CORE:
594                bstrncat(osbuf, TEXT("Home Edition" ), maxsiz);
595                break;
596             case PRODUCT_CORE_COUNTRYSPECIFIC:
597                bstrncat(osbuf, TEXT("Home China Edition" ), maxsiz);
598                break;
599             case PRODUCT_CORE_N:
600                bstrncat(osbuf, TEXT("Home N Edition" ), maxsiz);
601                break;
602             case PRODUCT_CORE_SINGLELANGUAGE:
603                bstrncat(osbuf, TEXT("Home Single Language Edition" ), maxsiz);
604                break;
605             case PRODUCT_DATACENTER_EVALUATION_SERVER:
606                bstrncat(osbuf, TEXT("Server Datacenter (evaluation installation)" ), maxsiz);
607                break;
608             case PRODUCT_DATACENTER_A_SERVER_CORE:
609                bstrncat(osbuf, TEXT("Server Datacenter, Semi-Annual Channel (core installation)" ), maxsiz);
610                break;
611             case PRODUCT_STANDARD_A_SERVER_CORE:
612                bstrncat(osbuf, TEXT("Server Standard, Semi-Annual Channel (core installation)" ), maxsiz);
613                break;
614             case PRODUCT_DATACENTER_SERVER_CORE_V:
615                bstrncat(osbuf, TEXT("Server Datacenter without Hyper-V (core installation)" ), maxsiz);
616                break;
617             case PRODUCT_DATACENTER_SERVER_V:
618                bstrncat(osbuf, TEXT("Server Datacenter without Hyper-V (full installation)" ), maxsiz);
619                break;
620             case PRODUCT_EDUCATION:
621                bstrncat(osbuf, TEXT("Education" ), maxsiz);
622                break;
623             case PRODUCT_EDUCATION_N:
624                bstrncat(osbuf, TEXT("Education N" ), maxsiz);
625                break;
626             case PRODUCT_ENTERPRISE_E:
627                bstrncat(osbuf, TEXT("Enterprise E" ), maxsiz);
628                break;
629             case PRODUCT_ENTERPRISE_EVALUATION:
630                bstrncat(osbuf, TEXT("Enterprise Evaluation" ), maxsiz);
631                break;
632             case PRODUCT_ENTERPRISE_N:
633                bstrncat(osbuf, TEXT("Enterprise N" ), maxsiz);
634                break;
635             case PRODUCT_ENTERPRISE_N_EVALUATION:
636                bstrncat(osbuf, TEXT("Enterprise N Evaluation" ), maxsiz);
637                break;
638             case PRODUCT_ENTERPRISE_S:
639                bstrncat(osbuf, TEXT("Enterprise 2015 LTSB" ), maxsiz);
640                break;
641             case PRODUCT_ENTERPRISE_S_EVALUATION:
642                bstrncat(osbuf, TEXT("Enterprise 2015 LTSB Evaluation" ), maxsiz);
643                break;
644             case PRODUCT_ENTERPRISE_S_N:
645                bstrncat(osbuf, TEXT("Enterprise 2015 LTSB N" ), maxsiz);
646                break;
647             case PRODUCT_ENTERPRISE_S_N_EVALUATION:
648                bstrncat(osbuf, TEXT("Enterprise 2015 LTSB N Evaluation" ), maxsiz);
649                break;
650             case PRODUCT_ENTERPRISE_SERVER:
651                bstrncat(osbuf, TEXT("Enterprise (full installation)" ), maxsiz);
652                break;
653             case PRODUCT_ENTERPRISE_SERVER_CORE_V:
654                bstrncat(osbuf, TEXT("Server Enterprise without Hyper-V (core installation)" ), maxsiz);
655                break;
656             case PRODUCT_ENTERPRISE_SERVER_IA64:
657                bstrncat(osbuf, TEXT("Server Enterprise for Itanium-based Systems" ), maxsiz);
658                break;
659             case PRODUCT_ENTERPRISE_SERVER_V:
660                bstrncat(osbuf, TEXT("Server Enterprise without Hyper-V (full installation)" ), maxsiz);
661                break;
662             case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDL:
663                bstrncat(osbuf, TEXT("Essential Server Solution Additional" ), maxsiz);
664                break;
665             case PRODUCT_ESSENTIALBUSINESS_SERVER_ADDLSVC:
666                bstrncat(osbuf, TEXT("Essential Server Solution Additional SVC" ), maxsiz);
667                break;
668             case PRODUCT_ESSENTIALBUSINESS_SERVER_MGMT:
669                bstrncat(osbuf, TEXT("Essential Server Solution Management" ), maxsiz);
670                break;
671             case PRODUCT_ESSENTIALBUSINESS_SERVER_MGMTSVC:
672                bstrncat(osbuf, TEXT("Essential Server Solution Management SVC" ), maxsiz);
673                break;
674             case PRODUCT_HOME_BASIC_E:
675                bstrncat(osbuf, TEXT("Not supported" ), maxsiz);
676                break;
677             case PRODUCT_HOME_BASIC_N:
678                bstrncat(osbuf, TEXT("Home Basic N" ), maxsiz);
679                break;
680             case PRODUCT_HOME_PREMIUM_E:
681                bstrncat(osbuf, TEXT("Not supported" ), maxsiz);
682                break;
683             case PRODUCT_HOME_PREMIUM_N:
684                bstrncat(osbuf, TEXT("Home Premium N" ), maxsiz);
685                break;
686             case PRODUCT_HOME_PREMIUM_SERVER:
687                bstrncat(osbuf, TEXT("Home Server 2011" ), maxsiz);
688                break;
689             case PRODUCT_HOME_SERVER:
690                bstrncat(osbuf, TEXT("Storage Server 2008 R2 Essentials" ), maxsiz);
691                break;
692             case PRODUCT_HYPERV:
693                bstrncat(osbuf, TEXT("Hyper-V Server" ), maxsiz);
694                break;
695             case PRODUCT_IOTUAP:
696                bstrncat(osbuf, TEXT("IoT Core" ), maxsiz);
697                break;
698             case PRODUCT_IOTUAPCOMMERCIAL:
699                bstrncat(osbuf, TEXT("IoT Core Commercial" ), maxsiz);
700                break;
701             case PRODUCT_MEDIUMBUSINESS_SERVER_MANAGEMENT:
702                bstrncat(osbuf, TEXT("Essential Business Server Management Server" ), maxsiz);
703                break;
704             case PRODUCT_MEDIUMBUSINESS_SERVER_MESSAGING:
705                bstrncat(osbuf, TEXT("Essential Business Server Messaging Server" ), maxsiz);
706                break;
707             case PRODUCT_MEDIUMBUSINESS_SERVER_SECURITY:
708                bstrncat(osbuf, TEXT("Essential Business Server Security Server" ), maxsiz);
709                break;
710             case PRODUCT_MOBILE_CORE:
711                bstrncat(osbuf, TEXT("Mobile" ), maxsiz);
712                break;
713             case PRODUCT_MOBILE_ENTERPRISE:
714                bstrncat(osbuf, TEXT("Mobile Enterprise" ), maxsiz);
715                break;
716             case PRODUCT_MULTIPOINT_PREMIUM_SERVER:
717                bstrncat(osbuf, TEXT("MultiPoint Server Premium (full installation)" ), maxsiz);
718                break;
719             case PRODUCT_MULTIPOINT_STANDARD_SERVER:
720                bstrncat(osbuf, TEXT("MultiPoint Server Standard (full installation)" ), maxsiz);
721                break;
722             case PRODUCT_PRO_WORKSTATION:
723                bstrncat(osbuf, TEXT("Pro for Workstations" ), maxsiz);
724                break;
725             case PRODUCT_PRO_WORKSTATION_N:
726                bstrncat(osbuf, TEXT("Pro for Workstations N" ), maxsiz);
727                break;
728             case PRODUCT_PROFESSIONAL_E:
729                bstrncat(osbuf, TEXT("Not supported" ), maxsiz);
730                break;
731             case PRODUCT_PROFESSIONAL_N:
732                bstrncat(osbuf, TEXT("Pro N" ), maxsiz);
733                break;
734             case PRODUCT_PROFESSIONAL_WMC:
735                bstrncat(osbuf, TEXT("Professional with Media Center" ), maxsiz);
736                break;
737             case PRODUCT_SB_SOLUTION_SERVER:
738                bstrncat(osbuf, TEXT("Small Business Server 2011 Essentials" ), maxsiz);
739                break;
740             case PRODUCT_SB_SOLUTION_SERVER_EM:
741                bstrncat(osbuf, TEXT("Server For SB Solutions EM" ), maxsiz);
742                break;
743             case PRODUCT_SERVER_FOR_SB_SOLUTIONS:
744                bstrncat(osbuf, TEXT("Server For SB Solutions" ), maxsiz);
745                break;
746             case PRODUCT_SERVER_FOR_SB_SOLUTIONS_EM:
747                bstrncat(osbuf, TEXT("Server For SB Solutions EM" ), maxsiz);
748                break;
749             case PRODUCT_SERVER_FOR_SMALLBUSINESS:
750                bstrncat(osbuf, TEXT("for Windows Essential Server Solutions" ), maxsiz);
751                break;
752             case PRODUCT_SERVER_FOR_SMALLBUSINESS_V:
753                bstrncat(osbuf, TEXT("without Hyper-V for Windows Essential Server Solutions" ), maxsiz);
754                break;
755             case PRODUCT_SERVER_FOUNDATION:
756                bstrncat(osbuf, TEXT("Server Foundation" ), maxsiz);
757                break;
758             case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM_CORE:
759                bstrncat(osbuf, TEXT("Small Business Server Premium (core installation)" ), maxsiz);
760                break;
761             case PRODUCT_SOLUTION_EMBEDDEDSERVER:
762                bstrncat(osbuf, TEXT("Windows MultiPoint Server" ), maxsiz);
763                break;
764             case PRODUCT_STANDARD_EVALUATION_SERVER:
765                bstrncat(osbuf, TEXT("Server Standard (evaluation installation)" ), maxsiz);
766                break;
767             case PRODUCT_STANDARD_SERVER_CORE_V:
768                bstrncat(osbuf, TEXT("Server Standard without Hyper-V" ), maxsiz);
769                break;
770             case PRODUCT_STANDARD_SERVER_SOLUTIONS:
771                bstrncat(osbuf, TEXT("Server Solutions Premium" ), maxsiz);
772                break;
773             case PRODUCT_STANDARD_SERVER_SOLUTIONS_CORE:
774                bstrncat(osbuf, TEXT("Server Solutions Premium (core installation)" ), maxsiz);
775                break;
776             case PRODUCT_STARTER_E:
777                bstrncat(osbuf, TEXT("Not supported" ), maxsiz);
778                break;
779             case PRODUCT_STARTER_N:
780                bstrncat(osbuf, TEXT("Starter N" ), maxsiz);
781                break;
782             case PRODUCT_STORAGE_ENTERPRISE_SERVER:
783                bstrncat(osbuf, TEXT("Storage Server Enterprise" ), maxsiz);
784                break;
785             case PRODUCT_STORAGE_ENTERPRISE_SERVER_CORE:
786                bstrncat(osbuf, TEXT("Storage Server Enterprise (core installation)" ), maxsiz);
787                break;
788             case PRODUCT_STORAGE_EXPRESS_SERVER:
789                bstrncat(osbuf, TEXT("Storage Server Express" ), maxsiz);
790                break;
791             case PRODUCT_STORAGE_EXPRESS_SERVER_CORE:
792                bstrncat(osbuf, TEXT("Storage Server Express (core installation)" ), maxsiz);
793                break;
794             case PRODUCT_STORAGE_STANDARD_EVALUATION_SERVER:
795                bstrncat(osbuf, TEXT("Storage Server Standard (evaluation installation)" ), maxsiz);
796                break;
797             case PRODUCT_STORAGE_STANDARD_SERVER:
798                bstrncat(osbuf, TEXT("Storage Server Standard" ), maxsiz);
799                break;
800             case PRODUCT_STORAGE_STANDARD_SERVER_CORE:
801                bstrncat(osbuf, TEXT("Storage Server Standard (core installation)" ), maxsiz);
802                break;
803             case PRODUCT_STORAGE_WORKGROUP_EVALUATION_SERVER:
804                bstrncat(osbuf, TEXT("Storage Server Workgroup (evaluation installation)" ), maxsiz);
805                break;
806             case PRODUCT_STORAGE_WORKGROUP_SERVER:
807                bstrncat(osbuf, TEXT("Storage Server Workgroup" ), maxsiz);
808                break;
809             case PRODUCT_STORAGE_WORKGROUP_SERVER_CORE:
810                bstrncat(osbuf, TEXT("Storage Server Workgroup (core installation)" ), maxsiz);
811                break;
812             case PRODUCT_ULTIMATE_E:
813                bstrncat(osbuf, TEXT("Not supported" ), maxsiz);
814                break;
815             case PRODUCT_ULTIMATE_N:
816                bstrncat(osbuf, TEXT("Ultimate N" ), maxsiz);
817                break;
818             case PRODUCT_UNDEFINED:
819                bstrncat(osbuf, TEXT("Unknown product" ), maxsiz);
820                break;
821             case PRODUCT_WEB_SERVER_CORE:
822                bstrncat(osbuf, TEXT("Web Server (core installation)" ), maxsiz);
823                break;
824             case PRODUCT_STARTER:
825                bstrncat(osbuf, TEXT("Starter Edition" ), maxsiz);
826                break;
827             case PRODUCT_CLUSTER_SERVER_V:
828                bstrncat(osbuf, TEXT("Server Hyper Core V" ), maxsiz);
829                break;
830             case PRODUCT_CLUSTER_SERVER:
831                bstrncat(osbuf, TEXT("Cluster Server Edition" ), maxsiz);
832                break;
833             case PRODUCT_DATACENTER_SERVER:
834                bstrncat(osbuf, TEXT("Datacenter Edition" ), maxsiz);
835                break;
836             case PRODUCT_DATACENTER_SERVER_CORE:
837                bstrncat(osbuf, TEXT("Datacenter Edition (core installation)" ), maxsiz);
838                break;
839             case PRODUCT_ENTERPRISE_SERVER_CORE:
840                bstrncat(osbuf, TEXT("Enterprise Edition (core installation)" ), maxsiz);
841                break;
842             case PRODUCT_SMALLBUSINESS_SERVER:
843                bstrncat(osbuf, TEXT("Small Business Server" ), maxsiz);
844                break;
845             case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
846                bstrncat(osbuf, TEXT("Small Business Server Premium Edition" ), maxsiz);
847                break;
848             case PRODUCT_STANDARD_SERVER:
849                bstrncat(osbuf, TEXT("Standard Edition" ), maxsiz);
850                break;
851             case PRODUCT_STANDARD_SERVER_CORE:
852                bstrncat(osbuf, TEXT("Standard Edition (core installation)" ), maxsiz);
853                break;
854             case PRODUCT_WEB_SERVER:
855                bstrncat(osbuf, TEXT("Web Server Edition" ), maxsiz);
856                break;
857          }
858       }
859       if (osvi.dwMajorVersion == 6) {
860          if (osvi.dwMinorVersion == 0) {
861             if (osvi.wProductType == VER_NT_WORKSTATION)
862                 bstrncat(osbuf, TEXT("Windows Vista "), maxsiz);
863             else
864                 bstrncat(osbuf, TEXT("Windows Server 2008 " ), maxsiz);
865          }
866 
867          if (osvi.dwMinorVersion == 1) {
868             if (osvi.wProductType == VER_NT_WORKSTATION )
869                 bstrncat(osbuf, TEXT("Windows 7 "), maxsiz);
870             else
871                 bstrncat(osbuf, TEXT("Windows Server 2008 R2 " ), maxsiz);
872          }
873          if (osvi.dwMinorVersion == 2) {
874             if (osvi.wProductType == VER_NT_WORKSTATION )
875                 bstrncat(osbuf, TEXT("Windows 8 "), maxsiz);
876             else
877                 bstrncat(osbuf, TEXT("Windows Server 2012 " ), maxsiz);
878          }
879          if (osvi.dwMinorVersion == 3) {
880             if (osvi.wProductType == VER_NT_WORKSTATION )
881                 bstrncat(osbuf, TEXT("Windows 8.1 "), maxsiz);
882             else
883                 bstrncat(osbuf, TEXT("Windows Server 2012 RC2 " ), maxsiz);
884          }
885 
886          pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
887             "GetProductInfo");
888 
889          if (pGPI) {
890             pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
891          } else {
892             dwType = PRODUCT_HOME_BASIC;
893          }
894 
895          switch (dwType) {
896             case PRODUCT_ULTIMATE:
897                bstrncat(osbuf, TEXT("Ultimate Edition" ), maxsiz);
898                break;
899             case PRODUCT_PROFESSIONAL:
900                bstrncat(osbuf, TEXT("Professional" ), maxsiz);
901                break;
902             case PRODUCT_HOME_PREMIUM:
903                bstrncat(osbuf, TEXT("Home Premium Edition" ), maxsiz);
904                break;
905             case PRODUCT_HOME_BASIC:
906                bstrncat(osbuf, TEXT("Home Basic Edition" ), maxsiz);
907                break;
908             case PRODUCT_ENTERPRISE:
909                bstrncat(osbuf, TEXT("Enterprise Edition" ), maxsiz);
910                break;
911             case PRODUCT_BUSINESS:
912                bstrncat(osbuf, TEXT("Business Edition" ), maxsiz);
913                break;
914             case PRODUCT_STARTER:
915                bstrncat(osbuf, TEXT("Starter Edition" ), maxsiz);
916                break;
917             case PRODUCT_CLUSTER_SERVER:
918                bstrncat(osbuf, TEXT("Cluster Server Edition" ), maxsiz);
919                break;
920             case PRODUCT_DATACENTER_SERVER:
921                bstrncat(osbuf, TEXT("Datacenter Edition" ), maxsiz);
922                break;
923             case PRODUCT_DATACENTER_SERVER_CORE:
924                bstrncat(osbuf, TEXT("Datacenter Edition (core installation)" ), maxsiz);
925                break;
926             case PRODUCT_ENTERPRISE_SERVER:
927                bstrncat(osbuf, TEXT("Enterprise Edition" ), maxsiz);
928                break;
929             case PRODUCT_ENTERPRISE_SERVER_CORE:
930                bstrncat(osbuf, TEXT("Enterprise Edition (core installation)" ), maxsiz);
931                break;
932             case PRODUCT_ENTERPRISE_SERVER_IA64:
933                bstrncat(osbuf, TEXT("Enterprise Edition for Itanium-based Systems" ), maxsiz);
934                break;
935             case PRODUCT_SMALLBUSINESS_SERVER:
936                bstrncat(osbuf, TEXT("Small Business Server" ), maxsiz);
937                break;
938             case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
939                bstrncat(osbuf, TEXT("Small Business Server Premium Edition" ), maxsiz);
940                break;
941             case PRODUCT_STANDARD_SERVER:
942                bstrncat(osbuf, TEXT("Standard Edition" ), maxsiz);
943                break;
944             case PRODUCT_STANDARD_SERVER_CORE:
945                bstrncat(osbuf, TEXT("Standard Edition (core installation)" ), maxsiz);
946                break;
947             case PRODUCT_WEB_SERVER:
948                bstrncat(osbuf, TEXT("Web Server Edition" ), maxsiz);
949                break;
950          }
951       }
952 
953       if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
954          if( GetSystemMetrics(SM_SERVERR2) )
955             bstrncat(osbuf, TEXT( "Windows Server 2003 R2 "), maxsiz);
956          else if (osvi.wSuiteMask & VER_SUITE_STORAGE_SERVER)
957             bstrncat(osbuf, TEXT( "Windows Storage Server 2003"), maxsiz);
958          else if (osvi.wSuiteMask & VER_SUITE_WH_SERVER )
959             bstrncat(osbuf, TEXT( "Windows Home Server"), maxsiz);
960          else if (osvi.wProductType == VER_NT_WORKSTATION &&
961                   si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64)
962             bstrncat(osbuf, TEXT( "Windows XP Professional x64 Edition"), maxsiz);
963          else
964             bstrncat(osbuf, TEXT("Windows Server 2003 "), maxsiz);
965 
966          // Test for the server type.
967          if (osvi.wProductType != VER_NT_WORKSTATION) {
968             if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64) {
969                 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
970                    bstrncat(osbuf, TEXT( "Datacenter Edition for Itanium-based Systems" ), maxsiz);
971                 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
972                    bstrncat(osbuf, TEXT( "Enterprise Edition for Itanium-based Systems" ), maxsiz);
973             }
974 
975             else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64) {
976                 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
977                    bstrncat(osbuf, TEXT( "Datacenter x64 Edition" ), maxsiz);
978                 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
979                    bstrncat(osbuf, TEXT( "Enterprise x64 Edition" ), maxsiz);
980                 else bstrncat(osbuf, TEXT( "Standard x64 Edition" ), maxsiz);
981             } else {
982                 if ( osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER )
983                    bstrncat(osbuf, TEXT( "Compute Cluster Edition" ), maxsiz);
984                 else if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
985                    bstrncat(osbuf, TEXT( "Datacenter Edition" ), maxsiz);
986                 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
987                    bstrncat(osbuf, TEXT( "Enterprise Edition" ), maxsiz);
988                 else if ( osvi.wSuiteMask & VER_SUITE_BLADE )
989                    bstrncat(osbuf, TEXT( "Web Edition" ), maxsiz);
990                 else bstrncat(osbuf, TEXT( "Standard Edition" ), maxsiz);
991             }
992          }
993       }
994 
995       if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
996          bstrncat(osbuf, TEXT("Windows XP "), maxsiz);
997          if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
998             bstrncat(osbuf, TEXT( "Home Edition" ), maxsiz);
999          else
1000             bstrncat(osbuf, TEXT( "Professional" ), maxsiz);
1001       }
1002 
1003       if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
1004          bstrncat(osbuf, TEXT("Windows 2000 "), maxsiz);
1005          if ( osvi.wProductType == VER_NT_WORKSTATION ) {
1006             bstrncat(osbuf, TEXT( "Professional" ), maxsiz);
1007          } else {
1008             if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
1009                bstrncat(osbuf, TEXT( "Datacenter Server" ), maxsiz);
1010             else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
1011                bstrncat(osbuf, TEXT( "Advanced Server" ), maxsiz);
1012             else bstrncat(osbuf, TEXT( "Server" ), maxsiz);
1013          }
1014       }
1015 
1016        // Include service pack (if any) and build number.
1017 
1018       if (_tcslen(osvi.szCSDVersion) > 0) {
1019           bstrncat(osbuf, TEXT(" ") , maxsiz);
1020           bstrncat(osbuf, osvi.szCSDVersion, maxsiz);
1021       }
1022 
1023       char buf[80];
1024 
1025       snprintf(buf, 80, " (build %d)", (int)osvi.dwBuildNumber);
1026       bstrncat(osbuf, buf, maxsiz);
1027 
1028       if (osvi.dwMajorVersion >= 6) {
1029          if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 )
1030             bstrncat(osbuf, TEXT( ", 64-bit" ), maxsiz);
1031          else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL )
1032             bstrncat(osbuf, TEXT(", 32-bit"), maxsiz);
1033       }
1034 
1035       return true;
1036    } else {
1037       bstrncpy(osbuf, "Unknown Windows version.", maxsiz);
1038       return true;
1039    }
1040 }
1041