The real, definitive, Visual C++ support branch. Accept no substitutes
[reactos.git] / base / applications / mscutils / devmgmt / mainwnd.c
1 /*
2 * PROJECT: ReactOS Device Managment
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/devmgmt/mainwnd.c
5 * PURPOSE: Main window message handler
6 * COPYRIGHT: Copyright 2006 Ged Murphy <gedmurphy@gmail.com>
7 *
8 */
9
10 #include "precomp.h"
11
12 static BOOL pCreateToolbar(PMAIN_WND_INFO Info);
13
14 static const TCHAR szMainWndClass[] = TEXT("DevMgmtWndClass");
15
16
17 /* Toolbar buttons */
18 TBBUTTON Buttons [] =
19 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
20 {TBICON_PROP, IDC_PROP, TBSTATE_INDETERMINATE, BTNS_BUTTON, {0}, 0, 0}, /* properties */
21 {TBICON_REFRESH, IDC_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0}, /* refresh */
22
23 /* Note: First item for a seperator is its width in pixels */
24 {15, 0, TBSTATE_ENABLED, BTNS_SEP, {0}, 0, 0}, /* separator */
25
26 {TBICON_HELP, IDC_PROGHELP,TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, /* help */
27 {TBICON_EXIT, IDC_EXIT, TBSTATE_ENABLED, BTNS_BUTTON, {0}, 0, 0 }, /* exit */
28
29 };
30
31
32 /* menu hints */
33 static const MENU_HINT MainMenuHintTable[] = {
34 /* File Menu */
35 {IDC_EXIT, IDS_HINT_EXIT},
36
37 /* Action Menu */
38 {IDC_REFRESH, IDS_HINT_REFRESH},
39 {IDC_PROP, IDS_HINT_PROP},
40
41 /* Help Menu */
42 {IDC_PROGHELP, IDS_HINT_HELP},
43 {IDC_ABOUT, IDS_HINT_ABOUT}
44 };
45
46 /* system menu hints */
47 static const MENU_HINT SystemMenuHintTable[] = {
48 {SC_RESTORE, IDS_HINT_SYS_RESTORE},
49 {SC_MOVE, IDS_HINT_SYS_MOVE},
50 {SC_SIZE, IDS_HINT_SYS_SIZE},
51 {SC_MINIMIZE, IDS_HINT_SYS_MINIMIZE},
52 {SC_MAXIMIZE, IDS_HINT_SYS_MAXIMIZE},
53 {SC_CLOSE, IDS_HINT_SYS_CLOSE},
54 };
55
56
57 static BOOL
58 MainWndMenuHint(PMAIN_WND_INFO Info,
59 WORD CmdId,
60 const MENU_HINT *HintArray,
61 DWORD HintsCount,
62 UINT DefHintId)
63 {
64 BOOL Found = FALSE;
65 const MENU_HINT *LastHint;
66 UINT HintId = DefHintId;
67
68 LastHint = HintArray + HintsCount;
69 while (HintArray != LastHint)
70 {
71 if (HintArray->CmdId == CmdId)
72 {
73 HintId = HintArray->HintId;
74 Found = TRUE;
75 break;
76 }
77 HintArray++;
78 }
79
80 StatusBarLoadString(Info->hStatus,
81 SB_SIMPLEID,
82 hInstance,
83 HintId);
84
85 return Found;
86 }
87
88
89 static VOID
90 UpdateMainStatusBar(PMAIN_WND_INFO Info)
91 {
92 if (Info->hStatus != NULL)
93 {
94 SendMessage(Info->hStatus,
95 SB_SIMPLE,
96 (WPARAM)Info->InMenuLoop,
97 0);
98 }
99 }
100
101
102 static BOOL
103 pCreateToolbar(PMAIN_WND_INFO Info)
104 {
105 INT NumButtons = sizeof(Buttons) / sizeof(Buttons[0]);
106
107 Info->hTool = CreateWindowEx(0,
108 TOOLBARCLASSNAME,
109 NULL,
110 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS,
111 0, 0, 0, 0,
112 Info->hMainWnd,
113 (HMENU)IDC_TOOLBAR,
114 hInstance,
115 NULL);
116 if(Info->hTool != NULL)
117 {
118 HIMAGELIST hImageList;
119
120 SendMessage(Info->hTool,
121 TB_SETEXTENDEDSTYLE,
122 0,
123 TBSTYLE_EX_HIDECLIPPEDBUTTONS);
124
125 SendMessage(Info->hTool,
126 TB_BUTTONSTRUCTSIZE,
127 sizeof(Buttons[0]),
128 0);
129
130 hImageList = InitImageList(IDB_PROP,
131 IDB_EXIT,
132 16,
133 16);
134 if (hImageList == NULL)
135 return FALSE;
136
137 ImageList_Destroy((HIMAGELIST)SendMessage(Info->hTool,
138 TB_SETIMAGELIST,
139 0,
140 (LPARAM)hImageList));
141
142 SendMessage(Info->hTool,
143 TB_ADDBUTTONS,
144 NumButtons,
145 (LPARAM)Buttons);
146
147 return TRUE;
148 }
149
150 return FALSE;
151 }
152
153
154 static BOOL
155 CreateTreeView(PMAIN_WND_INFO Info)
156 {
157 Info->hTreeView = CreateWindowEx(WS_EX_CLIENTEDGE,
158 WC_TREEVIEW,
159 NULL,
160 WS_CHILD | WS_VISIBLE | WS_BORDER | TVS_HASLINES |
161 TVS_HASBUTTONS | TVS_SHOWSELALWAYS | TVS_LINESATROOT,
162 0, 0, 0, 0,
163 Info->hMainWnd,
164 (HMENU)IDC_TREEVIEW,
165 hInstance,
166 NULL);
167 if (Info->hTreeView == NULL)
168 {
169 DisplayString(_T("Could not create TreeView."));
170 return FALSE;
171 }
172
173 return TRUE;
174 }
175
176 static BOOL
177 CreateStatusBar(PMAIN_WND_INFO Info)
178 {
179 INT StatWidths[] = {110, -1}; /* widths of status bar */
180
181 Info->hStatus = CreateWindowEx(0,
182 STATUSCLASSNAME,
183 NULL,
184 WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP,
185 0, 0, 0, 0,
186 Info->hMainWnd,
187 (HMENU)IDC_STATUSBAR,
188 hInstance,
189 NULL);
190 if(Info->hStatus == NULL)
191 return FALSE;
192
193
194 SendMessage(Info->hStatus,
195 SB_SETPARTS,
196 sizeof(StatWidths) / sizeof(INT),
197 (LPARAM)StatWidths);
198
199 return TRUE;
200 }
201
202
203 static DWORD WINAPI
204 DeviceEnumThread(LPVOID lpParameter)
205 {
206 HTREEITEM hRoot;
207 HWND *hTreeView;
208
209 hTreeView = (HWND *)lpParameter;
210
211 if (*hTreeView)
212 FreeDeviceStrings(*hTreeView);
213
214 hRoot = InitTreeView(*hTreeView);
215 if (hRoot)
216 {
217 ListDevicesByType(*hTreeView, hRoot);
218 return 0;
219 }
220
221 return -1;
222 }
223
224
225 static BOOL
226 InitMainWnd(PMAIN_WND_INFO Info)
227 {
228 HANDLE DevEnumThread;
229 HMENU hMenu;
230
231 if (!pCreateToolbar(Info))
232 DisplayString(_T("error creating toolbar"));
233
234 if (!CreateTreeView(Info))
235 {
236 DisplayString(_T("error creating list view"));
237 return FALSE;
238 }
239
240 if (!CreateStatusBar(Info))
241 DisplayString(_T("error creating status bar"));
242
243 /* make 'properties' bold */
244 hMenu = GetMenu(Info->hMainWnd);
245 hMenu = GetSubMenu(hMenu, 1);
246 SetMenuDefaultItem(hMenu, IDC_PROP, FALSE);
247
248 /* Create Popup Menu */
249 Info->hShortcutMenu = LoadMenu(hInstance,
250 MAKEINTRESOURCE(IDR_POPUP));
251 Info->hShortcutMenu = GetSubMenu(Info->hShortcutMenu,
252 0);
253 SetMenuDefaultItem(Info->hShortcutMenu, IDC_PROP, FALSE);
254
255 /* create seperate thread to emum devices */
256 DevEnumThread = CreateThread(NULL,
257 0,
258 DeviceEnumThread,
259 &Info->hTreeView,
260 0,
261 NULL);
262 if (!DevEnumThread)
263 {
264 DisplayString(_T("Failed to enumerate devices"));
265 return FALSE;
266 }
267
268 CloseHandle(DevEnumThread);
269 return TRUE;
270 }
271
272
273 static VOID
274 OnContext(PMAIN_WND_INFO Info,
275 LPARAM lParam)
276 {
277 HTREEITEM hSelected;
278 POINT pt;
279 RECT rc;
280
281 INT xPos = GET_X_LPARAM(lParam);
282 INT yPos = GET_Y_LPARAM(lParam);
283
284 hSelected = TreeView_GetSelection(Info->hTreeView);
285
286 if (TreeView_GetItemRect(Info->hTreeView,
287 hSelected,
288 &rc,
289 TRUE))
290 {
291 if (GetCursorPos(&pt) &&
292 ScreenToClient(Info->hTreeView, &pt) &&
293 PtInRect(&rc, pt))
294 {
295 TrackPopupMenuEx(Info->hShortcutMenu,
296 TPM_RIGHTBUTTON,
297 xPos,
298 yPos,
299 Info->hMainWnd,
300 NULL);
301 }
302 }
303 }
304
305
306 static VOID
307 OnNotify(PMAIN_WND_INFO Info,
308 LPARAM lParam)
309 {
310 LPNMHDR pnmhdr = (LPNMHDR)lParam;
311
312 switch (pnmhdr->code)
313 {
314 case TVN_SELCHANGED:
315 {
316 LPNM_TREEVIEW pnmtv = (LPNM_TREEVIEW)lParam;
317
318 if (!TreeView_GetChild(Info->hTreeView,
319 pnmtv->itemNew.hItem))
320 {
321 SendMessage(Info->hTool,
322 TB_SETSTATE,
323 IDC_PROP,
324 (LPARAM)MAKELONG(TBSTATE_ENABLED, 0));
325
326 EnableMenuItem(GetMenu(Info->hMainWnd), IDC_PROP, MF_ENABLED);
327 EnableMenuItem(Info->hShortcutMenu, IDC_PROP, MF_ENABLED);
328 }
329 else
330 {
331 SendMessage(Info->hTool,
332 TB_SETSTATE,
333 IDC_PROP,
334 (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
335
336 EnableMenuItem(GetMenu(Info->hMainWnd), IDC_PROP, MF_GRAYED);
337 EnableMenuItem(Info->hShortcutMenu, IDC_PROP, MF_GRAYED);
338 }
339 }
340 break;
341
342 case NM_DBLCLK:
343 {
344 HTREEITEM hSelected = TreeView_GetSelection(Info->hTreeView);
345
346 if (!TreeView_GetChild(Info->hTreeView,
347 hSelected))
348 {
349 OpenPropSheet(Info->hTreeView,
350 hSelected);
351 }
352 }
353 break;
354
355 case NM_RCLICK:
356 {
357 TV_HITTESTINFO HitTest;
358
359 if (GetCursorPos(&HitTest.pt) &&
360 ScreenToClient(Info->hTreeView, &HitTest.pt))
361 {
362 if (TreeView_HitTest(Info->hTreeView, &HitTest))
363 (void)TreeView_SelectItem(Info->hTreeView, HitTest.hItem);
364 }
365 }
366 break;
367
368 case TTN_GETDISPINFO:
369 {
370 LPTOOLTIPTEXT lpttt;
371 UINT idButton;
372
373 lpttt = (LPTOOLTIPTEXT)lParam;
374
375 idButton = (UINT)lpttt->hdr.idFrom;
376 switch (idButton)
377 {
378 case IDC_PROP:
379 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PROP);
380 break;
381
382 case IDC_REFRESH:
383 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_REFRESH);
384 break;
385
386 case IDC_PROGHELP:
387 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_HELP);
388 break;
389
390 case IDC_EXIT:
391 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EXIT);
392 break;
393 }
394 }
395 break;
396 }
397 }
398
399
400 static VOID
401 MainWndCommand(PMAIN_WND_INFO Info,
402 WORD CmdId,
403 HWND hControl)
404 {
405 UNREFERENCED_PARAMETER(hControl);
406
407 switch (CmdId)
408 {
409 case IDC_PROP:
410 {
411 HTREEITEM hSelected = TreeView_GetSelection(Info->hTreeView);
412 OpenPropSheet(Info->hTreeView,
413 hSelected);
414 }
415 break;
416
417 case IDC_REFRESH:
418 {
419 HANDLE DevEnumThread;
420
421 SendMessage(Info->hTool,
422 TB_SETSTATE,
423 IDC_PROP,
424 (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
425
426 EnableMenuItem(GetMenu(Info->hMainWnd), IDC_PROP, MF_GRAYED);
427 EnableMenuItem(Info->hShortcutMenu, IDC_PROP, MF_GRAYED);
428
429 /* create seperate thread to emum devices */
430 DevEnumThread = CreateThread(NULL,
431 0,
432 DeviceEnumThread,
433 &Info->hTreeView,
434 0,
435 NULL);
436 if (!DevEnumThread)
437 {
438 DisplayString(_T("Failed to enumerate devices"));
439 break;
440 }
441
442 CloseHandle(DevEnumThread);
443 }
444 break;
445
446 case IDC_PROGHELP:
447 {
448 DisplayString(_T("Help is not yet implemented\n"));
449 SetFocus(Info->hTreeView);
450 }
451 break;
452
453 case IDC_EXIT:
454 {
455 PostMessage(Info->hMainWnd,
456 WM_CLOSE,
457 0,
458 0);
459 }
460 break;
461
462 case IDC_ABOUT:
463 {
464 DialogBox(hInstance,
465 MAKEINTRESOURCE(IDD_ABOUTBOX),
466 Info->hMainWnd,
467 (DLGPROC)AboutDialogProc);
468
469 SetFocus(Info->hTreeView);
470 }
471 break;
472
473 }
474 }
475
476
477 static VOID CALLBACK
478 MainWndResize(PMAIN_WND_INFO Info,
479 WORD cx,
480 WORD cy)
481 {
482 RECT rcClient, rcTool, rcStatus;
483 int lvHeight, iToolHeight, iStatusHeight;
484
485 /* Size toolbar and get height */
486 SendMessage(Info->hTool, TB_AUTOSIZE, 0, 0);
487 GetWindowRect(Info->hTool, &rcTool);
488 iToolHeight = rcTool.bottom - rcTool.top;
489
490 /* Size status bar and get height */
491 SendMessage(Info->hStatus, WM_SIZE, 0, 0);
492 GetWindowRect(Info->hStatus, &rcStatus);
493 iStatusHeight = rcStatus.bottom - rcStatus.top;
494
495 /* Calculate remaining height and size list view */
496 GetClientRect(Info->hMainWnd, &rcClient);
497 lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
498 SetWindowPos(Info->hTreeView,
499 NULL,
500 0,
501 iToolHeight,
502 rcClient.right,
503 lvHeight,
504 SWP_NOZORDER);
505 }
506
507
508 static LRESULT CALLBACK
509 MainWndProc(HWND hwnd,
510 UINT msg,
511 WPARAM wParam,
512 LPARAM lParam)
513 {
514 PMAIN_WND_INFO Info;
515 LRESULT Ret = 0;
516
517 /* Get the window context */
518 Info = (PMAIN_WND_INFO)GetWindowLongPtr(hwnd,
519 GWLP_USERDATA);
520 if (Info == NULL && msg != WM_CREATE)
521 {
522 goto HandleDefaultMessage;
523 }
524
525 switch(msg)
526 {
527 case WM_CREATE:
528 {
529 Info = (PMAIN_WND_INFO)(((LPCREATESTRUCT)lParam)->lpCreateParams);
530
531 /* Initialize the main window context */
532 Info->hMainWnd = hwnd;
533
534 SetWindowLongPtr(hwnd,
535 GWLP_USERDATA,
536 (LONG_PTR)Info);
537
538 if (!InitMainWnd(Info))
539 SendMessage(hwnd, WM_CLOSE, 0, 0);
540
541 /* Show the window */
542 ShowWindow(hwnd,
543 Info->nCmdShow);
544
545 }
546 break;
547
548 case WM_SIZE:
549 {
550 MainWndResize(Info,
551 LOWORD(lParam),
552 HIWORD(lParam));
553 }
554 break;
555
556 case WM_NOTIFY:
557 {
558 OnNotify(Info, lParam);
559 }
560 break;
561
562 case WM_CONTEXTMENU:
563 {
564 OnContext(Info, lParam);
565 }
566 break;
567
568 case WM_COMMAND:
569 {
570 MainWndCommand(Info,
571 LOWORD(wParam),
572 (HWND)lParam);
573 goto HandleDefaultMessage;
574 }
575
576 case WM_MENUSELECT:
577 {
578 if (Info->hStatus != NULL)
579 {
580 if (!MainWndMenuHint(Info,
581 LOWORD(wParam),
582 MainMenuHintTable,
583 sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
584 IDS_HINT_BLANK))
585 {
586 MainWndMenuHint(Info,
587 LOWORD(wParam),
588 SystemMenuHintTable,
589 sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
590 IDS_HINT_BLANK);
591 }
592 }
593 }
594 break;
595
596 case WM_ENTERMENULOOP:
597 {
598 Info->InMenuLoop = TRUE;
599 UpdateMainStatusBar(Info);
600 break;
601 }
602
603 case WM_EXITMENULOOP:
604 {
605 Info->InMenuLoop = FALSE;
606 UpdateMainStatusBar(Info);
607 break;
608 }
609
610 case WM_CLOSE:
611 {
612 FreeDeviceStrings(Info->hTreeView);
613 DestroyMenu(Info->hShortcutMenu);
614 DestroyWindow(hwnd);
615 }
616 break;
617
618 case WM_DESTROY:
619 {
620 HeapFree(ProcessHeap,
621 0,
622 Info);
623 SetWindowLongPtr(hwnd,
624 GWLP_USERDATA,
625 0);
626
627 /* Break the message queue loop */
628 PostQuitMessage(0);
629 }
630 break;
631
632 default:
633 {
634 HandleDefaultMessage:
635
636 Ret = DefWindowProc(hwnd,
637 msg,
638 wParam,
639 lParam);
640 }
641 break;
642 }
643 return Ret;
644 }
645
646
647
648 HWND
649 CreateMainWindow(LPCTSTR lpCaption,
650 int nCmdShow)
651 {
652 PMAIN_WND_INFO Info;
653 HWND hMainWnd = NULL;
654
655 Info = (PMAIN_WND_INFO)HeapAlloc(ProcessHeap,
656 HEAP_ZERO_MEMORY,
657 sizeof(MAIN_WND_INFO));
658
659 if (Info != NULL)
660 {
661 Info->nCmdShow = nCmdShow;
662
663 hMainWnd = CreateWindowEx(WS_EX_WINDOWEDGE,
664 szMainWndClass,
665 lpCaption,
666 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
667 CW_USEDEFAULT,
668 CW_USEDEFAULT,
669 600,
670 450,
671 NULL,
672 NULL,
673 hInstance,
674 Info);
675 if (hMainWnd == NULL)
676 {
677 GetError();
678 HeapFree(ProcessHeap,
679 0,
680 Info);
681 }
682 }
683
684 return hMainWnd;
685 }
686
687 BOOL
688 InitMainWindowImpl(VOID)
689 {
690 WNDCLASSEX wc = {0};
691
692 wc.cbSize = sizeof(WNDCLASSEX);
693 wc.lpfnWndProc = MainWndProc;
694 wc.hInstance = hInstance;
695 wc.hIcon = LoadIcon(hInstance,
696 MAKEINTRESOURCE(IDI_MAIN_ICON));
697 wc.hCursor = LoadCursor(NULL,
698 IDC_ARROW);
699 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
700 wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
701 wc.lpszClassName = szMainWndClass;
702 wc.hIconSm = (HICON)LoadImage(hInstance,
703 MAKEINTRESOURCE(IDI_MAIN_ICON),
704 IMAGE_ICON,
705 16,
706 16,
707 LR_SHARED);
708
709 return RegisterClassEx(&wc) != (ATOM)0;
710 }
711
712
713 VOID
714 UninitMainWindowImpl(VOID)
715 {
716 UnregisterClass(szMainWndClass,
717 hInstance);
718 }
719
720