If the user doubleclicked a treeview item, make sure the doubleclicked item has alrea...
[reactos.git] / reactos / 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 TV_HITTESTINFO HitTest;
346
347 if (!TreeView_GetChild(Info->hTreeView,
348 hSelected))
349 {
350 if (GetCursorPos(&HitTest.pt) &&
351 ScreenToClient(Info->hTreeView, &HitTest.pt))
352 {
353 if (TreeView_HitTest(Info->hTreeView, &HitTest))
354 {
355 if (HitTest.hItem == hSelected)
356 OpenPropSheet(Info->hTreeView,
357 hSelected);
358 }
359 }
360 }
361 }
362 break;
363
364 case NM_RCLICK:
365 {
366 TV_HITTESTINFO HitTest;
367
368 if (GetCursorPos(&HitTest.pt) &&
369 ScreenToClient(Info->hTreeView, &HitTest.pt))
370 {
371 if (TreeView_HitTest(Info->hTreeView, &HitTest))
372 (void)TreeView_SelectItem(Info->hTreeView, HitTest.hItem);
373 }
374 }
375 break;
376
377 case TTN_GETDISPINFO:
378 {
379 LPTOOLTIPTEXT lpttt;
380 UINT idButton;
381
382 lpttt = (LPTOOLTIPTEXT)lParam;
383
384 idButton = (UINT)lpttt->hdr.idFrom;
385 switch (idButton)
386 {
387 case IDC_PROP:
388 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_PROP);
389 break;
390
391 case IDC_REFRESH:
392 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_REFRESH);
393 break;
394
395 case IDC_PROGHELP:
396 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_HELP);
397 break;
398
399 case IDC_EXIT:
400 lpttt->lpszText = MAKEINTRESOURCE(IDS_TOOLTIP_EXIT);
401 break;
402 }
403 }
404 break;
405 }
406 }
407
408
409 static VOID
410 MainWndCommand(PMAIN_WND_INFO Info,
411 WORD CmdId,
412 HWND hControl)
413 {
414 UNREFERENCED_PARAMETER(hControl);
415
416 switch (CmdId)
417 {
418 case IDC_PROP:
419 {
420 HTREEITEM hSelected = TreeView_GetSelection(Info->hTreeView);
421 OpenPropSheet(Info->hTreeView,
422 hSelected);
423 }
424 break;
425
426 case IDC_REFRESH:
427 {
428 HANDLE DevEnumThread;
429
430 SendMessage(Info->hTool,
431 TB_SETSTATE,
432 IDC_PROP,
433 (LPARAM)MAKELONG(TBSTATE_INDETERMINATE, 0));
434
435 EnableMenuItem(GetMenu(Info->hMainWnd), IDC_PROP, MF_GRAYED);
436 EnableMenuItem(Info->hShortcutMenu, IDC_PROP, MF_GRAYED);
437
438 /* create seperate thread to emum devices */
439 DevEnumThread = CreateThread(NULL,
440 0,
441 DeviceEnumThread,
442 &Info->hTreeView,
443 0,
444 NULL);
445 if (!DevEnumThread)
446 {
447 DisplayString(_T("Failed to enumerate devices"));
448 break;
449 }
450
451 CloseHandle(DevEnumThread);
452 }
453 break;
454
455 case IDC_PROGHELP:
456 {
457 DisplayString(_T("Help is not yet implemented\n"));
458 SetFocus(Info->hTreeView);
459 }
460 break;
461
462 case IDC_EXIT:
463 {
464 PostMessage(Info->hMainWnd,
465 WM_CLOSE,
466 0,
467 0);
468 }
469 break;
470
471 case IDC_ABOUT:
472 {
473 DialogBox(hInstance,
474 MAKEINTRESOURCE(IDD_ABOUTBOX),
475 Info->hMainWnd,
476 AboutDialogProc);
477
478 SetFocus(Info->hTreeView);
479 }
480 break;
481
482 }
483 }
484
485
486 static VOID CALLBACK
487 MainWndResize(PMAIN_WND_INFO Info,
488 WORD cx,
489 WORD cy)
490 {
491 RECT rcClient, rcTool, rcStatus;
492 int lvHeight, iToolHeight, iStatusHeight;
493
494 /* Size toolbar and get height */
495 SendMessage(Info->hTool, TB_AUTOSIZE, 0, 0);
496 GetWindowRect(Info->hTool, &rcTool);
497 iToolHeight = rcTool.bottom - rcTool.top;
498
499 /* Size status bar and get height */
500 SendMessage(Info->hStatus, WM_SIZE, 0, 0);
501 GetWindowRect(Info->hStatus, &rcStatus);
502 iStatusHeight = rcStatus.bottom - rcStatus.top;
503
504 /* Calculate remaining height and size list view */
505 GetClientRect(Info->hMainWnd, &rcClient);
506 lvHeight = rcClient.bottom - iToolHeight - iStatusHeight;
507 SetWindowPos(Info->hTreeView,
508 NULL,
509 0,
510 iToolHeight,
511 rcClient.right,
512 lvHeight,
513 SWP_NOZORDER);
514 }
515
516
517 static LRESULT CALLBACK
518 MainWndProc(HWND hwnd,
519 UINT msg,
520 WPARAM wParam,
521 LPARAM lParam)
522 {
523 PMAIN_WND_INFO Info;
524 LRESULT Ret = 0;
525
526 /* Get the window context */
527 Info = (PMAIN_WND_INFO)GetWindowLongPtr(hwnd,
528 GWLP_USERDATA);
529 if (Info == NULL && msg != WM_CREATE)
530 {
531 goto HandleDefaultMessage;
532 }
533
534 switch(msg)
535 {
536 case WM_CREATE:
537 {
538 Info = (PMAIN_WND_INFO)(((LPCREATESTRUCT)lParam)->lpCreateParams);
539
540 /* Initialize the main window context */
541 Info->hMainWnd = hwnd;
542
543 SetWindowLongPtr(hwnd,
544 GWLP_USERDATA,
545 (LONG_PTR)Info);
546
547 if (!InitMainWnd(Info))
548 SendMessage(hwnd, WM_CLOSE, 0, 0);
549
550 /* Show the window */
551 ShowWindow(hwnd,
552 Info->nCmdShow);
553
554 }
555 break;
556
557 case WM_SIZE:
558 {
559 MainWndResize(Info,
560 LOWORD(lParam),
561 HIWORD(lParam));
562 }
563 break;
564
565 case WM_NOTIFY:
566 {
567 OnNotify(Info, lParam);
568 }
569 break;
570
571 case WM_CONTEXTMENU:
572 {
573 OnContext(Info, lParam);
574 }
575 break;
576
577 case WM_COMMAND:
578 {
579 MainWndCommand(Info,
580 LOWORD(wParam),
581 (HWND)lParam);
582 goto HandleDefaultMessage;
583 }
584
585 case WM_MENUSELECT:
586 {
587 if (Info->hStatus != NULL)
588 {
589 if (!MainWndMenuHint(Info,
590 LOWORD(wParam),
591 MainMenuHintTable,
592 sizeof(MainMenuHintTable) / sizeof(MainMenuHintTable[0]),
593 IDS_HINT_BLANK))
594 {
595 MainWndMenuHint(Info,
596 LOWORD(wParam),
597 SystemMenuHintTable,
598 sizeof(SystemMenuHintTable) / sizeof(SystemMenuHintTable[0]),
599 IDS_HINT_BLANK);
600 }
601 }
602 }
603 break;
604
605 case WM_ENTERMENULOOP:
606 {
607 Info->InMenuLoop = TRUE;
608 UpdateMainStatusBar(Info);
609 break;
610 }
611
612 case WM_EXITMENULOOP:
613 {
614 Info->InMenuLoop = FALSE;
615 UpdateMainStatusBar(Info);
616 break;
617 }
618
619 case WM_CLOSE:
620 {
621 FreeDeviceStrings(Info->hTreeView);
622 DestroyMenu(Info->hShortcutMenu);
623 DestroyWindow(hwnd);
624 }
625 break;
626
627 case WM_DESTROY:
628 {
629 HeapFree(ProcessHeap,
630 0,
631 Info);
632 SetWindowLongPtr(hwnd,
633 GWLP_USERDATA,
634 0);
635
636 /* Break the message queue loop */
637 PostQuitMessage(0);
638 }
639 break;
640
641 default:
642 {
643 HandleDefaultMessage:
644
645 Ret = DefWindowProc(hwnd,
646 msg,
647 wParam,
648 lParam);
649 }
650 break;
651 }
652 return Ret;
653 }
654
655
656
657 HWND
658 CreateMainWindow(LPCTSTR lpCaption,
659 int nCmdShow)
660 {
661 PMAIN_WND_INFO Info;
662 HWND hMainWnd = NULL;
663
664 Info = (PMAIN_WND_INFO)HeapAlloc(ProcessHeap,
665 HEAP_ZERO_MEMORY,
666 sizeof(MAIN_WND_INFO));
667
668 if (Info != NULL)
669 {
670 Info->nCmdShow = nCmdShow;
671
672 hMainWnd = CreateWindowEx(WS_EX_WINDOWEDGE,
673 szMainWndClass,
674 lpCaption,
675 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
676 CW_USEDEFAULT,
677 CW_USEDEFAULT,
678 600,
679 450,
680 NULL,
681 NULL,
682 hInstance,
683 Info);
684 if (hMainWnd == NULL)
685 {
686 GetError();
687 HeapFree(ProcessHeap,
688 0,
689 Info);
690 }
691 }
692
693 return hMainWnd;
694 }
695
696 BOOL
697 InitMainWindowImpl(VOID)
698 {
699 WNDCLASSEX wc = {0};
700
701 wc.cbSize = sizeof(WNDCLASSEX);
702 wc.lpfnWndProc = MainWndProc;
703 wc.hInstance = hInstance;
704 wc.hIcon = LoadIcon(hInstance,
705 MAKEINTRESOURCE(IDI_MAIN_ICON));
706 wc.hCursor = LoadCursor(NULL,
707 IDC_ARROW);
708 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
709 wc.lpszMenuName = MAKEINTRESOURCE(IDR_MAINMENU);
710 wc.lpszClassName = szMainWndClass;
711 wc.hIconSm = (HICON)LoadImage(hInstance,
712 MAKEINTRESOURCE(IDI_MAIN_ICON),
713 IMAGE_ICON,
714 16,
715 16,
716 LR_SHARED);
717
718 return RegisterClassEx(&wc) != (ATOM)0;
719 }
720
721
722 VOID
723 UninitMainWindowImpl(VOID)
724 {
725 UnregisterClass(szMainWndClass,
726 hInstance);
727 }
728
729