]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/MRU.CPP
hello world
[icculus/iodoom3.git] / neo / tools / radiant / MRU.CPP
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code.  If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include <windowsx.h>
33 #include "mru.h"
34
35 //*************************************************************
36 //  File name: mru.c
37 //
38 //  Description:
39 //
40 //      Routines for MRU support
41 //
42 //  Development Team:
43 //
44 //      Gilles Vollant (100144.2636@compuserve.com) 
45 //
46 //*************************************************************
47
48
49 // CreateMruMenu  : MRUMENU constructor
50 // wNbLruShowInit : nb of item showed in menu
51 // wNbLruMenuInit : nb of item stored in memory
52 // wMaxSizeLruItemInit : size max. of filename
53
54
55 //*************************************************************
56 //
57 //  CreateMruMenu()
58 //
59 //  Purpose:
60 //
61 //              Allocate and Initialize an MRU and return a pointer on it
62 //
63 //
64 //  Parameters:
65 //
66 //      WORD wNbLruShowInit -      Maximum number of item displayed on menu
67 //      WORD wNbLruMenuInit -      Maximum number of item stored in memory
68 //      WORD wMaxSizeLruItemInit - Maximum size of an item (ie size of pathname)
69 //      WORD wIdMruInit -          ID of the first item in the menu (default:IDMRU)
70 //
71 //
72 //  Return: (LPMRUMENU)
73 //
74 //      Pointer on a MRUMENU structure, used by other function
75 //
76 //
77 //  Comments:
78 //      wNbLruShowInit <= wNbLruMenuInit
79 //
80 //
81 //  History:    Date       Author       Comment
82 //              09/24/94   G. Vollant   Created
83 //
84 //*************************************************************
85
86 LPMRUMENU CreateMruMenu (WORD wNbLruShowInit,
87             WORD wNbLruMenuInit,WORD wMaxSizeLruItemInit,WORD wIdMruInit)
88 {
89 LPMRUMENU lpMruMenu;
90   lpMruMenu = (LPMRUMENU)GlobalAllocPtr(GHND,sizeof(MRUMENU));
91
92   lpMruMenu->wNbItemFill = 0;                   
93   lpMruMenu->wNbLruMenu = wNbLruMenuInit;             
94   lpMruMenu->wNbLruShow = wNbLruShowInit;
95   lpMruMenu->wIdMru = wIdMruInit;
96   lpMruMenu->wMaxSizeLruItem = wMaxSizeLruItemInit;
97   lpMruMenu->lpMRU = (LPSTR)GlobalAllocPtr(GHND,
98                       lpMruMenu->wNbLruMenu*(UINT)lpMruMenu->wMaxSizeLruItem);
99   if (lpMruMenu->lpMRU == NULL)
100      {
101        GlobalFreePtr(lpMruMenu);
102        lpMruMenu =  NULL;
103      }
104   return lpMruMenu;
105 }
106
107 //*************************************************************
108 //
109 //  CreateMruMenuDefault()
110 //
111 //  Purpose:
112 //
113 //              Allocate and Initialize an MRU and return a pointer on it
114 //              Use default parameter
115 //
116 //
117 //  Parameters:
118 //
119 //
120 //  Return: (LPMRUMENU)
121 //
122 //      Pointer on a MRUMENU structure, used by other function
123 //
124 //
125 //  Comments:
126 //
127 //
128 //  History:    Date       Author       Comment
129 //              09/24/94   G. Vollant   Created
130 //
131 //*************************************************************
132
133 LPMRUMENU CreateMruMenuDefault()
134 {
135   return CreateMruMenu (NBMRUMENUSHOW,NBMRUMENU,MAXSIZEMRUITEM,IDMRU);
136 }
137
138
139 //*************************************************************
140 //
141 //  DeleteMruMenu()
142 //
143 //  Purpose:
144 //              Destructor :
145 //              Clean and free a MRUMENU structure
146 //
147 //  Parameters:
148 //
149 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU, allocated
150 //             by CreateMruMenu() or CreateMruMenuDefault()
151 //
152 //
153 //  Return: void
154 //
155 //
156 //  Comments:
157 //
158 //
159 //  History:    Date       Author       Comment
160 //              09/24/94   G. Vollant   Created
161 //
162 //*************************************************************
163 void DeleteMruMenu(LPMRUMENU lpMruMenu)
164 {
165   GlobalFreePtr(lpMruMenu->lpMRU);
166   GlobalFreePtr(lpMruMenu);
167 }
168
169 //*************************************************************
170 //
171 //  SetNbLruShow()
172 //
173 //  Purpose:
174 //              Change the maximum number of item displayed on menu
175 //
176 //  Parameters:
177 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
178 //      WORD wNbLruShowInit -      Maximum number of item displayed on menu
179 //
180 //
181 //  Return: void
182 //
183 //
184 //  Comments:
185 //
186 //
187 //  History:    Date       Author       Comment
188 //              09/24/94   G. Vollant   Created
189 //
190 //*************************************************************
191 void SetNbLruShow   (LPMRUMENU lpMruMenu,WORD wNbLruShowInit)
192 {
193   lpMruMenu->wNbLruShow = min(wNbLruShowInit,lpMruMenu->wNbLruMenu);
194 }
195
196 //*************************************************************
197 //
198 //  SetMenuItem()
199 //
200 //  Purpose:
201 //              Set the filename of an item 
202 //
203 //  Parameters:
204 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
205 //      WORD wItem -               Number of Item to set, zero based
206 //      LPSTR lpItem -             String, contain the filename of the item
207 //
208 //
209 //  Return: (BOOL)
210 //      TRUE  - Function run successfully
211 //      FALSE - Function don't run successfully
212 //
213 //
214 //  Comments:
215 //      used when load .INI or reg database
216 //
217 //  History:    Date       Author       Comment
218 //              09/24/94   G. Vollant   Created
219 //
220 //*************************************************************
221 BOOL SetMenuItem    (LPMRUMENU lpMruMenu,WORD wItem,LPSTR lpItem)
222 {                                      
223   if (wItem >= NBMRUMENU) 
224     return FALSE;
225   _fstrncpy((lpMruMenu->lpMRU) + 
226             ((lpMruMenu->wMaxSizeLruItem) * (UINT)wItem),
227             lpItem,lpMruMenu->wMaxSizeLruItem-1);
228   lpMruMenu->wNbItemFill = max(lpMruMenu->wNbItemFill,wItem+1);
229   return TRUE;
230 }
231
232 //*************************************************************
233 //
234 //  GetMenuItem()
235 //
236 //  Purpose:
237 //              Get the filename of an item 
238 //
239 //  Parameters:
240 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
241 //      WORD wItem -               Number of Item to set, zero based
242 //      BOOL fIDMBased -           TRUE :  wItem is based on ID menu item
243 //                                 FALSE : wItem is zero-based
244 //      LPSTR lpItem -             String where the filename of the item will be
245 //                                   stored by GetMenuItem()
246 //      UINT  uiSize -             Size of the lpItem buffer
247 //
248 //
249 //  Return: (BOOL)
250 //      TRUE  - Function run successfully
251 //      FALSE - Function don't run successfully
252 //
253 //
254 //  Comments:
255 //      Used for saving in .INI or reg database, or when user select
256 //        an MRU in File menu
257 //
258 //  History:    Date       Author       Comment
259 //              09/24/94   G. Vollant   Created
260 //
261 //*************************************************************
262 BOOL GetMenuItem    (LPMRUMENU lpMruMenu,WORD wItem,
263                      BOOL fIDMBased,LPSTR lpItem,UINT uiSize)
264 {
265   if (fIDMBased) 
266     wItem -= (lpMruMenu->wIdMru + 1);
267   if (wItem >= lpMruMenu->wNbItemFill) 
268     return FALSE;
269   _fstrncpy(lpItem,(lpMruMenu->lpMRU) + 
270                 ((lpMruMenu->wMaxSizeLruItem) * (UINT)(wItem)),uiSize);
271   *(lpItem+uiSize-1) = '\0';
272   return TRUE;
273 }
274
275 //*************************************************************
276 //
277 //  AddNewItem()
278 //
279 //  Purpose:
280 //              Add an item at the begin of the list
281 //
282 //  Parameters:
283 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
284 //      LPSTR lpItem -             String contain the filename to add
285 //
286 //  Return: (BOOL)
287 //      TRUE  - Function run successfully
288 //      FALSE - Function don't run successfully
289 //
290 //
291 //  Comments:
292 //      Used when used open a file (using File Open common
293 //        dialog, Drag and drop or MRU)
294 //
295 //  History:    Date       Author       Comment
296 //              09/24/94   G. Vollant   Created
297 //
298 //*************************************************************
299 void AddNewItem     (LPMRUMENU lpMruMenu,LPSTR lpItem)
300 {
301 WORD i,j;
302   for (i=0;i<lpMruMenu->wNbItemFill;i++)
303     if (lstrcmpi(lpItem,(lpMruMenu->lpMRU) + 
304         ((lpMruMenu->wMaxSizeLruItem) * (UINT)i)) == 0)
305       {         
306         // Shift the other items
307         for (j=i;j>0;j--)
308          lstrcpy((lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)j),
309                  (lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)(j-1)));
310         _fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1);  
311         return ;
312       }
313   lpMruMenu->wNbItemFill = min(lpMruMenu->wNbItemFill+1,lpMruMenu->wNbLruMenu);
314   for (i=lpMruMenu->wNbItemFill-1;i>0;i--)
315      lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i),
316              lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i-1)));
317   _fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1);  
318 }
319
320 //*************************************************************
321 //
322 //  DelMenuItem()
323 //
324 //  Purpose:
325 //              Delete an item
326 //
327 //  Parameters:
328 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
329 //      WORD wItem -               Number of Item to set, zero based
330 //      BOOL fIDMBased -           TRUE :  wItem is based on ID menu item
331 //                                 FALSE : wItem is zero-based
332 //
333 //  Return: (BOOL)
334 //      TRUE  - Function run successfully
335 //      FALSE - Function don't run successfully
336 //
337 //
338 //  Comments:
339 //      Used when used open a file, using MRU, and when an error
340 //         occured (by example, when file was deleted)
341 //
342 //  History:    Date       Author       Comment
343 //              09/24/94   G. Vollant   Created
344 //
345 //*************************************************************
346 BOOL DelMenuItem(LPMRUMENU lpMruMenu,WORD wItem,BOOL fIDMBased)
347
348 WORD i;
349   if (fIDMBased) 
350     wItem -= (lpMruMenu->wIdMru + 1);
351   if (lpMruMenu->wNbItemFill <= wItem) 
352     return FALSE;
353   lpMruMenu->wNbItemFill--;
354   for (i=wItem;i<lpMruMenu->wNbItemFill;i++)
355      lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i),
356              lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i+1)));
357   return TRUE;
358 }
359                            
360 //*************************************************************
361 //
362 //  PlaceMenuMRUItem()
363 //
364 //  Purpose:
365 //              Add MRU at the end of a menu
366 //
367 //  Parameters:
368 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
369 //      HMENU hMenu -              Handle of menu where MRU must be added
370 //      UINT uiItem -              Item of menu entry where MRU must be added
371 //
372 //  Return: void
373 //
374 //
375 //  Comments:
376 //      Used MRU is modified, for refresh the File menu
377 //
378 //  History:    Date       Author       Comment
379 //              09/24/94   G. Vollant   Created
380 //
381 //*************************************************************
382 void PlaceMenuMRUItem(LPMRUMENU lpMruMenu,HMENU hMenu,UINT uiItem)
383 {
384 int  i;   
385 WORD wNbShow;
386   if (hMenu == NULL) 
387     return;
388   // remove old MRU in menu
389   for (i=0;i<=(int)(lpMruMenu->wNbLruMenu);i++)
390     RemoveMenu(hMenu,i+lpMruMenu->wIdMru,MF_BYCOMMAND);
391
392   if (lpMruMenu->wNbItemFill == 0) 
393     return;
394
395   // If they are item, insert a separator before the files
396   InsertMenu(hMenu,uiItem,MF_SEPARATOR,lpMruMenu->wIdMru,NULL);
397
398   wNbShow = min(lpMruMenu->wNbItemFill,lpMruMenu->wNbLruShow);
399   for (i=(int)wNbShow-1;i>=0;i--)
400   {
401   LPSTR lpTxt;
402     if (lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20))
403       {
404         wsprintf(lpTxt,"&%lu %s",
405                  (DWORD)(i+1),lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem*(UINT)i));
406         InsertMenu(hMenu,(((WORD)i)!=(wNbShow-1)) ? (lpMruMenu->wIdMru+i+2) : lpMruMenu->wIdMru,
407                    MF_STRING,lpMruMenu->wIdMru+i+1,lpTxt);   
408         GlobalFreePtr(lpTxt);
409       }
410   }
411
412 }
413
414 ///////////////////////////////////////////
415
416
417
418 //*************************************************************
419 //
420 //  SaveMruInIni()
421 //
422 //  Purpose:
423 //              Save MRU in a private .INI
424 //
425 //  Parameters:
426 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
427 //      LPSTR lpszSection  -       Points to a null-terminated string containing
428 //                                      the name of the section 
429 //      LPSTR lpszFile -           Points to a null-terminated string that names 
430 //                                      the initialization file. 
431 //
432 //  Return: (BOOL)
433 //      TRUE  - Function run successfully
434 //      FALSE - Function don't run successfully
435 //
436 //
437 //  Comments:
438 //      See WritePrivateProfileString API for more info on lpszSection and lpszFile
439 //
440 //  History:    Date       Author       Comment
441 //              09/24/94   G. Vollant   Created
442 //
443 //*************************************************************
444 BOOL SaveMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile)
445 {
446 LPSTR lpTxt;
447 WORD i;
448
449   lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
450   if (lpTxt == NULL) 
451     return FALSE;
452
453   for (i=0;i<lpMruMenu->wNbLruMenu;i++)
454     {
455     char szEntry[16];
456       wsprintf(szEntry,"File%lu",(DWORD)i+1);
457       if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10))
458         *lpTxt = '\0';
459       WritePrivateProfileString(lpszSection,szEntry,lpTxt,lpszFile);
460     }
461   GlobalFreePtr(lpTxt);
462   WritePrivateProfileString(NULL,NULL,NULL,lpszFile); // flush cache 
463   return TRUE;
464 }
465
466
467 //*************************************************************
468 //
469 //  LoadMruInIni()
470 //
471 //  Purpose:
472 //              Load MRU from a private .INI
473 //
474 //  Parameters:
475 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
476 //      LPSTR lpszSection  -       Points to a null-terminated string containing
477 //                                      the name of the section 
478 //      LPSTR lpszFile -           Points to a null-terminated string that names 
479 //                                      the initialization file. 
480 //
481 //  Return: (BOOL)
482 //      TRUE  - Function run successfully
483 //      FALSE - Function don't run successfully
484 //
485 //
486 //  Comments:
487 //      See GetPrivateProfileString API for more info on lpszSection and lpszFile
488 //
489 //  History:    Date       Author       Comment
490 //              09/24/94   G. Vollant   Created
491 //
492 //*************************************************************
493 BOOL LoadMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile)
494 {
495 LPSTR lpTxt;
496 WORD i;
497   lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
498   if (lpTxt == NULL) 
499     return FALSE;
500
501   for (i=0;i<lpMruMenu->wNbLruMenu;i++)
502     {
503     char szEntry[16];
504       
505       wsprintf(szEntry,"File%lu",(DWORD)i+1);
506       GetPrivateProfileString(lpszSection,szEntry,"",lpTxt,
507                               lpMruMenu->wMaxSizeLruItem + 10,lpszFile);
508       if (*lpTxt == '\0')
509         break;
510       SetMenuItem(lpMruMenu,i,lpTxt);
511     }
512   GlobalFreePtr(lpTxt);
513   return TRUE;
514 }
515
516 #ifdef WIN32
517
518 BOOL IsWin395OrHigher(void)
519 {
520   WORD wVer;
521
522   wVer = LOWORD(GetVersion());
523   wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer);
524
525   return (wVer >= 0x035F);              // 5F = 95 dec
526 }
527
528
529 //*************************************************************
530 //
531 //  SaveMruInReg()
532 //
533 //  Purpose:
534 //              Save MRU in the registry
535 //
536 //  Parameters:
537 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
538 //      LPSTR lpszKey  -           Points to a null-terminated string 
539 //                                      specifying  the name of a key that 
540 //                                      this function opens or creates.
541 //
542 //  Return: (BOOL)
543 //      TRUE  - Function run successfully
544 //      FALSE - Function don't run successfully
545 //
546 //
547 //  Comments:
548 //      Win32 function designed for Windows NT and Windows 95
549 //      See RegCreateKeyEx API for more info on lpszKey
550 //
551 //  History:    Date       Author       Comment
552 //              09/24/94   G. Vollant   Created
553 //
554 //*************************************************************
555 BOOL SaveMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey)
556 {
557 LPSTR lpTxt;
558 WORD i;
559 HKEY hCurKey;
560 DWORD dwDisp;
561
562   lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
563   if (lpTxt == NULL) 
564     return FALSE;
565
566   RegCreateKeyEx(HKEY_CURRENT_USER,lpszKey,0,NULL,
567                   REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hCurKey,&dwDisp);
568
569   for (i=0;i<lpMruMenu->wNbLruMenu;i++)
570     {
571     char szEntry[16];
572       wsprintf(szEntry,"File%lu",(DWORD)i+1);
573       if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10))
574         *lpTxt = '\0';
575       RegSetValueEx(hCurKey,szEntry,0,REG_SZ,(unsigned char*)lpTxt,lstrlen(lpTxt));
576     }
577   RegCloseKey(hCurKey);
578   GlobalFreePtr(lpTxt);
579   return TRUE;
580 }
581
582 //*************************************************************
583 //
584 //  LoadMruInReg()
585 //
586 //  Purpose:
587 //              Load MRU from the registry
588 //
589 //  Parameters:
590 //      LPMRUMENU lpMruMenu -      pointer on MRUMENU
591 //      LPSTR lpszKey  -           Points to a null-terminated string 
592 //                                      specifying  the name of a key that 
593 //                                      this function opens or creates.
594 //
595 //  Return: (BOOL)
596 //      TRUE  - Function run successfully
597 //      FALSE - Function don't run successfully
598 //
599 //
600 //  Comments:
601 //      Win32 function designed for Windows NT and Windows 95
602 //      See RegOpenKeyEx API for more info on lpszKey
603 //
604 //  History:    Date       Author       Comment
605 //              09/24/94   G. Vollant   Created
606 //
607 //*************************************************************
608 BOOL LoadMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey)
609 {
610 LPSTR lpTxt;
611 WORD i;
612 HKEY hCurKey;
613 DWORD dwType;
614   lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20);
615   if (lpTxt == NULL) 
616     return FALSE;
617
618   RegOpenKeyEx(HKEY_CURRENT_USER,lpszKey,0,KEY_READ,&hCurKey);
619
620
621   for (i=0;i<lpMruMenu->wNbLruMenu;i++)
622     {
623     char szEntry[16];
624     DWORD dwSizeBuf;  
625       wsprintf(szEntry,"File%lu",(DWORD)i+1);
626       *lpTxt = '\0';
627       dwSizeBuf = lpMruMenu->wMaxSizeLruItem + 10;
628       RegQueryValueEx(hCurKey,szEntry,NULL,&dwType,(LPBYTE)lpTxt,&dwSizeBuf);
629       *(lpTxt+dwSizeBuf)='\0';
630       if (*lpTxt == '\0')
631         break;
632       SetMenuItem(lpMruMenu,i,lpTxt);
633     }
634   RegCloseKey(hCurKey);
635   GlobalFreePtr(lpTxt);
636   return TRUE;
637 }
638
639
640 //*************************************************************
641 //
642 //  GetWin32Kind()
643 //
644 //  Purpose:
645 //              Get the Win32 platform
646 //
647 //  Parameters:
648 //
649 //  Return: (WIN32KIND)
650 //      WINNT -           Run under Windows NT
651 //      WIN32S -          Run under Windows 3.1x + Win32s
652 //      WIN95ORGREATHER - Run under Windows 95
653 //
654 //
655 //  Comments:
656 //      Win32 function designed for Windows NT and Windows 95
657 //      See RegOpenKeyEx API for more info on lpszKey
658 //
659 //  History:    Date       Author       Comment
660 //              09/24/94   G. Vollant   Created
661 //
662 //*************************************************************
663 WIN32KIND GetWin32Kind()
664 {
665 BOOL IsWin395OrHigher(void);
666
667   WORD wVer;
668
669   if ((GetVersion() & 0x80000000) == 0)
670     return WINNT;
671   wVer = LOWORD(GetVersion());
672   wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer);
673
674   if (wVer >= 0x035F)
675     return WIN95ORGREATHER;
676   else
677     return WIN32S;
678 }
679 #endif