thread-and-timer-corrections-to-afscreds-20031121
[openafs.git] / src / WINNT / client_creds / window.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 extern "C" {
11 #include <afs/param.h>
12 #include <afs/stds.h>
13 }
14
15 #include "afscreds.h"
16
17
18 /*
19  * DEFINITIONS ________________________________________________________________
20  *
21  */
22
23 #define ID_REMIND_TIMER      1000
24 #define ID_SERVICE_TIMER     1001
25
26 #define cREALLOC_TABS        4
27
28 #define dwTABPARAM_MOUNT     (LPTSTR)0
29 #define dwTABPARAM_ADVANCED  (LPTSTR)1
30 #define ISCELLTAB(_psz)      ((HIWORD((LONG)(_psz))) != 0)
31
32
33 /*
34  * PROTOTYPES _________________________________________________________________
35  *
36  */
37
38 void Main_OnInitDialog (HWND hDlg);
39 void Main_OnCheckMenuRemind (void);
40 void Main_OnRemindTimer (void);
41 void Main_OnMouseOver (void);
42 void Main_OnSelectTab (void);
43 void Main_OnCheckTerminate (void);
44 HWND Main_CreateTabDialog (HWND hTab, size_t iTab);
45
46 BOOL CALLBACK Terminate_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
47 void Terminate_OnInitDialog (HWND hDlg);
48 void Terminate_OnOK (HWND hDlg);
49
50
51 /*
52  * ROUTINES ___________________________________________________________________
53  *
54  */
55
56 BOOL CALLBACK Main_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
57 {
58    static UINT msgCheckTerminate = 0;
59    if (msgCheckTerminate == 0)
60       msgCheckTerminate = RegisterWindowMessage (TEXT("AfsCredsCheckTerminate"));
61
62    if (msg == msgCheckTerminate)
63       {
64       Main_OnCheckTerminate();
65       }
66    else switch (msg)
67       {
68       case WM_INITDIALOG:
69          g.hMain = hDlg;
70          Main_OnInitDialog (hDlg);
71          break;
72
73       case WM_DESTROY:
74          Creds_CloseLibraries();
75          ChangeTrayIcon (NIM_DELETE);
76          break;
77
78       case WM_ACTIVATEAPP:
79          if (wp)
80             {
81             Main_RepopulateTabs (FALSE);
82             }
83          break;
84
85       case WM_COMMAND:
86          switch (LOWORD(wp))
87             {
88             case IDOK:
89             case IDCANCEL:
90                Main_Show (FALSE);
91                break;
92
93             case M_ACTIVATE:
94                if (g.fIsWinNT || IsServiceRunning())
95                   {
96                   if (!lp) // Got here from "/show" parameter? switch tabs.
97                      {
98                      HWND hTab = GetDlgItem (g.hMain, IDC_TABS);
99                      TabCtrl_SetCurSel (hTab, 0);
100                      Main_OnSelectTab();
101                      }
102                   Main_Show (TRUE);
103                   }
104                else
105                   {
106                   Message (MB_ICONHAND, IDS_UNCONFIG_TITLE_95, IDS_UNCONFIG_DESC_95);
107                   }
108                break;
109
110             case M_TERMINATE:
111                if (g.fIsWinNT && IsServiceRunning())
112                   ModalDialog (IDD_TERMINATE, NULL, (DLGPROC)Terminate_DlgProc);
113                else if (g.fIsWinNT)
114                   ModalDialog (IDD_TERMINATE_SMALL, NULL, (DLGPROC)Terminate_DlgProc);
115                else // (!g.fIsWinNT)
116                   ModalDialog (IDD_TERMINATE_SMALL_95, NULL, (DLGPROC)Terminate_DlgProc);
117                break;
118
119             case M_TERMINATE_NOW:
120                Quit();
121                break;
122
123             case M_REMIND:
124                Main_OnCheckMenuRemind();
125                break;
126             }
127          break;
128
129       case WM_TIMER:
130          Main_OnRemindTimer();
131          break;
132
133       case WM_NOTIFY:
134          switch (((NMHDR*)lp)->code)
135             {
136             case TCN_SELCHANGE:
137                Main_OnSelectTab();
138                break;
139             }
140          break;
141
142       case WM_TRAYICON:
143          switch (lp)
144             {
145             case WM_LBUTTONDOWN:
146                if (IsServiceRunning() || !IsServiceConfigured())
147                   Main_Show (TRUE);
148                else if (!g.fIsWinNT)
149                   Message (MB_ICONHAND, IDS_UNCONFIG_TITLE_95, IDS_UNCONFIG_DESC_95);
150                else
151                   ShowStartupWizard();
152                break;
153
154             case WM_RBUTTONDOWN:
155                HMENU hm;
156                if ((hm = TaLocale_LoadMenu (MENU_TRAYICON)) != 0)
157                   {
158                   POINT pt;
159                   GetCursorPos(&pt);
160
161                   HMENU hmDummy = CreateMenu();
162                   InsertMenu (hmDummy, 0, MF_POPUP, (UINT)hm, NULL);
163
164                   BOOL fRemind = FALSE;
165                   lock_ObtainMutex(&g.credsLock);
166                   for (size_t iCreds = 0; iCreds < g.cCreds; ++iCreds)
167                      {
168                      if (g.aCreds[ iCreds ].fRemind)
169                         fRemind = TRUE;
170                      }
171                   lock_ReleaseMutex(&g.credsLock);
172                   CheckMenuItem (hm, M_REMIND, MF_BYCOMMAND | ((fRemind) ? MF_CHECKED : MF_UNCHECKED));
173
174                   TrackPopupMenu (GetSubMenu (hmDummy, 0),
175                                   TPM_RIGHTALIGN | TPM_RIGHTBUTTON,
176                                   pt.x, pt.y, NULL, hDlg, NULL);
177
178                   DestroyMenu (hmDummy);
179                   }
180                break;
181
182             case WM_MOUSEMOVE:
183                Main_OnMouseOver();
184                break;
185             }
186          break;
187       }
188
189    return FALSE;
190 }
191
192
193 void Main_Show (BOOL fShow)
194 {
195    if (fShow)
196       {
197       ShowWindow (g.hMain, SW_SHOW);
198       SetWindowPos (g.hMain, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
199       SetForegroundWindow (g.hMain);
200       }
201    else
202       {
203       SetWindowPos (g.hMain, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW);
204       }
205 }
206
207
208 void Main_OnInitDialog (HWND hDlg)
209 {
210    if (!g.fIsWinNT)
211       {
212       TCHAR szTitle[256];
213       GetString (szTitle, IDS_TITLE_95);
214       SetWindowText (hDlg, szTitle);
215       }
216
217    TCHAR szVersion[256];
218    DWORD dwPatch = 0;
219    TCHAR szUser[256];
220    GetString (szVersion, IDS_UNKNOWN);
221    GetString (szUser, IDS_UNKNOWN);
222
223    HKEY hk;
224    if (RegOpenKey (HKEY_LOCAL_MACHINE, REGSTR_PATH_AFS, &hk) == 0)
225       {
226       DWORD dwSize = sizeof(szVersion);
227       DWORD dwType = REG_SZ;
228       RegQueryValueEx (hk, REGVAL_AFS_VERSION, NULL, &dwType, (PBYTE)szVersion, &dwSize);
229
230       dwSize = sizeof(dwPatch);
231       dwType = REG_DWORD;
232       RegQueryValueEx (hk, REGVAL_AFS_PATCH, NULL, &dwType, (PBYTE)&dwPatch, &dwSize);
233       RegCloseKey (hk);
234       }
235
236    BOOL fFoundUserName = FALSE;
237    if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hk) == 0)
238       {
239       DWORD dwSize = sizeof(szUser);
240       DWORD dwType = REG_SZ;
241       if (RegQueryValueEx (hk, TEXT("DefaultUserName"), NULL, &dwType, (PBYTE)szUser, &dwSize) == 0)
242          fFoundUserName = TRUE;
243       RegCloseKey (hk);
244       }
245    if (!fFoundUserName)
246       {
247       if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("Network\\Logon"), &hk) == 0)
248          {
249          DWORD dwSize = sizeof(szUser);
250          DWORD dwType = REG_SZ;
251          if (RegQueryValueEx (hk, TEXT("UserName"), NULL, &dwType, (PBYTE)szUser, &dwSize) == 0)
252             fFoundUserName = TRUE;
253          RegCloseKey (hk);
254          }
255       }
256
257    TCHAR szSource[ cchRESOURCE ];
258    TCHAR szTarget[ cchRESOURCE ];
259
260    GetString (szSource, (dwPatch) ? IDS_TITLE_VERSION : IDS_TITLE_VERSION_NOPATCH);
261    wsprintf (szTarget, szSource, szVersion, dwPatch);
262    SetDlgItemText (hDlg, IDC_TITLE_VERSION, szTarget);
263
264    GetDlgItemText (hDlg, IDC_TITLE_NT, szSource, cchRESOURCE);
265    wsprintf (szTarget, szSource, szUser);
266    SetDlgItemText (hDlg, IDC_TITLE_NT, szTarget);
267 }
268
269
270 void Main_OnCheckMenuRemind (void)
271 {
272    BOOL fRemind = FALSE;
273    lock_ObtainMutex(&g.credsLock);
274    for (size_t iCreds = 0; iCreds < g.cCreds; ++iCreds)
275       {
276       if (g.aCreds[ iCreds ].fRemind)
277          fRemind = TRUE;
278       }
279
280    fRemind = !fRemind;
281    for (iCreds = 0; iCreds < g.cCreds; ++iCreds)
282       {
283       if (g.aCreds[ iCreds ].fRemind != fRemind)
284          {
285          g.aCreds[ iCreds ].fRemind = fRemind;
286          SaveRemind (iCreds);
287          }
288       }
289    lock_ReleaseMutex(&g.credsLock);
290
291    // Check the active tab, and fix its checkbox if necessary
292    //
293    HWND hTab = GetDlgItem (g.hMain, IDC_TABS);
294    LPTSTR pszTab = (LPTSTR)GetTabParam (hTab, TabCtrl_GetCurSel(hTab));
295    if (ISCELLTAB(pszTab) && (*pszTab))
296       {
297       HWND hDlg = GetTabChild (hTab);
298       if (hDlg)
299          CheckDlgButton (hDlg, IDC_CREDS_REMIND, fRemind);
300       }
301
302    // Make sure the reminder timer is going
303    //
304    Main_EnableRemindTimer (fRemind);
305 }
306
307
308 void Main_OnRemindTimer (void)
309 {
310    Main_RepopulateTabs (TRUE);
311
312    // See if anything is close to expiring; if so, display a warning
313    // dialog. Make sure we never display a warning more than once.
314    //
315    size_t iExpired;
316    if ((iExpired = Main_FindExpiredCreds()) != -1)
317       {
318       if (InterlockedIncrement (&g.fShowingMessage) != 1)
319          InterlockedDecrement (&g.fShowingMessage);
320       else
321          ShowObtainCreds (TRUE, g.aCreds[ iExpired ].szCell);
322       }
323 }
324
325
326 void Main_OnMouseOver (void)
327 {
328    if ((GetTickCount() - g.tickLastRetest) > cmsecMOUSEOVER)
329       {
330       Main_RepopulateTabs (TRUE);
331       }
332 }
333
334
335 void Main_OnSelectTab (void)
336 {
337    HWND hTab = GetDlgItem (g.hMain, IDC_TABS);
338    size_t iTab = TabCtrl_GetCurSel (hTab);
339
340    HWND hDlgOld = GetTabChild (hTab);
341
342    HWND hDlgNew;
343    if ((hDlgNew = Main_CreateTabDialog (hTab, iTab)) != NULL)
344       ShowWindow (hDlgNew, SW_SHOW);
345
346    if (hDlgOld)
347       DestroyWindow (hDlgOld);
348 }
349
350
351 void Main_OnCheckTerminate (void)
352 {
353    HKEY hk;
354    if (RegOpenKey (HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"), &hk) == 0)
355       {
356       DWORD dwSize = sizeof(g.fStartup);
357       DWORD dwType = REG_DWORD;
358       RegQueryValueEx (hk, TEXT("ShowTrayIcon"), NULL, &dwType, (PBYTE)&g.fStartup, &dwSize);
359       RegCloseKey (hk);
360       }
361
362    Shortcut_FixStartup (cszSHORTCUT_NAME, g.fStartup);
363
364    if (!g.fStartup)
365       Quit();
366 }
367
368
369 HWND Main_CreateTabDialog (HWND hTab, size_t iTab)
370 {
371    HWND hDlg = NULL;
372    LPTSTR psz = NULL;
373
374    TC_ITEM Item;
375    memset (&Item, 0x00, sizeof(Item));
376    Item.mask = TCIF_PARAM;
377    if (TabCtrl_GetItem (hTab, iTab, &Item))
378       {
379       psz = (LPTSTR)(Item.lParam);
380       }
381
382    if (psz == dwTABPARAM_ADVANCED)    // Advanced tab
383       {
384       hDlg = ModelessDialog (IDD_TAB_ADVANCED, hTab, (DLGPROC)Advanced_DlgProc);
385       }
386    else if (psz == dwTABPARAM_MOUNT)  // Mount Points tab
387       {
388       hDlg = ModelessDialog (IDD_TAB_MOUNT, hTab, (DLGPROC)Mount_DlgProc);
389       }
390    else if (ISCELLTAB(psz) && !*psz)  // No Creds tab
391       {
392       hDlg = ModelessDialogParam (IDD_TAB_NOCREDS, hTab, (DLGPROC)Creds_DlgProc, (LPARAM)psz);
393       }
394    else if (ISCELLTAB(psz) && *psz)   // Creds tab for a particular cell
395       {
396       hDlg = ModelessDialogParam (IDD_TAB_CREDS, hTab, (DLGPROC)Creds_DlgProc, (LPARAM)psz);
397       }
398
399    return hDlg;
400 }
401
402
403 void Main_RepopulateTabs (BOOL fDestroyInvalid)
404 {
405    static BOOL fInHere = FALSE;
406    if (!fInHere)
407       {
408       fInHere = TRUE;
409
410       if (IsWindowVisible (g.hMain))
411          fDestroyInvalid = FALSE;
412
413       // First we'll have to look around and see what credentials we currently
414       // have. This call just updates g.aCreds[]; it doesn't do anything else.
415       //
416       (void)GetCurrentCredentials();
417
418       // We want one tab on the main dialog for each g.aCredentials entry,
419       // and one tab for Advanced.
420       //
421       HWND hTab = GetDlgItem (g.hMain, IDC_TABS);
422
423       // Generate a list of the lParams we'll be giving tabs...
424       //
425       LPTSTR *aTabs = NULL;
426       size_t cTabs = 0;
427       size_t iTabOut = 0;
428
429       size_t nCreds = 0;
430       lock_ObtainMutex(&g.credsLock);
431       for (size_t iCreds = 0; iCreds < g.cCreds; ++iCreds)
432          {
433          if (g.aCreds[ iCreds ].szCell[0])
434             ++nCreds;
435          }
436       if (!nCreds)
437          {
438          fDestroyInvalid = TRUE;
439          }
440
441       if (!fDestroyInvalid)
442          {
443          int nTabs = TabCtrl_GetItemCount(hTab);
444          for (int iTab = 0; iTab < nTabs; ++iTab)
445             {
446             LPTSTR pszTab = (LPTSTR)GetTabParam (hTab, iTab);
447             if (ISCELLTAB(pszTab) && (*pszTab))
448                {
449                if (REALLOC (aTabs, cTabs, 1+iTabOut, cREALLOC_TABS))
450                   aTabs[ iTabOut++ ] = CloneString(pszTab);
451                }
452             }
453          }
454
455       if (nCreds == 0)
456          {
457          if (REALLOC (aTabs, cTabs, 1+iTabOut, cREALLOC_TABS))
458             aTabs[ iTabOut++ ] = CloneString (TEXT(""));
459          }
460       else for (iCreds = 0; iCreds < g.cCreds; ++iCreds)
461          {
462          if (g.aCreds[ iCreds ].szCell[0])
463             {
464             for (size_t ii = 0; ii < iTabOut; ++ii)
465                {
466                if (!ISCELLTAB (aTabs[ii]))
467                   continue;
468                if (!lstrcmpi (g.aCreds[ iCreds ].szCell, aTabs[ ii ]))
469                   break;
470                }
471             if (ii == iTabOut)
472                {
473                if (REALLOC (aTabs, cTabs, 1+iTabOut, cREALLOC_TABS))
474                   aTabs[ iTabOut++ ] = CloneString (g.aCreds[ iCreds ].szCell);
475                }
476             }
477          }
478       lock_ReleaseMutex(&g.credsLock);
479
480       if (REALLOC (aTabs, cTabs, 1+iTabOut, cREALLOC_TABS))
481          aTabs[ iTabOut++ ] = dwTABPARAM_MOUNT;
482
483       if (g.fIsWinNT)
484          {
485          if (REALLOC (aTabs, cTabs, 1+iTabOut, cREALLOC_TABS))
486             aTabs[ iTabOut++ ] = dwTABPARAM_ADVANCED;
487          }
488
489       // Now erase the current tabs, and re-add new ones. Remember which tab is
490       // currently selected, so we can try to go back to it later.
491       //
492       int iTabSel = 0;
493       if (TabCtrl_GetItemCount(hTab))
494          {
495          LPTSTR pszTabSel = (LPTSTR)GetTabParam (hTab, TabCtrl_GetCurSel(hTab));
496          for (size_t iSel = 0; iSel < iTabOut; ++iSel)
497             {
498             if ((!ISCELLTAB(pszTabSel))  && (!ISCELLTAB(aTabs[iSel])) && (pszTabSel == aTabs[iSel]))
499                iTabSel = iSel;
500             else if (ISCELLTAB(pszTabSel) && ISCELLTAB(aTabs[iSel]) && !lstrcmpi (pszTabSel, aTabs[iSel]))
501                iTabSel = iSel;
502             }
503          }
504
505       int nTabs = TabCtrl_GetItemCount(hTab);
506       for (int iTab = 0; iTab < nTabs; ++iTab)
507          {
508          LPTSTR pszTab = (LPTSTR)GetTabParam (hTab, iTab);
509          if (ISCELLTAB(pszTab))
510             FreeString (pszTab);
511          }
512       TabCtrl_DeleteAllItems (hTab);
513
514       for (size_t ii = 0; ii < iTabOut; ++ii)
515          {
516          TCHAR szTitle[cchRESOURCE];
517          if (aTabs[ii] == dwTABPARAM_ADVANCED)
518             GetString (szTitle, IDS_ADVANCED);
519          else if (aTabs[ii] == dwTABPARAM_MOUNT)
520             GetString (szTitle, IDS_MOUNT);
521          else if ((nCreds <= 1) || (aTabs[ii][0] == TEXT('\0')))
522             GetString (szTitle, IDS_CREDENTIALS);
523          else
524             lstrcpy (szTitle, aTabs[ii]);
525
526          TC_ITEM Item;
527          memset (&Item, 0x00, sizeof(Item));
528          Item.mask = TCIF_PARAM | TCIF_TEXT;
529          Item.pszText = szTitle;
530          Item.cchTextMax = cchRESOURCE;
531          Item.lParam = (LPARAM)(aTabs[ii]);
532
533          TabCtrl_InsertItem (hTab, ii, &Item);
534          }
535
536       if (aTabs != NULL)
537          Free (aTabs);
538
539       TabCtrl_SetCurSel (hTab, iTabSel);
540       Main_OnSelectTab ();
541
542       fInHere = FALSE;
543       }
544 }
545
546
547 void Main_EnableRemindTimer (BOOL fEnable)
548 {
549    static BOOL bEnabled = FALSE;
550
551    if ( fEnable == FALSE && bEnabled == TRUE ) {
552        KillTimer (g.hMain, ID_REMIND_TIMER);
553        bEnabled = FALSE;
554    } else if ( fEnable == TRUE && bEnabled == FALSE ) {
555       SetTimer (g.hMain, ID_REMIND_TIMER, (ULONG)cmsec1MINUTE * cminREMIND_TEST, NULL);
556       bEnabled = TRUE;
557    }
558 }
559
560
561 size_t Main_FindExpiredCreds (void)
562 {
563    size_t retval = (size_t) -1;
564    lock_ObtainMutex(&g.expirationCheckLock);
565    lock_ObtainMutex(&g.credsLock);
566    for (size_t iCreds = 0; iCreds < g.cCreds; ++iCreds)
567       {
568       if (!g.aCreds[ iCreds ].szCell[0])
569          continue;
570       if (!g.aCreds[ iCreds ].fRemind)
571          continue;
572
573       SYSTEMTIME stNow;
574       GetLocalTime (&stNow);
575
576       FILETIME ftNow;
577       SystemTimeToFileTime (&stNow, &ftNow);
578
579       FILETIME ftExpires;
580       SystemTimeToFileTime (&g.aCreds[ iCreds ].stExpires, &ftExpires);
581
582       LONGLONG llNow = (((LONGLONG)ftNow.dwHighDateTime) << 32) + (LONGLONG)(ftNow.dwLowDateTime);
583       LONGLONG llExpires = (((LONGLONG)ftExpires.dwHighDateTime) << 32) + (LONGLONG)(ftExpires.dwLowDateTime);
584
585       llNow /= c100ns1SECOND;
586       llExpires /= c100ns1SECOND;
587
588       if (llExpires <= (llNow + (LONGLONG)cminREMIND_WARN * csec1MINUTE))
589          retval = (size_t) iCreds;
590          break;
591       }
592    
593    lock_ReleaseMutex(&g.credsLock);
594    lock_ReleaseMutex(&g.expirationCheckLock);
595
596    return retval;
597 }
598
599
600 BOOL CALLBACK Terminate_DlgProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
601 {
602    switch (msg)
603       {
604       case WM_INITDIALOG:
605          Terminate_OnInitDialog (hDlg);
606          break;
607
608       case WM_COMMAND:
609          switch (LOWORD(wp))
610             {
611             case IDOK:
612                Terminate_OnOK (hDlg);
613                break;
614
615             case IDCANCEL:
616                EndDialog (hDlg, IDCANCEL);
617                break;
618             }
619          break;
620       }
621
622    return FALSE;
623 }
624
625
626 void Terminate_OnInitDialog (HWND hDlg)
627 {
628    BOOL fPersistent = IsServicePersistent();
629
630    CheckDlgButton (hDlg, IDC_STARTUP, g.fStartup);
631    CheckDlgButton (hDlg, IDC_LEAVE, fPersistent);
632    CheckDlgButton (hDlg, IDC_STOP, !fPersistent);
633 }
634
635
636 void Terminate_OnOK (HWND hDlg)
637 {
638    if (IsServiceRunning())
639       {
640       if (IsDlgButtonChecked (hDlg, IDC_STOP))
641          {
642          SC_HANDLE hManager;
643          if ((hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL)
644             {
645             SC_HANDLE hService;
646             if ((hService = OpenService (hManager, TEXT("TransarcAFSDaemon"), SERVICE_ALL_ACCESS)) != NULL)
647                {
648                SERVICE_STATUS Status;
649                ControlService (hService, SERVICE_CONTROL_STOP, &Status);
650
651                CloseServiceHandle (hService);
652                }
653
654             CloseServiceHandle (hManager);
655             }
656          }
657       }
658
659    g.fStartup = IsDlgButtonChecked (hDlg, IDC_STARTUP);
660
661    HKEY hk;
662    if (RegCreateKey (HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Services\\TransarcAFSDaemon\\Parameters"), &hk) == 0)
663       {
664       DWORD dwSize = sizeof(g.fStartup);
665       DWORD dwType = REG_DWORD;
666       RegSetValueEx (hk, TEXT("ShowTrayIcon"), NULL, dwType, (PBYTE)&g.fStartup, dwSize);
667       RegCloseKey (hk);
668       }
669
670    Shortcut_FixStartup (cszSHORTCUT_NAME, g.fStartup);
671
672    Quit();
673    EndDialog (hDlg, IDOK);
674 }
675