1 /*
2  * PROJECT:     ReactOS Services
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        base/applications/mscutils/servman/mainwnd.c
5  * PURPOSE:     Main window message handler
6  * COPYRIGHT:   Copyright 2006-2017 Ged Murphy <gedmurphy@reactos.org>
7  *
8  */
9 
10 #include "precomp.h"
11 
12 #include <windowsx.h>
13 
14 static const WCHAR szMainWndClass[] = L"ServManWndClass";
15 
16 /* Toolbar buttons */
17 static const TBBUTTON Buttons [] =
18 {   /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
19     {TBICON_PROP,    ID_PROP,    TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0},    /* properties */
20     {TBICON_REFRESH, ID_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},          /* refresh */
21     {TBICON_EXPORT,  ID_EXPORT,  TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0},          /* export */
22 
23     /* Note: First item for a separator is its width in pixels */
24     {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},                                  /* separator */
25 
26     {TBICON_CREATE,  ID_CREATE,  TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0 },         /* create */
27     {TBICON_DELETE,  ID_DELETE,  TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0 },   /* delete */
28 
29     {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0},                                  /* separator */
30 
31     {TBICON_START,   ID_START,   TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0 },   /* start */
32     {TBICON_STOP,    ID_STOP,    TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0 },   /* stop */
33     {TBICON_PAUSE,   ID_PAUSE,   TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0 },   /* pause */
34     {TBICON_RESTART, ID_RESTART, TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0 },   /* restart */
35 };
36 
37 
38 /* menu hints */
39 static const MENU_HINT MainMenuHintTable[] = {
40     /* File Menu */
41     {ID_EXPORT,    IDS_HINT_EXPORT},
42     {ID_EXIT,      IDS_HINT_EXIT},
43 
44     /* Action Menu */
45     {ID_CONNECT,  IDS_HINT_CONNECT},
46     {ID_START,    IDS_HINT_START},
47     {ID_STOP,     IDS_HINT_STOP},
48     {ID_PAUSE,    IDS_HINT_PAUSE},
49     {ID_RESUME,   IDS_HINT_RESUME},
50     {ID_RESTART,  IDS_HINT_RESTART},
51     {ID_REFRESH,  IDS_HINT_REFRESH},
52     {ID_EDIT,     IDS_HINT_EDIT},
53     {ID_CREATE,   IDS_HINT_CREATE},
54     {ID_DELETE,   IDS_HINT_DELETE},
55     {ID_PROP,     IDS_HINT_PROP},
56 
57     /* View menu */
58     {ID_VIEW_LARGE,   IDS_HINT_LARGE},
59     {ID_VIEW_SMALL,   IDS_HINT_SMALL},
60     {ID_VIEW_LIST,    IDS_HINT_LIST},
61     {ID_VIEW_DETAILS, IDS_HINT_DETAILS},
62     {ID_VIEW_CUST,    IDS_HINT_CUST},
63 
64     /* Help Menu */
65     {ID_HELP,     IDS_HINT_HELP},
66     {ID_ABOUT,    IDS_HINT_ABOUT}
67 };
68 /* system menu hints */
69 static const MENU_HINT SystemMenuHintTable[] = {
70     {SC_RESTORE,    IDS_HINT_SYS_RESTORE},
71     {SC_MOVE,       IDS_HINT_SYS_MOVE},
72     {SC_SIZE,       IDS_HINT_SYS_SIZE},
73     {SC_MINIMIZE,   IDS_HINT_SYS_MINIMIZE},
74     {SC_MAXIMIZE,   IDS_HINT_SYS_MAXIMIZE},
75     {SC_CLOSE,      IDS_HINT_SYS_CLOSE},
76 };
77 
78 
79 static BOOL
80 MainWndMenuHint(PMAIN_WND_INFO Info,
81                 WORD CmdId,
82                 const MENU_HINT *HintArray,
83                 DWORD HintsCount,
84                 UINT DefHintId)
85 {
86     BOOL Found = FALSE;
87     const MENU_HINT *LastHint;
88     UINT HintId = DefHintId;
89 
90     LastHint = HintArray + HintsCount;
91     while (HintArray != LastHint)
92     {
93         if (HintArray->CmdId == CmdId)
94         {
95             HintId = HintArray->HintId;
96             Found = TRUE;
97             break;
98         }
99         HintArray++;
100     }
101 
102     StatusBarLoadString(Info->hStatus,
103                         SB_SIMPLEID,
104                         hInstance,
105                         HintId);
106 
107     return Found;
108 }
109 
110 
111 static VOID
112 UpdateMainStatusBar(PMAIN_WND_INFO Info)
113 {
114     if (Info->hStatus != NULL)
115     {
116         SendMessage(Info->hStatus,
117                     SB_SIMPLE,
118                     (WPARAM)Info->bInMenuLoop,
119                     0);
120     }
121 }
122 
123 VOID
124 UpdateServiceCount(PMAIN_WND_INFO Info)
125 {
126     LPWSTR lpNumServices;
127 
128     if (AllocAndLoadString(&lpNumServices,
129                            hInstance,
130                            IDS_NUM_SERVICES))
131     {
132         WCHAR szNumServices[32];
133 
134         INT NumListedServ = ListView_GetItemCount(Info->hListView);
135 
136         _snwprintf(szNumServices,
137                    31,
138                    lpNumServices,
139                    NumListedServ);
140 
141         SendMessage(Info->hStatus,
142                     SB_SETTEXT,
143                     0,
144                     (LPARAM)szNumServices);
145 
146         LocalFree(lpNumServices);
147     }
148 }
149 
150 
151 VOID SetMenuAndButtonStates(PMAIN_WND_INFO Info)
152 {
153     HMENU hMainMenu;
154     UINT i;
155 
156     /* get handle to menu */
157     hMainMenu = GetMenu(Info->hMainWnd);
158 
159     /* set all to greyed */
160     for (i = ID_START; i <= ID_RESTART; i++)
161     {
162         EnableMenuItem(hMainMenu, i, MF_GRAYED);
163         EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), i, MF_GRAYED);
164         SendMessage(Info->hTool, TB_SETSTATE, i,
165                     (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
166     }
167 
168     if (Info->SelectedItem != NO_ITEM_SELECTED)
169     {
170         LPQUERY_SERVICE_CONFIG lpServiceConfig = NULL;
171         DWORD Flags, State;
172 
173         /* allow user to delete service */
174         if (Info->bIsUserAnAdmin)
175         {
176             SendMessage(Info->hTool, TB_SETSTATE, ID_DELETE,
177                        (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
178             EnableMenuItem(hMainMenu, ID_DELETE, MF_ENABLED);
179             EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), ID_DELETE, MF_ENABLED);
180         }
181 
182         Flags = Info->pCurrentService->ServiceStatusProcess.dwControlsAccepted;
183         State = Info->pCurrentService->ServiceStatusProcess.dwCurrentState;
184 
185         lpServiceConfig = GetServiceConfig(Info->pCurrentService->lpServiceName);
186 
187         if (lpServiceConfig && lpServiceConfig->dwStartType != SERVICE_DISABLED)
188         {
189             if (State == SERVICE_STOPPED)
190             {
191                 EnableMenuItem(hMainMenu, ID_START, MF_ENABLED);
192                 EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), ID_START, MF_ENABLED);
193                 SendMessage(Info->hTool, TB_SETSTATE, ID_START,
194                        (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
195             }
196 
197             if ( (Flags & SERVICE_ACCEPT_STOP) && (State == SERVICE_RUNNING) )
198             {
199                 EnableMenuItem(hMainMenu, ID_RESTART, MF_ENABLED);
200                 EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), ID_RESTART, MF_ENABLED);
201                 SendMessage(Info->hTool, TB_SETSTATE, ID_RESTART,
202                        (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
203             }
204         }
205 
206         if(lpServiceConfig)
207             HeapFree(GetProcessHeap(), 0, lpServiceConfig);
208 
209         if ( (Flags & SERVICE_ACCEPT_STOP) && (State == SERVICE_RUNNING) )
210         {
211             EnableMenuItem(hMainMenu, ID_STOP, MF_ENABLED);
212             EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), ID_STOP, MF_ENABLED);
213             SendMessage(Info->hTool, TB_SETSTATE, ID_STOP,
214                    (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
215         }
216 
217         if ( (Flags & SERVICE_ACCEPT_PAUSE_CONTINUE) && (State == SERVICE_RUNNING) )
218         {
219             EnableMenuItem(hMainMenu, ID_PAUSE, MF_ENABLED);
220             EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), ID_PAUSE, MF_ENABLED);
221             SendMessage(Info->hTool, TB_SETSTATE, ID_PAUSE,
222                    (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
223         }
224     }
225     else
226     {
227         /* disable tools which rely on a selected service */
228         EnableMenuItem(hMainMenu, ID_PROP, MF_GRAYED);
229         EnableMenuItem(hMainMenu, ID_DELETE, MF_GRAYED);
230         EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), ID_PROP, MF_GRAYED);
231         EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0), ID_DELETE, MF_GRAYED);
232         SendMessage(Info->hTool, TB_SETSTATE, ID_PROP,
233                    (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
234         SendMessage(Info->hTool, TB_SETSTATE, ID_DELETE,
235                    (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
236     }
237 
238 }
239 
240 
241 static INT CALLBACK
242 CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
243 {
244     PMAIN_WND_INFO Info = (PMAIN_WND_INFO)lParamSort;
245     WCHAR Item1[256], Item2[256];
246 
247     ListView_GetItemText(Info->hListView, lParam1, Info->SortSelection, Item1, sizeof(Item1) / sizeof(WCHAR));
248     ListView_GetItemText(Info->hListView, lParam2, Info->SortSelection, Item2, sizeof(Item2) / sizeof(WCHAR));
249 
250     return wcscmp(Item1, Item2) * Info->SortDirection;
251 }
252 
253 
254 static BOOL
255 pCreateToolbar(PMAIN_WND_INFO Info)
256 {
257     INT numButtons = sizeof(Buttons) / sizeof(Buttons[0]);
258 
259     Info->hTool = CreateWindowEx(0,
260                                  TOOLBARCLASSNAME,
261                                  NULL,
262                                  WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
263                                  0, 0, 0, 0,
264                                  Info->hMainWnd,
265                                  0,
266                                  hInstance,
267                                  NULL);
268     if(Info->hTool != NULL)
269     {
270         HIMAGELIST hImageList;
271 
272         SendMessage(Info->hTool,
273                     TB_SETEXTENDEDSTYLE,
274                     0,
275                     TBSTYLE_EX_HIDECLIPPEDBUTTONS);
276 
277         SendMessage(Info->hTool,
278                     TB_BUTTONSTRUCTSIZE,
279                     sizeof(Buttons[0]),
280                     0);
281 
282         hImageList = InitImageList(IDB_PROP,
283                                    IDB_RESTART,
284                                    GetSystemMetrics(SM_CXSMICON),
285                                    GetSystemMetrics(SM_CXSMICON),
286                                    IMAGE_BITMAP);
287         if (hImageList == NULL)
288             return FALSE;
289 
290         ImageList_Destroy((HIMAGELIST)SendMessage(Info->hTool,
291                                                   TB_SETIMAGELIST,
292                                                   0,
293                                                   (LPARAM)hImageList));
294 
295         SendMessage(Info->hTool,
296                     TB_ADDBUTTONS,
297                     numButtons,
298                     (LPARAM)Buttons);
299 
300         return TRUE;
301     }
302 
303     return FALSE;
304 }
305 
306 static BOOL
307 CreateStatusBar(PMAIN_WND_INFO Info)
308 {
309     INT StatWidths[] = {130, -1}; /* widths of status bar */
310 
311     Info->hStatus = CreateWindowEx(0,
312                                    STATUSCLASSNAME,
313                                    NULL,
314                                    WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
315                                    0, 0, 0, 0,
316                                    Info->hMainWnd,
317                                    (HMENU)IDC_STATUSBAR,
318                                    hInstance,
319                                    NULL);
320     if(Info->hStatus == NULL)
321         return FALSE;
322 
323     SendMessage(Info->hStatus,
324                 SB_SETPARTS,
325                 sizeof(StatWidths) / sizeof(INT),
326                 (LPARAM)StatWidths);
327 
328     return TRUE;
329 }
330 
331 
332 static BOOL
333 InitMainWnd(PMAIN_WND_INFO Info)
334 {
335     if (!pCreateToolbar(Info))
336     {
337         DisplayString(L"error creating toolbar");
338         return FALSE;
339     }
340 
341     if (!CreateListView(Info))
342     {
343         DisplayString(L"error creating list view");
344         return FALSE;
345     }
346 
347     if (!CreateStatusBar(Info))
348         DisplayString(L"error creating status bar");
349 
350     /* Create Popup Menu */
351     Info->hShortcutMenu = LoadMenu(hInstance,
352                                    MAKEINTRESOURCE(IDR_POPUP));
353 
354     Info->bIsUserAnAdmin = TRUE;// IsUserAnAdmin();
355     if (Info->bIsUserAnAdmin)
356     {
357         HMENU hMainMenu = GetMenu(Info->hMainWnd);
358 
359         SendMessage(Info->hTool,
360                     TB_SETSTATE,
361                     ID_CREATE,
362                     (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
363         if (hMainMenu)
364         {
365             EnableMenuItem(hMainMenu,
366                            ID_CREATE,
367                            MF_ENABLED);
368         }
369         EnableMenuItem(GetSubMenu(Info->hShortcutMenu, 0),
370                        ID_CREATE,
371                        MF_ENABLED);
372     }
373 
374     return TRUE;
375 }
376 
377 
378 static VOID
379 MainWndCommand(PMAIN_WND_INFO Info,
380                WORD CmdId,
381                HWND hControl)
382 {
383     UNREFERENCED_PARAMETER(hControl);
384 
385     switch (CmdId)
386     {
387         case ID_PROP:
388         {
389             if (Info->SelectedItem != NO_ITEM_SELECTED)
390             {
391                 Info->bDlgOpen = TRUE;
392                 OpenPropSheet(Info);
393                 Info->bDlgOpen = FALSE;
394                 SetMenuAndButtonStates(Info);
395             }
396         }
397         break;
398 
399         case ID_REFRESH:
400         {
401             RefreshServiceList(Info);
402             Info->SelectedItem = NO_ITEM_SELECTED;
403 
404             /* disable menus and buttons */
405             SetMenuAndButtonStates(Info);
406 
407             /* clear the service in the status bar */
408             SendMessage(Info->hStatus,
409                         SB_SETTEXT,
410                         1,
411                         L'\0');
412         }
413         break;
414 
415         case ID_EXPORT:
416         {
417             ExportFile(Info);
418             SetFocus(Info->hListView);
419         }
420         break;
421 
422         case ID_CREATE:
423         {
424             INT ret;
425 
426             ret = DialogBoxParam(hInstance,
427                                  MAKEINTRESOURCE(IDD_DLG_CREATE),
428                                  Info->hMainWnd,
429                                  CreateDialogProc,
430                                  (LPARAM)Info);
431             if (ret == IDOK)
432                 RefreshServiceList(Info);
433 
434             SetFocus(Info->hListView);
435         }
436         break;
437 
438         case ID_DELETE:
439         {
440             if (Info->pCurrentService->ServiceStatusProcess.dwCurrentState != SERVICE_RUNNING)
441             {
442                 DialogBoxParam(hInstance,
443                                MAKEINTRESOURCE(IDD_DLG_DELETE),
444                                Info->hMainWnd,
445                                DeleteDialogProc,
446                                (LPARAM)Info);
447             }
448             else
449             {
450                 WCHAR Buf[60];
451                 LoadString(hInstance,
452                            IDS_DELETE_STOP,
453                            Buf,
454                            sizeof(Buf) / sizeof(WCHAR));
455                 DisplayString(Buf);
456             }
457 
458             SetFocus(Info->hListView);
459 
460         }
461         break;
462 
463         case ID_START:
464         {
465             RunActionWithProgress(Info->hMainWnd,
466                                   Info->pCurrentService->lpServiceName,
467                                   Info->pCurrentService->lpDisplayName,
468                                   ACTION_START,
469                                   NULL); //FIXME: Add start params
470 
471             UpdateServiceStatus(Info->pCurrentService);
472             ChangeListViewText(Info, Info->pCurrentService, LVSTATUS);
473             SetMenuAndButtonStates(Info);
474             SetFocus(Info->hListView);
475 
476         }
477         break;
478 
479         case ID_STOP:
480             RunActionWithProgress(Info->hMainWnd,
481                                   Info->pCurrentService->lpServiceName,
482                                   Info->pCurrentService->lpDisplayName,
483                                   ACTION_STOP,
484                                   NULL);
485 
486             UpdateServiceStatus(Info->pCurrentService);
487             ChangeListViewText(Info, Info->pCurrentService, LVSTATUS);
488             SetMenuAndButtonStates(Info);
489             SetFocus(Info->hListView);
490 
491         break;
492 
493         case ID_PAUSE:
494             RunActionWithProgress(Info->hMainWnd,
495                                   Info->pCurrentService->lpServiceName,
496                                   Info->pCurrentService->lpDisplayName,
497                                   ACTION_PAUSE,
498                                   NULL);
499 
500             UpdateServiceStatus(Info->pCurrentService);
501             ChangeListViewText(Info, Info->pCurrentService, LVSTATUS);
502             SetMenuAndButtonStates(Info);
503             SetFocus(Info->hListView);
504         break;
505 
506         case ID_RESUME:
507             RunActionWithProgress(Info->hMainWnd,
508                                   Info->pCurrentService->lpServiceName,
509                                   Info->pCurrentService->lpDisplayName,
510                                   ACTION_RESUME,
511                                   NULL);
512 
513             UpdateServiceStatus(Info->pCurrentService);
514             ChangeListViewText(Info, Info->pCurrentService, LVSTATUS);
515             SetMenuAndButtonStates(Info);
516             SetFocus(Info->hListView);
517         break;
518 
519         case ID_RESTART:
520             RunActionWithProgress(Info->hMainWnd,
521                                   Info->pCurrentService->lpServiceName,
522                                   Info->pCurrentService->lpDisplayName,
523                                   ACTION_RESTART,
524                                   NULL);
525 
526             UpdateServiceStatus(Info->pCurrentService);
527             ChangeListViewText(Info, Info->pCurrentService, LVSTATUS);
528             SetMenuAndButtonStates(Info);
529             SetFocus(Info->hListView);
530         break;
531 
532         case ID_HELP:
533             MessageBoxW(NULL,
534                         L"Help is not yet implemented\n",
535                         L"Note!",
536                         MB_OK | MB_ICONINFORMATION);
537             SetFocus(Info->hListView);
538         break;
539 
540         case ID_EXIT:
541             PostMessage(Info->hMainWnd,
542                         WM_CLOSE,
543                         0,
544                         0);
545         break;
546 
547         case ID_VIEW_LARGE:
548             SetListViewStyle(Info->hListView, LVS_ICON);
549             ListView_Arrange(Info->hListView, LVA_DEFAULT);
550 
551             CheckMenuRadioItem(GetMenu(Info->hMainWnd),
552                                ID_VIEW_LARGE,
553                                ID_VIEW_DETAILS,
554                                ID_VIEW_LARGE,
555                                MF_BYCOMMAND);
556         break;
557 
558         case ID_VIEW_SMALL:
559             SetListViewStyle(Info->hListView, LVS_SMALLICON);
560             ListView_Arrange(Info->hListView, LVA_DEFAULT);
561 
562             CheckMenuRadioItem(GetMenu(Info->hMainWnd),
563                                ID_VIEW_LARGE,
564                                ID_VIEW_DETAILS,
565                                ID_VIEW_SMALL,
566                                MF_BYCOMMAND);
567         break;
568 
569         case ID_VIEW_LIST:
570             SetListViewStyle(Info->hListView,
571                              LVS_LIST);
572             CheckMenuRadioItem(GetMenu(Info->hMainWnd),
573                                ID_VIEW_LARGE,
574                                ID_VIEW_DETAILS,
575                                ID_VIEW_LIST,
576                                MF_BYCOMMAND);
577         break;
578 
579         case ID_VIEW_DETAILS:
580             SetListViewStyle(Info->hListView,
581                              LVS_REPORT);
582             CheckMenuRadioItem(GetMenu(Info->hMainWnd),
583                                ID_VIEW_LARGE,
584                                ID_VIEW_DETAILS,
585                                ID_VIEW_DETAILS,
586                                MF_BYCOMMAND);
587         break;
588 
589         case ID_VIEW_CUST:
590         break;
591 
592         case ID_ABOUT:
593             DialogBox(hInstance,
594                       MAKEINTRESOURCE(IDD_ABOUTBOX),
595                       Info->hMainWnd,
596                       AboutDialogProc);
597             SetFocus(Info->hListView);
598         break;
599 
600     }
601 }
602 
603 
604 static VOID CALLBACK
605 MainWndResize(PMAIN_WND_INFO Info,
606               WORD cx,
607               WORD cy)
608 {
609     RECT rcClient, rcTool, rcStatus;
610     int lvHeight, iToolHeight, iStatusHeight;
611 
612     /* Size toolbar and get height */
613     SendMessage(Info->hTool, TB_AUTOSIZE, 0, 0);
614     GetWindowRect(Info->hTool, &rcTool);
615     iToolHeight = rcTool.bottom - rcTool.top;
616 
617     /* Size status bar and get height */
618     SendMessage(Info->hStatus, WM_SIZE, 0, 0);
619     GetWindowRect(Info->hStatus, &rcStatus);
620     iStatusHeight = rcStatus.bottom - rcStatus.top;
621 
622     /* Calculate remaining height and size list view */
623     GetClientRect(Info->hMainWnd, &rcClient);
624     lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
625     SetWindowPos(Info->hListView,
626                  NULL,
627                  0,
628                  iToolHeight,
629                  rcClient.right,
630                  lvHeight,
631                  SWP_NOZORDER);
632 }
633 
634 
635 static LRESULT CALLBACK
636 MainWndProc(HWND hwnd,
637             UINT msg,
638             WPARAM wParam,
639             LPARAM lParam)
640 {
641     PMAIN_WND_INFO Info;
642     LRESULT Ret = 0;
643 
644     /* Get the window context */
645     Info = (PMAIN_WND_INFO)GetWindowLongPtr(hwnd,
646                                             GWLP_USERDATA);
647     if (Info == NULL && msg != WM_CREATE)
648     {
649         goto HandleDefaultMessage;
650     }
651 
652     switch(msg)
653     {
654         case WM_CREATE:
655         {
656             Info = (PMAIN_WND_INFO)(((LPCREATESTRUCT)lParam)->lpCreateParams);
657 
658             /* Initialize the main window context */
659             Info->hMainWnd = hwnd;
660             Info->SelectedItem = NO_ITEM_SELECTED;
661 
662             SetWindowLongPtr(hwnd,
663                              GWLP_USERDATA,
664                              (LONG_PTR)Info);
665 
666             if (!InitMainWnd(Info))
667                 return -1;
668 
669             /* Fill the list-view before showing the main window */
670             RefreshServiceList(Info);
671 
672             /* Show the window */
673             ShowWindow(hwnd,
674                        Info->nCmdShow);
675 
676             SetFocus(Info->hListView);
677         }
678         break;
679 
680         case WM_SIZE:
681         {
682             MainWndResize(Info,
683                           LOWORD(lParam),
684                           HIWORD(lParam));
685         }
686         break;
687 
688         case WM_NOTIFY:
689         {
690             LPNMHDR pnmhdr = (LPNMHDR)lParam;
691 
692             switch (pnmhdr->code)
693             {
694                 case NM_DBLCLK:
695                 {
696                     POINT pt;
697                     RECT rect;
698 
699                     GetCursorPos(&pt);
700                     GetWindowRect(Info->hListView, &rect);
701 
702                     if (PtInRect(&rect, pt))
703                     {
704                         SendMessage(hwnd,
705                                     WM_COMMAND,
706                                     //ID_PROP,
707                                     MAKEWPARAM((WORD)ID_PROP, (WORD)0),
708                                     0);
709                     }
710 
711                     //OpenPropSheet(Info);
712                 }
713                 break;
714 
715                 case NM_RETURN:
716                 {
717                     SendMessage(hwnd,
718                                 WM_COMMAND,
719                                 //ID_PROP,
720                                 MAKEWPARAM((WORD)ID_PROP, (WORD)0),
721                                 0);
722                 }
723                 break;
724 
725                 case LVN_COLUMNCLICK:
726                 {
727                     LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
728                     HDITEM       hdi;
729 
730                     /* get pending sort direction for clicked column */
731                     hdi.mask = HDI_LPARAM;
732                     (void)Header_GetItem(Info->hHeader, pnmv->iSubItem, &hdi);
733 
734                     /* get new sort parameters */
735                     Info->SortSelection = pnmv->iSubItem;
736                     Info->SortDirection = hdi.lParam;
737 
738                     /* set new sort direction and save */
739                     hdi.lParam = (hdi.lParam == ORD_ASCENDING) ?
740                                  ORD_DESCENDING : ORD_ASCENDING;
741 
742                     (void)Header_SetItem(Info->hHeader, pnmv->iSubItem, &hdi);
743 
744                     (void)ListView_SortItemsEx(Info->hListView,
745                                                CompareFunc,
746                                                (LPARAM)Info);
747                 }
748                 break;
749                 case LVN_ITEMCHANGED:
750                 {
751                     LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
752 
753                     if (pnmv->uNewState != 0)
754                     {
755                         ListViewSelectionChanged(Info, pnmv);
756                         SetMenuAndButtonStates(Info);
757                     }
758                 }
759                 break;
760 
761                 case TTN_GETDISPINFO:
762                 {
763                     LPTOOLTIPTEXT lpttt;
764                     UINT idButton;
765 
766                     lpttt = (LPTOOLTIPTEXT)lParam;
767 
768                     /* Specify the resource identifier of the descriptive
769                      * text for the given button. */
770                     idButton = (UINT)lpttt->hdr.idFrom;
771                     switch (idButton)
772                     {
773                         case ID_PROP:
774                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PROP);
775                         break;
776 
777                         case ID_REFRESH:
778                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_REFRESH);
779                         break;
780 
781                         case ID_EXPORT:
782                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EXPORT);
783                         break;
784 
785                         case ID_CREATE:
786                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_CREATE);
787                         break;
788 
789                         case ID_DELETE:
790                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_DELETE);
791                         break;
792 
793                         case ID_START:
794                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_START);
795                         break;
796 
797                         case ID_STOP:
798                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_STOP);
799                         break;
800 
801                         case ID_PAUSE:
802                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PAUSE);
803                         break;
804 
805                         case ID_RESTART:
806                             lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_RESTART);
807                         break;
808                     }
809                 }
810                 break;
811             }
812         }
813         break;
814 
815         case WM_CONTEXTMENU:
816             {
817                 POINT pt;
818                 RECT lvRect;
819 
820                 INT xPos = GET_X_LPARAM(lParam);
821                 INT yPos = GET_Y_LPARAM(lParam);
822 
823                 GetCursorPos(&pt);
824 
825                 /* display popup when cursor is in the list view */
826                 GetWindowRect(Info->hListView, &lvRect);
827                 if (PtInRect(&lvRect, pt))
828                 {
829                     TrackPopupMenuEx(GetSubMenu(Info->hShortcutMenu, 0),
830                                      TPM_RIGHTBUTTON,
831                                      xPos,
832                                      yPos,
833                                      Info->hMainWnd,
834                                      NULL);
835                 }
836             }
837         break;
838 
839         case WM_COMMAND:
840         {
841             MainWndCommand(Info,
842                            LOWORD(wParam),
843                            (HWND)lParam);
844             goto HandleDefaultMessage;
845         }
846 
847         case WM_MENUSELECT:
848         {
849             if (Info->hStatus != NULL)
850             {
851                 if (!MainWndMenuHint(Info,
852                                      LOWORD(wParam),
853                                      MainMenuHintTable,
854                                      sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
855                                      IDS_HINT_BLANK))
856                 {
857                     MainWndMenuHint(Info,
858                                     LOWORD(wParam),
859                                     SystemMenuHintTable,
860                                     sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
861                                     IDS_HINT_BLANK);
862                 }
863             }
864         }
865         break;
866 
867         case WM_ENTERMENULOOP:
868         {
869             Info->bInMenuLoop = TRUE;
870             UpdateMainStatusBar(Info);
871             break;
872         }
873 
874         case WM_EXITMENULOOP:
875         {
876             Info->bInMenuLoop = FALSE;
877             UpdateMainStatusBar(Info);
878             break;
879         }
880 
881         case WM_CLOSE:
882         {
883             FreeServiceList(Info);
884             DestroyMenu(Info->hShortcutMenu);
885             DestroyWindow(hwnd);
886         }
887         break;
888 
889         case WM_DESTROY:
890         {
891             HeapFree(ProcessHeap,
892                      0,
893                      Info);
894             SetWindowLongPtr(hwnd,
895                              GWLP_USERDATA,
896                              0);
897 
898             PostQuitMessage(0);
899         }
900         break;
901 
902         default:
903         {
904 HandleDefaultMessage:
905 
906             Ret = DefWindowProc(hwnd,
907                                 msg,
908                                 wParam,
909                                 lParam);
910         }
911         break;
912     }
913 
914     return Ret;
915 }
916 
917 
918 
919 HWND
920 CreateMainWindow(LPCTSTR lpCaption,
921                  int nCmdShow)
922 {
923     PMAIN_WND_INFO Info;
924     HWND hMainWnd = NULL;
925 
926     Info = (MAIN_WND_INFO*) HeapAlloc(ProcessHeap,
927                      HEAP_ZERO_MEMORY,
928                      sizeof(MAIN_WND_INFO));
929 
930     if (Info != NULL)
931     {
932         Info->nCmdShow = nCmdShow;
933 
934         hMainWnd = CreateWindowEx(WS_EX_WINDOWEDGE,
935                                   szMainWndClass,
936                                   lpCaption,
937                                   WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
938                                   CW_USEDEFAULT,
939                                   CW_USEDEFAULT,
940                                   680,
941                                   450,
942                                   NULL,
943                                   NULL,
944                                   hInstance,
945                                   Info);
946         if (hMainWnd == NULL)
947         {
948             //int ret;
949             //ret = GetLastError();
950             GetError();
951             HeapFree(ProcessHeap,
952                      0,
953                      Info);
954         }
955     }
956 
957     return hMainWnd;
958 }
959 
960 BOOL
961 InitMainWindowImpl(VOID)
962 {
963     WNDCLASSEX wc = {0};
964 
965     wc.cbSize = sizeof(WNDCLASSEX);
966     wc.lpfnWndProc = MainWndProc;
967     wc.hInstance = hInstance;
968     wc.hIcon = LoadIcon(hInstance,
969                         MAKEINTRESOURCE(IDI_SM_ICON));
970     wc.hCursor = LoadCursor(NULL,
971                             IDC_ARROW);
972     wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
973     wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
974     wc.lpszClassName = szMainWndClass;
975     wc.hIconSm = (HICON)LoadImage(hInstance,
976                                   MAKEINTRESOURCE(IDI_SM_ICON),
977                                   IMAGE_ICON,
978                                   16,
979                                   16,
980                                   LR_SHARED);
981 
982     return RegisterClassEx(&wc) != (ATOM)0;
983 }
984 
985 
986 VOID
987 UninitMainWindowImpl(VOID)
988 {
989     UnregisterClass(szMainWndClass,
990                     hInstance);
991 }
992