[RAPPS] CMainWindow: Make EnumInstalledAppProc and EnumAvailableAppProc methods
[reactos.git] / base / applications / rapps / gui.cpp
1 /*
2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * FILE: base/applications/rapps/gui.cpp
5 * PURPOSE: GUI classes for RAPPS
6 * COPYRIGHT: Copyright 2015 David Quintana (gigaherz@gmail.com)
7 * Copyright 2017 Alexander Shaposhnikov (sanchaez@reactos.org)
8 */
9 #include "rapps.h"
10
11 #include "rapps.h"
12 #include "rosui.h"
13 #include "crichedit.h"
14
15 #include <shlobj_undoc.h>
16 #include <shlguid_undoc.h>
17
18 #include <atlbase.h>
19 #include <atlcom.h>
20 #include <atlwin.h>
21 #include <wininet.h>
22 #include <shellutils.h>
23 #include <rosctrls.h>
24
25 #define SEARCH_TIMER_ID 'SR'
26 #define LISTVIEW_ICON_SIZE 24
27 #define TREEVIEW_ICON_SIZE 24
28
29 HWND hListView = NULL;
30
31 INT GetSystemColorDepth()
32 {
33 DEVMODEW pDevMode;
34 INT ColorDepth;
35
36 pDevMode.dmSize = sizeof(pDevMode);
37 pDevMode.dmDriverExtra = 0;
38
39 if (!EnumDisplaySettingsW(NULL, ENUM_CURRENT_SETTINGS, &pDevMode))
40 {
41 /* TODO: Error message */
42 return ILC_COLOR;
43 }
44
45 switch (pDevMode.dmBitsPerPel)
46 {
47 case 32: ColorDepth = ILC_COLOR32; break;
48 case 24: ColorDepth = ILC_COLOR24; break;
49 case 16: ColorDepth = ILC_COLOR16; break;
50 case 8: ColorDepth = ILC_COLOR8; break;
51 case 4: ColorDepth = ILC_COLOR4; break;
52 default: ColorDepth = ILC_COLOR; break;
53 }
54
55 return ColorDepth;
56 }
57
58 class CAppRichEdit:
59 public CUiWindow<CRichEdit>
60 {
61 private:
62 VOID LoadAndInsertText(UINT uStringID,
63 const ATL::CStringW& szText,
64 DWORD StringFlags,
65 DWORD TextFlags)
66 {
67 ATL::CStringW szLoadedText;
68 if (!szText.IsEmpty() && szLoadedText.LoadStringW(uStringID))
69 {
70 InsertText(szLoadedText, StringFlags);
71 InsertText(szText, TextFlags);
72 }
73 }
74
75 VOID LoadAndInsertText(UINT uStringID,
76 DWORD StringFlags)
77 {
78 ATL::CStringW szLoadedText;
79 if (szLoadedText.LoadStringW(uStringID))
80 {
81 InsertText(L"\n", 0);
82 InsertText(szLoadedText, StringFlags);
83 InsertText(L"\n", 0);
84 }
85 }
86
87 VOID InsertVersionInfo(CAvailableApplicationInfo* Info)
88 {
89 if (Info->IsInstalled())
90 {
91 if (Info->HasInstalledVersion())
92 {
93 if (Info->HasUpdate())
94 LoadAndInsertText(IDS_STATUS_UPDATE_AVAILABLE, CFE_ITALIC);
95 else
96 LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
97
98 LoadAndInsertText(IDS_AINFO_VERSION, Info->m_szInstalledVersion, CFE_BOLD, 0);
99 }
100 else
101 {
102 LoadAndInsertText(IDS_STATUS_INSTALLED, CFE_ITALIC);
103 }
104 }
105 else
106 {
107 LoadAndInsertText(IDS_STATUS_NOTINSTALLED, CFE_ITALIC);
108 }
109
110 LoadAndInsertText(IDS_AINFO_AVAILABLEVERSION, Info->m_szVersion, CFE_BOLD, 0);
111 }
112
113 VOID InsertLicenseInfo(CAvailableApplicationInfo* Info)
114 {
115 ATL::CStringW szLicense;
116 switch (Info->m_LicenseType)
117 {
118 case LICENSE_OPENSOURCE:
119 szLicense.LoadStringW(IDS_LICENSE_OPENSOURCE);
120 break;
121 case LICENSE_FREEWARE:
122 szLicense.LoadStringW(IDS_LICENSE_FREEWARE);
123 break;
124 case LICENSE_TRIAL:
125 szLicense.LoadStringW(IDS_LICENSE_TRIAL);
126 break;
127 default:
128 LoadAndInsertText(IDS_AINFO_LICENSE, Info->m_szLicense, CFE_BOLD, 0);
129 return;
130 }
131
132 szLicense += L" (" + Info->m_szLicense + L")";
133 LoadAndInsertText(IDS_AINFO_LICENSE, szLicense, CFE_BOLD, 0);
134 }
135
136 VOID InsertLanguageInfo(CAvailableApplicationInfo* Info)
137 {
138 if (!Info->HasLanguageInfo())
139 {
140 return;
141 }
142
143 const INT nTranslations = Info->m_LanguageLCIDs.GetSize();
144 ATL::CStringW szLangInfo;
145 ATL::CStringW szLoadedTextAvailability;
146 ATL::CStringW szLoadedAInfoText;
147
148 szLoadedAInfoText.LoadStringW(IDS_AINFO_LANGUAGES);
149
150 if (Info->HasNativeLanguage())
151 {
152 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_AVAILABLE_TRANSLATION);
153 if (nTranslations > 1)
154 {
155 ATL::CStringW buf;
156 buf.LoadStringW(IDS_LANGUAGE_MORE_PLACEHOLDER);
157 szLangInfo.Format(buf, nTranslations - 1);
158 }
159 else
160 {
161 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
162 szLangInfo = L" (" + szLangInfo + L")";
163 }
164 }
165 else if (Info->HasEnglishLanguage())
166 {
167 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_ENGLISH_TRANSLATION);
168 if (nTranslations > 1)
169 {
170 ATL::CStringW buf;
171 buf.LoadStringW(IDS_LANGUAGE_AVAILABLE_PLACEHOLDER);
172 szLangInfo.Format(buf, nTranslations - 1);
173 }
174 else
175 {
176 szLangInfo.LoadStringW(IDS_LANGUAGE_SINGLE);
177 szLangInfo = L" (" + szLangInfo + L")";
178 }
179 }
180 else
181 {
182 szLoadedTextAvailability.LoadStringW(IDS_LANGUAGE_NO_TRANSLATION);
183 }
184
185 InsertText(szLoadedAInfoText, CFE_BOLD);
186 InsertText(szLoadedTextAvailability, NULL);
187 InsertText(szLangInfo, CFE_ITALIC);
188 }
189
190 public:
191 BOOL ShowAvailableAppInfo(CAvailableApplicationInfo* Info)
192 {
193 if (!Info) return FALSE;
194
195 SetText(Info->m_szName, CFE_BOLD);
196 InsertVersionInfo(Info);
197 InsertLicenseInfo(Info);
198 InsertLanguageInfo(Info);
199
200 LoadAndInsertText(IDS_AINFO_SIZE, Info->m_szSize, CFE_BOLD, 0);
201 LoadAndInsertText(IDS_AINFO_URLSITE, Info->m_szUrlSite, CFE_BOLD, CFE_LINK);
202 LoadAndInsertText(IDS_AINFO_DESCRIPTION, Info->m_szDesc, CFE_BOLD, 0);
203 LoadAndInsertText(IDS_AINFO_URLDOWNLOAD, Info->m_szUrlDownload, CFE_BOLD, CFE_LINK);
204
205 return TRUE;
206 }
207
208 BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
209 {
210 ATL::CStringW szText;
211 ATL::CStringW szInfo;
212
213 if (!Info || !Info->hSubKey)
214 return FALSE;
215
216 Info->GetApplicationString(L"DisplayName", szText);
217 SetText(szText, CFE_BOLD);
218 InsertText(L"\n", 0);
219
220 #define GET_INFO(a, b, c, d) \
221 if (Info->GetApplicationString(a, szInfo)) \
222 { \
223 LoadAndInsertText(b, szInfo, c, d); \
224 }
225
226 GET_INFO(L"DisplayVersion", IDS_INFO_VERSION, CFE_BOLD, 0);
227 GET_INFO(L"Publisher", IDS_INFO_PUBLISHER, CFE_BOLD, 0);
228 GET_INFO(L"RegOwner", IDS_INFO_REGOWNER, CFE_BOLD, 0);
229 GET_INFO(L"ProductID", IDS_INFO_PRODUCTID, CFE_BOLD, 0);
230 GET_INFO(L"HelpLink", IDS_INFO_HELPLINK, CFE_BOLD, CFM_LINK);
231 GET_INFO(L"HelpTelephone", IDS_INFO_HELPPHONE, CFE_BOLD, 0);
232 GET_INFO(L"Readme", IDS_INFO_README, CFE_BOLD, 0);
233 GET_INFO(L"Contact", IDS_INFO_CONTACT, CFE_BOLD, 0);
234 GET_INFO(L"URLUpdateInfo", IDS_INFO_UPDATEINFO, CFE_BOLD, CFM_LINK);
235 GET_INFO(L"URLInfoAbout", IDS_INFO_INFOABOUT, CFE_BOLD, CFM_LINK);
236 GET_INFO(L"Comments", IDS_INFO_COMMENTS, CFE_BOLD, 0);
237 GET_INFO(L"InstallDate", IDS_INFO_INSTALLDATE, CFE_BOLD, 0);
238 GET_INFO(L"InstallLocation", IDS_INFO_INSTLOCATION, CFE_BOLD, 0);
239 GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
240 GET_INFO(L"UninstallString", IDS_INFO_UNINSTALLSTR, CFE_BOLD, 0);
241 GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
242 GET_INFO(L"ModifyPath", IDS_INFO_MODIFYPATH, CFE_BOLD, 0);
243
244 return TRUE;
245 }
246
247 VOID SetWelcomeText()
248 {
249 ATL::CStringW szText;
250
251 szText.LoadStringW(IDS_WELCOME_TITLE);
252 SetText(szText, CFE_BOLD);
253
254 szText.LoadStringW(IDS_WELCOME_TEXT);
255 InsertText(szText, 0);
256
257 szText.LoadStringW(IDS_WELCOME_URL);
258 InsertText(szText, CFM_LINK);
259 }
260 };
261
262 class CMainToolbar :
263 public CUiWindow< CToolbar<> >
264 {
265 const INT m_iToolbarHeight;
266 DWORD m_dButtonsWidthMax;
267
268 WCHAR szInstallBtn[MAX_STR_LEN];
269 WCHAR szUninstallBtn[MAX_STR_LEN];
270 WCHAR szModifyBtn[MAX_STR_LEN];
271 WCHAR szSelectAll[MAX_STR_LEN];
272
273 VOID AddImageToImageList(HIMAGELIST hImageList, UINT ImageIndex)
274 {
275 HICON hImage;
276
277 if (!(hImage = (HICON) LoadImageW(hInst,
278 MAKEINTRESOURCE(ImageIndex),
279 IMAGE_ICON,
280 m_iToolbarHeight,
281 m_iToolbarHeight,
282 0)))
283 {
284 /* TODO: Error message */
285 }
286
287 ImageList_AddIcon(hImageList, hImage);
288 DeleteObject(hImage);
289 }
290
291 HIMAGELIST InitImageList()
292 {
293 HIMAGELIST hImageList;
294
295 /* Create the toolbar icon image list */
296 hImageList = ImageList_Create(m_iToolbarHeight,//GetSystemMetrics(SM_CXSMICON),
297 m_iToolbarHeight,//GetSystemMetrics(SM_CYSMICON),
298 ILC_MASK | GetSystemColorDepth(),
299 1, 1);
300 if (!hImageList)
301 {
302 /* TODO: Error message */
303 return NULL;
304 }
305
306 AddImageToImageList(hImageList, IDI_INSTALL);
307 AddImageToImageList(hImageList, IDI_UNINSTALL);
308 AddImageToImageList(hImageList, IDI_MODIFY);
309 AddImageToImageList(hImageList, IDI_CHECK_ALL);
310 AddImageToImageList(hImageList, IDI_REFRESH);
311 AddImageToImageList(hImageList, IDI_UPDATE_DB);
312 AddImageToImageList(hImageList, IDI_SETTINGS);
313 AddImageToImageList(hImageList, IDI_EXIT);
314
315 return hImageList;
316 }
317
318 public:
319 CMainToolbar() : m_iToolbarHeight(24)
320 {
321 }
322
323 VOID OnGetDispInfo(LPTOOLTIPTEXT lpttt)
324 {
325 UINT idButton = (UINT) lpttt->hdr.idFrom;
326
327 switch (idButton)
328 {
329 case ID_EXIT:
330 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_EXIT);
331 break;
332
333 case ID_INSTALL:
334 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_INSTALL);
335 break;
336
337 case ID_UNINSTALL:
338 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UNINSTALL);
339 break;
340
341 case ID_MODIFY:
342 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_MODIFY);
343 break;
344
345 case ID_SETTINGS:
346 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_SETTINGS);
347 break;
348
349 case ID_REFRESH:
350 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_REFRESH);
351 break;
352
353 case ID_RESETDB:
354 lpttt->lpszText = MAKEINTRESOURCEW(IDS_TOOLTIP_UPDATE_DB);
355 break;
356 }
357 }
358
359 HWND Create(HWND hwndParent)
360 {
361 /* Create buttons */
362 TBBUTTON Buttons[] =
363 { /* iBitmap, idCommand, fsState, fsStyle, bReserved[2], dwData, iString */
364 { 0, ID_INSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szInstallBtn },
365 { 1, ID_UNINSTALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szUninstallBtn },
366 { 2, ID_MODIFY, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szModifyBtn },
367 { 3, ID_CHECK_ALL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, (INT_PTR) szSelectAll },
368 { -1, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0, 0 },
369 { 4, ID_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
370 { 5, ID_RESETDB, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
371 { -1, 0, TBSTATE_ENABLED, BTNS_SEP, { 0 }, 0, 0 },
372 { 6, ID_SETTINGS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
373 { 7, ID_EXIT, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, { 0 }, 0, 0 },
374 };
375
376 LoadStringW(hInst, IDS_INSTALL, szInstallBtn, _countof(szInstallBtn));
377 LoadStringW(hInst, IDS_UNINSTALL, szUninstallBtn, _countof(szUninstallBtn));
378 LoadStringW(hInst, IDS_MODIFY, szModifyBtn, _countof(szModifyBtn));
379 LoadStringW(hInst, IDS_SELECT_ALL, szSelectAll, _countof(szSelectAll));
380
381 m_hWnd = CreateWindowExW(0, TOOLBARCLASSNAMEW, NULL,
382 WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_LIST,
383 0, 0, 0, 0,
384 hwndParent,
385 0, hInst, NULL);
386
387 if (!m_hWnd)
388 {
389 /* TODO: Show error message */
390 return FALSE;
391 }
392
393 SendMessageW(TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_HIDECLIPPEDBUTTONS);
394 SetButtonStructSize();
395
396 /* Set image list */
397 HIMAGELIST hImageList = InitImageList();
398
399 if (!hImageList)
400 {
401 /* TODO: Show error message */
402 return FALSE;
403 }
404
405 ImageList_Destroy(SetImageList(hImageList));
406
407 AddButtons(_countof(Buttons), Buttons);
408
409 /* Remember ideal width to use as a max width of buttons */
410 SIZE size;
411 GetIdealSize(FALSE, &size);
412 m_dButtonsWidthMax = size.cx;
413
414 return m_hWnd;
415 }
416
417 VOID HideButtonCaption()
418 {
419 DWORD dCurrentExStyle = (DWORD) SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
420 SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle | TBSTYLE_EX_MIXEDBUTTONS);
421 }
422
423 VOID ShowButtonCaption()
424 {
425 DWORD dCurrentExStyle = (DWORD) SendMessageW(TB_GETEXTENDEDSTYLE, 0, 0);
426 SendMessageW(TB_SETEXTENDEDSTYLE, 0, dCurrentExStyle & ~TBSTYLE_EX_MIXEDBUTTONS);
427 }
428
429 DWORD GetMaxButtonsWidth() const
430 {
431 return m_dButtonsWidthMax;
432 }
433 };
434
435 class CAppsListView :
436 public CUiWindow<CListView>
437 {
438 struct SortContext
439 {
440 CAppsListView * lvw;
441 INT iSubItem;
442 };
443
444 BOOL bHasAllChecked;
445 BOOL bIsAscending;
446 BOOL bHasCheckboxes;
447
448 INT nLastHeaderID;
449
450 public:
451 CAppsListView() :
452 bHasAllChecked(FALSE),
453 bIsAscending(TRUE),
454 bHasCheckboxes(FALSE),
455 nLastHeaderID(-1)
456 {
457 }
458
459 VOID SetCheckboxesVisible(BOOL bIsVisible)
460 {
461 if (bIsVisible)
462 {
463 SetExtendedListViewStyle(LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
464 }
465 else
466 {
467 SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
468 }
469
470 bHasCheckboxes = bIsVisible;
471 }
472
473 VOID ColumnClick(LPNMLISTVIEW pnmv)
474 {
475 HWND hHeader;
476 HDITEMW hColumn;
477 INT nHeaderID = pnmv->iSubItem;
478
479 if ((GetWindowLongPtr(GWL_STYLE) & ~LVS_NOSORTHEADER) == 0)
480 return;
481
482 hHeader = (HWND) SendMessage(LVM_GETHEADER, 0, 0);
483 ZeroMemory(&hColumn, sizeof(hColumn));
484
485 /* If the sorting column changed, remove the sorting style from the old column */
486 if ((nLastHeaderID != -1) && (nLastHeaderID != nHeaderID))
487 {
488 hColumn.mask = HDI_FORMAT;
489 Header_GetItem(hHeader, nLastHeaderID, &hColumn);
490 hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
491 Header_SetItem(hHeader, nLastHeaderID, &hColumn);
492 }
493
494 /* Set the sorting style to the new column */
495 hColumn.mask = HDI_FORMAT;
496 Header_GetItem(hHeader, nHeaderID, &hColumn);
497
498 hColumn.fmt &= (bIsAscending ? ~HDF_SORTDOWN : ~HDF_SORTUP);
499 hColumn.fmt |= (bIsAscending ? HDF_SORTUP : HDF_SORTDOWN);
500 Header_SetItem(hHeader, nHeaderID, &hColumn);
501
502 /* Sort the list, using the current values of nHeaderID and bIsAscending */
503 SortContext ctx = {this, nHeaderID};
504 SortItems(s_CompareFunc, &ctx);
505
506 /* Save new values */
507 nLastHeaderID = nHeaderID;
508 bIsAscending = !bIsAscending;
509 }
510
511 PVOID GetLParam(INT Index)
512 {
513 INT ItemIndex;
514 LVITEMW Item;
515
516 if (Index == -1)
517 {
518 ItemIndex = (INT) SendMessage(LVM_GETNEXTITEM, -1, LVNI_FOCUSED);
519 if (ItemIndex == -1)
520 return NULL;
521 }
522 else
523 {
524 ItemIndex = Index;
525 }
526
527 ZeroMemory(&Item, sizeof(Item));
528
529 Item.mask = LVIF_PARAM;
530 Item.iItem = ItemIndex;
531 if (!GetItem(&Item))
532 return NULL;
533
534 return (PVOID) Item.lParam;
535 }
536
537 BOOL AddColumn(INT Index, ATL::CStringW& Text, INT Width, INT Format)
538 {
539 return AddColumn(Index, const_cast<LPWSTR>(Text.GetString()), Width, Format);
540 }
541
542 BOOL AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
543 {
544 LVCOLUMNW Column;
545
546 ZeroMemory(&Column, sizeof(Column));
547
548 Column.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
549 Column.iSubItem = Index;
550 Column.pszText = lpText;
551 Column.cx = Width;
552 Column.fmt = Format;
553
554 return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE;
555 }
556
557 INT AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam)
558 {
559 LVITEMW Item;
560
561 ZeroMemory(&Item, sizeof(Item));
562
563 Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
564 Item.pszText = const_cast<LPWSTR>(lpText);
565 Item.lParam = lParam;
566 Item.iItem = ItemIndex;
567 Item.iImage = IconIndex;
568
569 return InsertItem(&Item);
570 }
571
572 static INT CALLBACK s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
573 {
574 SortContext * ctx = ((SortContext*) lParamSort);
575 return ctx->lvw->CompareFunc(lParam1, lParam2, ctx->iSubItem);
576 }
577
578 INT CompareFunc(LPARAM lParam1, LPARAM lParam2, INT iSubItem)
579 {
580 ATL::CStringW Item1, Item2;
581 LVFINDINFOW IndexInfo;
582 INT Index;
583
584 IndexInfo.flags = LVFI_PARAM;
585
586 IndexInfo.lParam = lParam1;
587 Index = FindItem(-1, &IndexInfo);
588 GetItemText(Index, iSubItem, Item1.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
589 Item1.ReleaseBuffer();
590
591 IndexInfo.lParam = lParam2;
592 Index = FindItem(-1, &IndexInfo);
593 GetItemText(Index, iSubItem, Item2.GetBuffer(MAX_STR_LEN), MAX_STR_LEN);
594 Item2.ReleaseBuffer();
595
596 return bIsAscending ? Item1.Compare(Item2) : Item2.Compare(Item1);
597 }
598
599 HWND Create(HWND hwndParent)
600 {
601 RECT r = {205, 28, 465, 250};
602 DWORD style = WS_CHILD | WS_VISIBLE | LVS_SORTASCENDING | LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS;
603 HMENU menu = GetSubMenu(LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_APPLICATIONMENU)), 0);
604
605 HWND hwnd = CListView::Create(hwndParent, r, NULL, style, WS_EX_CLIENTEDGE, menu);
606
607 if (hwnd)
608 {
609 SetCheckboxesVisible(FALSE);
610 }
611
612 return hwnd;
613 }
614
615 BOOL GetCheckState(INT item)
616 {
617 return (BOOL) (GetItemState(item, LVIS_STATEIMAGEMASK) >> 12) - 1;
618 }
619
620 VOID SetCheckState(INT item, BOOL fCheck)
621 {
622 if (bHasCheckboxes)
623 {
624 SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), LVIS_STATEIMAGEMASK);
625 SetSelected(item, fCheck);
626 }
627 }
628
629 VOID SetSelected(INT item, BOOL value)
630 {
631 if (item < 0)
632 {
633 for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
634 {
635 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(i);
636 if (pAppInfo)
637 {
638 pAppInfo->m_IsSelected = value;
639 }
640 }
641 }
642 else
643 {
644 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(item);
645 if (pAppInfo)
646 {
647 pAppInfo->m_IsSelected = value;
648 }
649 }
650 }
651
652 VOID CheckAll()
653 {
654 if (bHasCheckboxes)
655 {
656 bHasAllChecked = !bHasAllChecked;
657 SetCheckState(-1, bHasAllChecked);
658 }
659 }
660
661 ATL::CSimpleArray<CAvailableApplicationInfo> GetCheckedItems()
662 {
663 if (!bHasCheckboxes)
664 {
665 return ATL::CSimpleArray<CAvailableApplicationInfo>();
666 }
667
668 ATL::CSimpleArray<CAvailableApplicationInfo> list;
669 for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
670 {
671 if (GetCheckState(i) != FALSE)
672 {
673 CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) GetItemData(i);
674 list.Add(*pAppInfo);
675 }
676 }
677 return list;
678 }
679
680 CAvailableApplicationInfo* GetSelectedData()
681 {
682 INT item = GetSelectionMark();
683 return (CAvailableApplicationInfo*) GetItemData(item);
684 }
685 };
686
687 class CSideTreeView :
688 public CUiWindow<CTreeView>
689 {
690 HIMAGELIST hImageTreeView;
691
692 public:
693 CSideTreeView() :
694 CUiWindow(),
695 hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
696 GetSystemColorDepth() | ILC_MASK,
697 0, 1))
698 {
699 }
700
701 HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT SelectedImage, LPARAM lParam)
702 {
703 return CUiWindow<CTreeView>::AddItem(hParent, const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
704 }
705
706 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
707 {
708 ATL::CStringW szText;
709 INT Index;
710 HICON hIcon;
711
712 hIcon = (HICON) LoadImageW(hInst,
713 MAKEINTRESOURCE(IconIndex),
714 IMAGE_ICON,
715 TREEVIEW_ICON_SIZE,
716 TREEVIEW_ICON_SIZE,
717 LR_CREATEDIBSECTION);
718 if (hIcon)
719 {
720 Index = ImageList_AddIcon(hImageTreeView, hIcon);
721 DestroyIcon(hIcon);
722 }
723
724 szText.LoadStringW(TextIndex);
725 return AddItem(hRootItem, szText, Index, Index, TextIndex);
726 }
727
728 HIMAGELIST SetImageList()
729 {
730 return CUiWindow<CTreeView>::SetImageList(hImageTreeView, TVSIL_NORMAL);
731 }
732
733 VOID DestroyImageList()
734 {
735 if (hImageTreeView)
736 ImageList_Destroy(hImageTreeView);
737 }
738
739 ~CSideTreeView()
740 {
741 DestroyImageList();
742 }
743 };
744
745 class CSearchBar :
746 public CWindow
747 {
748 public:
749 const INT m_Width;
750 const INT m_Height;
751
752 CSearchBar() : m_Width(200), m_Height(22)
753 {
754 }
755
756 VOID SetText(LPCWSTR lpszText)
757 {
758 SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
759 }
760
761 HWND Create(HWND hwndParent)
762 {
763 ATL::CStringW szBuf;
764 m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
765 WS_CHILD | WS_VISIBLE | ES_LEFT | ES_AUTOHSCROLL,
766 0, 0, m_Width, m_Height,
767 hwndParent, (HMENU) NULL,
768 hInst, 0);
769
770 SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
771 szBuf.LoadStringW(IDS_SEARCH_TEXT);
772 SetWindowTextW(szBuf);
773 return m_hWnd;
774 }
775
776 };
777
778 class CMainWindow :
779 public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
780 {
781 CUiPanel* m_ClientPanel;
782 CUiSplitPanel* m_VSplitter;
783 CUiSplitPanel* m_HSplitter;
784
785 CMainToolbar* m_Toolbar;
786 CAppsListView* m_ListView;
787
788 CSideTreeView* m_TreeView;
789 CUiWindow<CStatusBar>* m_StatusBar;
790 CAppRichEdit* m_RichEdit;
791
792 CUiWindow<CSearchBar>* m_SearchBar;
793 CAvailableApps m_AvailableApps;
794
795 LPWSTR pLink;
796
797 INT nSelectedApps;
798
799 BOOL bSearchEnabled;
800 BOOL bUpdating;
801
802 public:
803 CMainWindow() :
804 m_ClientPanel(NULL),
805 pLink(NULL),
806 bSearchEnabled(FALSE)
807 {
808 }
809
810 private:
811 VOID InitApplicationsList()
812 {
813 ATL::CStringW szText;
814
815 /* Add columns to ListView */
816 szText.LoadStringW(IDS_APP_NAME);
817 m_ListView->AddColumn(0, szText, 250, LVCFMT_LEFT);
818
819 szText.LoadStringW(IDS_APP_INST_VERSION);
820 m_ListView->AddColumn(1, szText, 90, LVCFMT_RIGHT);
821
822 szText.LoadStringW(IDS_APP_DESCRIPTION);
823 m_ListView->AddColumn(3, szText, 300, LVCFMT_LEFT);
824
825 // Unnesesary since the list updates on every TreeView selection
826 // UpdateApplicationsList(ENUM_ALL_COMPONENTS);
827 }
828
829 HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
830 {
831 return m_TreeView->AddCategory(hRootItem, TextIndex, IconIndex);
832 }
833
834 VOID InitCategoriesList()
835 {
836 HTREEITEM hRootItemInstalled, hRootItemAvailable;
837
838 hRootItemInstalled = AddCategory(TVI_ROOT, IDS_INSTALLED, IDI_CATEGORY);
839 AddCategory(hRootItemInstalled, IDS_APPLICATIONS, IDI_APPS);
840 AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
841
842 AddCategory(TVI_ROOT, IDS_SELECTEDFORINST, IDI_SELECTEDFORINST);
843
844 hRootItemAvailable = AddCategory(TVI_ROOT, IDS_AVAILABLEFORINST, IDI_CATEGORY);
845 AddCategory(hRootItemAvailable, IDS_CAT_AUDIO, IDI_CAT_AUDIO);
846 AddCategory(hRootItemAvailable, IDS_CAT_VIDEO, IDI_CAT_VIDEO);
847 AddCategory(hRootItemAvailable, IDS_CAT_GRAPHICS, IDI_CAT_GRAPHICS);
848 AddCategory(hRootItemAvailable, IDS_CAT_GAMES, IDI_CAT_GAMES);
849 AddCategory(hRootItemAvailable, IDS_CAT_INTERNET, IDI_CAT_INTERNET);
850 AddCategory(hRootItemAvailable, IDS_CAT_OFFICE, IDI_CAT_OFFICE);
851 AddCategory(hRootItemAvailable, IDS_CAT_DEVEL, IDI_CAT_DEVEL);
852 AddCategory(hRootItemAvailable, IDS_CAT_EDU, IDI_CAT_EDU);
853 AddCategory(hRootItemAvailable, IDS_CAT_ENGINEER, IDI_CAT_ENGINEER);
854 AddCategory(hRootItemAvailable, IDS_CAT_FINANCE, IDI_CAT_FINANCE);
855 AddCategory(hRootItemAvailable, IDS_CAT_SCIENCE, IDI_CAT_SCIENCE);
856 AddCategory(hRootItemAvailable, IDS_CAT_TOOLS, IDI_CAT_TOOLS);
857 AddCategory(hRootItemAvailable, IDS_CAT_DRIVERS, IDI_CAT_DRIVERS);
858 AddCategory(hRootItemAvailable, IDS_CAT_LIBS, IDI_CAT_LIBS);
859 AddCategory(hRootItemAvailable, IDS_CAT_THEMES, IDI_CAT_THEMES);
860 AddCategory(hRootItemAvailable, IDS_CAT_OTHER, IDI_CAT_OTHER);
861
862 m_TreeView->SetImageList();
863 m_TreeView->Expand(hRootItemInstalled, TVE_EXPAND);
864 m_TreeView->Expand(hRootItemAvailable, TVE_EXPAND);
865 m_TreeView->SelectItem(hRootItemAvailable);
866 }
867
868 BOOL CreateStatusBar()
869 {
870 m_StatusBar = new CUiWindow<CStatusBar>();
871 m_StatusBar->m_VerticalAlignment = UiAlign_RightBtm;
872 m_StatusBar->m_HorizontalAlignment = UiAlign_Stretch;
873 m_ClientPanel->Children().Append(m_StatusBar);
874
875 return m_StatusBar->Create(m_hWnd, (HMENU) IDC_STATUSBAR) != NULL;
876 }
877
878 BOOL CreateToolbar()
879 {
880 m_Toolbar = new CMainToolbar();
881 m_Toolbar->m_VerticalAlignment = UiAlign_LeftTop;
882 m_Toolbar->m_HorizontalAlignment = UiAlign_Stretch;
883 m_ClientPanel->Children().Append(m_Toolbar);
884
885 return m_Toolbar->Create(m_hWnd) != NULL;
886 }
887
888 BOOL CreateTreeView()
889 {
890 m_TreeView = new CSideTreeView();
891 m_TreeView->m_VerticalAlignment = UiAlign_Stretch;
892 m_TreeView->m_HorizontalAlignment = UiAlign_Stretch;
893 m_VSplitter->First().Append(m_TreeView);
894
895 return m_TreeView->Create(m_hWnd) != NULL;
896 }
897
898 BOOL CreateListView()
899 {
900 m_ListView = new CAppsListView();
901 m_ListView->m_VerticalAlignment = UiAlign_Stretch;
902 m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
903 m_HSplitter->First().Append(m_ListView);
904
905 hListView = m_ListView->Create(m_hWnd);
906 return hListView != NULL;
907 }
908
909 BOOL CreateRichEdit()
910 {
911 m_RichEdit = new CAppRichEdit();
912 m_RichEdit->m_VerticalAlignment = UiAlign_Stretch;
913 m_RichEdit->m_HorizontalAlignment = UiAlign_Stretch;
914 m_HSplitter->Second().Append(m_RichEdit);
915
916 return m_RichEdit->Create(m_hWnd) != NULL;
917 }
918
919 BOOL CreateVSplitter()
920 {
921 m_VSplitter = new CUiSplitPanel();
922 m_VSplitter->m_VerticalAlignment = UiAlign_Stretch;
923 m_VSplitter->m_HorizontalAlignment = UiAlign_Stretch;
924 m_VSplitter->m_DynamicFirst = FALSE;
925 m_VSplitter->m_Horizontal = FALSE;
926 m_VSplitter->m_MinFirst = 0;
927 m_VSplitter->m_MinSecond = 320;
928 m_VSplitter->m_Pos = 240;
929 m_ClientPanel->Children().Append(m_VSplitter);
930
931 return m_VSplitter->Create(m_hWnd) != NULL;
932 }
933
934 BOOL CreateHSplitter()
935 {
936 m_HSplitter = new CUiSplitPanel();
937 m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
938 m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
939 m_HSplitter->m_DynamicFirst = TRUE;
940 m_HSplitter->m_Horizontal = TRUE;
941 m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible position (m_MinSecond)
942 m_HSplitter->m_MinFirst = 10;
943 m_HSplitter->m_MinSecond = 140;
944 m_VSplitter->Second().Append(m_HSplitter);
945
946 return m_HSplitter->Create(m_hWnd) != NULL;
947 }
948
949 BOOL CreateSearchBar()
950 {
951 m_SearchBar = new CUiWindow<CSearchBar>();
952 m_SearchBar->m_VerticalAlignment = UiAlign_LeftTop;
953 m_SearchBar->m_HorizontalAlignment = UiAlign_RightBtm;
954 m_SearchBar->m_Margin.top = 4;
955 m_SearchBar->m_Margin.right = 6;
956
957 return m_SearchBar->Create(m_Toolbar->m_hWnd) != NULL;
958 }
959
960 BOOL CreateLayout()
961 {
962 BOOL b = TRUE;
963 bUpdating = TRUE;
964
965 m_ClientPanel = new CUiPanel();
966 m_ClientPanel->m_VerticalAlignment = UiAlign_Stretch;
967 m_ClientPanel->m_HorizontalAlignment = UiAlign_Stretch;
968
969 // Top level
970 b = b && CreateStatusBar();
971 b = b && CreateToolbar();
972 b = b && CreateSearchBar();
973 b = b && CreateVSplitter();
974
975 // Inside V Splitter
976 b = b && CreateHSplitter();
977 b = b && CreateTreeView();
978
979 // Inside H Splitter
980 b = b && CreateListView();
981 b = b && CreateRichEdit();
982
983 if (b)
984 {
985 RECT rTop;
986 RECT rBottom;
987
988 /* Size status bar */
989 m_StatusBar->SendMessageW(WM_SIZE, 0, 0);
990
991 /* Size tool bar */
992 m_Toolbar->AutoSize();
993
994 ::GetWindowRect(m_Toolbar->m_hWnd, &rTop);
995 ::GetWindowRect(m_StatusBar->m_hWnd, &rBottom);
996
997 m_VSplitter->m_Margin.top = rTop.bottom - rTop.top;
998 m_VSplitter->m_Margin.bottom = rBottom.bottom - rBottom.top;
999 }
1000
1001 bUpdating = FALSE;
1002 return b;
1003 }
1004
1005 BOOL InitControls()
1006 {
1007 if (CreateLayout())
1008 {
1009
1010 InitApplicationsList();
1011 InitCategoriesList();
1012
1013 nSelectedApps = 0;
1014 UpdateStatusBarText();
1015
1016 return TRUE;
1017 }
1018
1019 return FALSE;
1020 }
1021
1022 VOID ShowAppInfo(INT Index)
1023 {
1024 if (IsInstalledEnum(SelectedEnumType))
1025 {
1026 if (Index == -1)
1027 Index = m_ListView->GetSelectionMark();
1028
1029 PINSTALLED_INFO Info = (PINSTALLED_INFO) m_ListView->GetItemData(Index);
1030
1031 m_RichEdit->ShowInstalledAppInfo(Info);
1032 }
1033 else if (IsAvailableEnum(SelectedEnumType))
1034 {
1035 if (Index == -1)
1036 return;
1037
1038 CAvailableApplicationInfo* Info = (CAvailableApplicationInfo*) m_ListView->GetItemData(Index);
1039
1040 m_RichEdit->ShowAvailableAppInfo(Info);
1041 }
1042 }
1043
1044 VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
1045 {
1046 if (wParam == SIZE_MINIMIZED)
1047 return;
1048
1049 /* Size status bar */
1050 m_StatusBar->SendMessage(WM_SIZE, 0, 0);
1051
1052 /* Size tool bar */
1053 m_Toolbar->AutoSize();
1054
1055 /* Automatically hide captions */
1056 DWORD dToolbarTreshold = m_Toolbar->GetMaxButtonsWidth();
1057 DWORD dSearchbarMargin = (LOWORD(lParam) - m_SearchBar->m_Width);
1058
1059 if (dSearchbarMargin > dToolbarTreshold)
1060 {
1061 m_Toolbar->ShowButtonCaption();
1062 }
1063 else if (dSearchbarMargin < dToolbarTreshold)
1064 {
1065 m_Toolbar->HideButtonCaption();
1066 }
1067
1068 RECT r = {0, 0, LOWORD(lParam), HIWORD(lParam)};
1069 HDWP hdwp = NULL;
1070 INT count = m_ClientPanel->CountSizableChildren();
1071
1072 hdwp = BeginDeferWindowPos(count);
1073 if (hdwp)
1074 {
1075 hdwp = m_ClientPanel->OnParentSize(r, hdwp);
1076 if (hdwp)
1077 {
1078 EndDeferWindowPos(hdwp);
1079 }
1080
1081 }
1082
1083 // TODO: Sub-layouts for children of children
1084 count = m_SearchBar->CountSizableChildren();
1085 hdwp = BeginDeferWindowPos(count);
1086 if (hdwp)
1087 {
1088 hdwp = m_SearchBar->OnParentSize(r, hdwp);
1089 if (hdwp)
1090 {
1091 EndDeferWindowPos(hdwp);
1092 }
1093 }
1094
1095 }
1096
1097 BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT& theResult, DWORD dwMapId)
1098 {
1099 theResult = 0;
1100 switch (Msg)
1101 {
1102 case WM_CREATE:
1103 if (!InitControls())
1104 ::PostMessageW(hwnd, WM_CLOSE, 0, 0);
1105 break;
1106
1107 case WM_DESTROY:
1108 {
1109 ShowWindow(SW_HIDE);
1110 SaveSettings(hwnd);
1111
1112 FreeLogs();
1113 m_AvailableApps.FreeCachedEntries();
1114
1115 if (IsInstalledEnum(SelectedEnumType))
1116 FreeInstalledAppList();
1117
1118 delete m_ClientPanel;
1119
1120 PostQuitMessage(0);
1121 return 0;
1122 }
1123
1124 case WM_COMMAND:
1125 OnCommand(wParam, lParam);
1126 break;
1127
1128 case WM_NOTIFY:
1129 {
1130 LPNMHDR data = (LPNMHDR) lParam;
1131
1132 switch (data->code)
1133 {
1134 case TVN_SELCHANGED:
1135 {
1136 if (data->hwndFrom == m_TreeView->m_hWnd)
1137 {
1138 switch (((LPNMTREEVIEW) lParam)->itemNew.lParam)
1139 {
1140 case IDS_INSTALLED:
1141 UpdateApplicationsList(ENUM_ALL_INSTALLED);
1142 break;
1143
1144 case IDS_APPLICATIONS:
1145 UpdateApplicationsList(ENUM_INSTALLED_APPLICATIONS);
1146 break;
1147
1148 case IDS_UPDATES:
1149 UpdateApplicationsList(ENUM_UPDATES);
1150 break;
1151
1152 case IDS_AVAILABLEFORINST:
1153 UpdateApplicationsList(ENUM_ALL_AVAILABLE);
1154 break;
1155
1156 case IDS_CAT_AUDIO:
1157 UpdateApplicationsList(ENUM_CAT_AUDIO);
1158 break;
1159
1160 case IDS_CAT_DEVEL:
1161 UpdateApplicationsList(ENUM_CAT_DEVEL);
1162 break;
1163
1164 case IDS_CAT_DRIVERS:
1165 UpdateApplicationsList(ENUM_CAT_DRIVERS);
1166 break;
1167
1168 case IDS_CAT_EDU:
1169 UpdateApplicationsList(ENUM_CAT_EDU);
1170 break;
1171
1172 case IDS_CAT_ENGINEER:
1173 UpdateApplicationsList(ENUM_CAT_ENGINEER);
1174 break;
1175
1176 case IDS_CAT_FINANCE:
1177 UpdateApplicationsList(ENUM_CAT_FINANCE);
1178 break;
1179
1180 case IDS_CAT_GAMES:
1181 UpdateApplicationsList(ENUM_CAT_GAMES);
1182 break;
1183
1184 case IDS_CAT_GRAPHICS:
1185 UpdateApplicationsList(ENUM_CAT_GRAPHICS);
1186 break;
1187
1188 case IDS_CAT_INTERNET:
1189 UpdateApplicationsList(ENUM_CAT_INTERNET);
1190 break;
1191
1192 case IDS_CAT_LIBS:
1193 UpdateApplicationsList(ENUM_CAT_LIBS);
1194 break;
1195
1196 case IDS_CAT_OFFICE:
1197 UpdateApplicationsList(ENUM_CAT_OFFICE);
1198 break;
1199
1200 case IDS_CAT_OTHER:
1201 UpdateApplicationsList(ENUM_CAT_OTHER);
1202 break;
1203
1204 case IDS_CAT_SCIENCE:
1205 UpdateApplicationsList(ENUM_CAT_SCIENCE);
1206 break;
1207
1208 case IDS_CAT_TOOLS:
1209 UpdateApplicationsList(ENUM_CAT_TOOLS);
1210 break;
1211
1212 case IDS_CAT_VIDEO:
1213 UpdateApplicationsList(ENUM_CAT_VIDEO);
1214 break;
1215
1216 case IDS_CAT_THEMES:
1217 UpdateApplicationsList(ENUM_CAT_THEMES);
1218 break;
1219
1220 case IDS_SELECTEDFORINST:
1221 UpdateApplicationsList(ENUM_CAT_SELECTED);
1222 break;
1223 }
1224 }
1225
1226 HMENU mainMenu = ::GetMenu(hwnd);
1227 HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
1228
1229 /* Disable/enable items based on treeview selection */
1230 if (IsSelectedNodeInstalled())
1231 {
1232 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_ENABLED);
1233 EnableMenuItem(mainMenu, ID_INSTALL, MF_GRAYED);
1234 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
1235 EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
1236
1237 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
1238 EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
1239 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
1240 EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
1241
1242 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, TRUE);
1243 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, FALSE);
1244 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, TRUE);
1245 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, TRUE);
1246 }
1247 else
1248 {
1249 EnableMenuItem(mainMenu, ID_REGREMOVE, MF_GRAYED);
1250 EnableMenuItem(mainMenu, ID_INSTALL, MF_ENABLED);
1251 EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
1252 EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
1253
1254 EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
1255 EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
1256 EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
1257 EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
1258
1259 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, FALSE);
1260 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
1261 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, FALSE);
1262 m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_MODIFY, FALSE);
1263 }
1264 }
1265 break;
1266
1267 case LVN_ITEMCHANGED:
1268 {
1269 LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
1270
1271 if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
1272 {
1273 /* Check if this is a valid item
1274 * (technically, it can be also an unselect) */
1275 INT ItemIndex = pnic->iItem;
1276 if (ItemIndex == -1 ||
1277 ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
1278 {
1279 break;
1280 }
1281
1282 /* Check if the focus has been moved to another item */
1283 if ((pnic->uChanged & LVIF_STATE) &&
1284 (pnic->uNewState & LVIS_FOCUSED) &&
1285 !(pnic->uOldState & LVIS_FOCUSED))
1286 {
1287 ShowAppInfo(ItemIndex);
1288 }
1289 /* Check if the item is checked */
1290 if ((pnic->uNewState & LVIS_STATEIMAGEMASK) && !bUpdating)
1291 {
1292 BOOL checked = m_ListView->GetCheckState(pnic->iItem);
1293 /* FIXME: HAX!
1294 - preventing decremention below zero as a safeguard for ReactOS
1295 In ReactOS this action is triggered whenever user changes *selection*, but should be only when *checkbox* state toggled
1296 Maybe LVIS_STATEIMAGEMASK is set incorrectly
1297 */
1298 nSelectedApps +=
1299 (checked)
1300 ? 1
1301 : ((nSelectedApps > 0)
1302 ? -1
1303 : 0);
1304
1305 /* Update item's selection status */
1306 m_ListView->SetSelected(pnic->iItem, checked);
1307
1308 UpdateStatusBarText();
1309 }
1310 }
1311 }
1312 break;
1313
1314 case LVN_COLUMNCLICK:
1315 {
1316 LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
1317
1318 m_ListView->ColumnClick(pnmv);
1319 }
1320 break;
1321
1322 case NM_CLICK:
1323 {
1324 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1325 {
1326 ShowAppInfo(-1);
1327 }
1328 }
1329 break;
1330
1331 case NM_DBLCLK:
1332 {
1333 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1334 {
1335 /* this won't do anything if the program is already installed */
1336 SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
1337 }
1338 }
1339 break;
1340
1341 case NM_RCLICK:
1342 {
1343 if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) lParam)->iItem != -1)
1344 {
1345 ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
1346 }
1347 }
1348 break;
1349
1350 case EN_LINK:
1351 OnLink((ENLINK*) lParam);
1352 break;
1353
1354 case TTN_GETDISPINFO:
1355 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
1356 break;
1357 }
1358 }
1359 break;
1360
1361 case WM_SIZE:
1362 OnSize(hwnd, wParam, lParam);
1363 break;
1364
1365 case WM_SIZING:
1366 {
1367 LPRECT pRect = (LPRECT) lParam;
1368
1369 if (pRect->right - pRect->left < 565)
1370 pRect->right = pRect->left + 565;
1371
1372 if (pRect->bottom - pRect->top < 300)
1373 pRect->bottom = pRect->top + 300;
1374
1375 return TRUE;
1376 }
1377
1378 case WM_SYSCOLORCHANGE:
1379 {
1380 /* Forward WM_SYSCOLORCHANGE to common controls */
1381 m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1382 m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1383 m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
1384 m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, GetSysColor(COLOR_BTNFACE));
1385 }
1386 break;
1387
1388 case WM_TIMER:
1389 if (wParam == SEARCH_TIMER_ID)
1390 {
1391 ::KillTimer(hwnd, SEARCH_TIMER_ID);
1392 if (bSearchEnabled)
1393 UpdateApplicationsList(-1);
1394 }
1395 break;
1396 }
1397
1398 return FALSE;
1399 }
1400
1401 virtual VOID OnLink(ENLINK *Link)
1402 {
1403 switch (Link->msg)
1404 {
1405 case WM_LBUTTONUP:
1406 case WM_RBUTTONUP:
1407 {
1408 if (pLink) HeapFree(GetProcessHeap(), 0, pLink);
1409
1410 pLink = (LPWSTR) HeapAlloc(GetProcessHeap(), 0,
1411 (max(Link->chrg.cpMin, Link->chrg.cpMax) -
1412 min(Link->chrg.cpMin, Link->chrg.cpMax) + 1) * sizeof(WCHAR));
1413 if (!pLink)
1414 {
1415 /* TODO: Error message */
1416 return;
1417 }
1418
1419 m_RichEdit->SendMessageW(EM_SETSEL, Link->chrg.cpMin, Link->chrg.cpMax);
1420 m_RichEdit->SendMessageW(EM_GETSELTEXT, 0, (LPARAM) pLink);
1421
1422 ShowPopupMenu(m_RichEdit->m_hWnd, IDR_LINKMENU, -1);
1423 }
1424 break;
1425 }
1426 }
1427
1428 BOOL IsSelectedNodeInstalled()
1429 {
1430 HTREEITEM hSelectedItem = m_TreeView->GetSelection();
1431 TV_ITEM tItem;
1432
1433 tItem.mask = TVIF_PARAM | TVIF_HANDLE;
1434 tItem.hItem = hSelectedItem;
1435 m_TreeView->GetItem(&tItem);
1436 switch (tItem.lParam)
1437 {
1438 case IDS_INSTALLED:
1439 case IDS_APPLICATIONS:
1440 case IDS_UPDATES:
1441 return TRUE;
1442 default:
1443 return FALSE;
1444 }
1445 }
1446
1447 VOID OnCommand(WPARAM wParam, LPARAM lParam)
1448 {
1449 WORD wCommand = LOWORD(wParam);
1450
1451 if (lParam == (LPARAM) m_SearchBar->m_hWnd)
1452 {
1453 ATL::CStringW szBuf;
1454
1455 switch (HIWORD(wParam))
1456 {
1457 case EN_SETFOCUS:
1458 {
1459 ATL::CStringW szWndText;
1460
1461 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1462 m_SearchBar->GetWindowTextW(szWndText);
1463 if (szBuf == szWndText)
1464 {
1465 bSearchEnabled = FALSE;
1466 m_SearchBar->SetWindowTextW(L"");
1467 }
1468 }
1469 break;
1470
1471 case EN_KILLFOCUS:
1472 {
1473 m_SearchBar->GetWindowTextW(szBuf);
1474 if (szBuf.IsEmpty())
1475 {
1476 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1477 bSearchEnabled = FALSE;
1478 m_SearchBar->SetWindowTextW(szBuf.GetString());
1479 }
1480 }
1481 break;
1482
1483 case EN_CHANGE:
1484 {
1485 ATL::CStringW szWndText;
1486
1487 if (!bSearchEnabled)
1488 {
1489 bSearchEnabled = TRUE;
1490 break;
1491 }
1492
1493 szBuf.LoadStringW(IDS_SEARCH_TEXT);
1494 m_SearchBar->GetWindowTextW(szWndText);
1495 if (szBuf == szWndText)
1496 {
1497 szSearchPattern.Empty();
1498 }
1499 else
1500 {
1501 szSearchPattern = szWndText;
1502 }
1503
1504 DWORD dwDelay;
1505 SystemParametersInfoW(SPI_GETMENUSHOWDELAY, 0, &dwDelay, 0);
1506 SetTimer(SEARCH_TIMER_ID, dwDelay);
1507 }
1508 break;
1509 }
1510
1511 return;
1512 }
1513
1514 switch (wCommand)
1515 {
1516 case ID_OPEN_LINK:
1517 ShellExecuteW(m_hWnd, L"open", pLink, NULL, NULL, SW_SHOWNOACTIVATE);
1518 HeapFree(GetProcessHeap(), 0, pLink);
1519 break;
1520
1521 case ID_COPY_LINK:
1522 CopyTextToClipboard(pLink);
1523 HeapFree(GetProcessHeap(), 0, pLink);
1524 break;
1525
1526 case ID_SETTINGS:
1527 CreateSettingsDlg(m_hWnd);
1528 break;
1529
1530 case ID_EXIT:
1531 PostMessageW(WM_CLOSE, 0, 0);
1532 break;
1533
1534 case ID_SEARCH:
1535 ::SetFocus(m_SearchBar->m_hWnd);
1536 break;
1537
1538 case ID_INSTALL:
1539 if (IsAvailableEnum(SelectedEnumType))
1540 {
1541 if (nSelectedApps > 0)
1542 {
1543 DownloadListOfApplications(m_AvailableApps.GetSelected(), FALSE);
1544 UpdateApplicationsList(-1);
1545 m_ListView->SetSelected(-1, FALSE);
1546 }
1547 else if (DownloadApplication(m_ListView->GetSelectedData(), FALSE))
1548 {
1549 UpdateApplicationsList(-1);
1550 }
1551
1552 }
1553 break;
1554
1555 case ID_UNINSTALL:
1556 if (UninstallApplication(-1, FALSE))
1557 UpdateApplicationsList(-1);
1558 break;
1559
1560 case ID_MODIFY:
1561 if (UninstallApplication(-1, TRUE))
1562 UpdateApplicationsList(-1);
1563 break;
1564
1565 case ID_REGREMOVE:
1566 RemoveAppFromRegistry(-1);
1567 break;
1568
1569 case ID_REFRESH:
1570 UpdateApplicationsList(-1);
1571 break;
1572
1573 case ID_RESETDB:
1574 CAvailableApps::ForceUpdateAppsDB();
1575 UpdateApplicationsList(-1);
1576 break;
1577
1578 case ID_HELP:
1579 MessageBoxW(L"Help not implemented yet", NULL, MB_OK);
1580 break;
1581
1582 case ID_ABOUT:
1583 ShowAboutDialog();
1584 break;
1585
1586 case ID_CHECK_ALL:
1587 m_ListView->CheckAll();
1588 break;
1589 }
1590 }
1591
1592 VOID FreeInstalledAppList()
1593 {
1594 INT Count = m_ListView->GetItemCount() - 1;
1595 PINSTALLED_INFO Info;
1596
1597 while (Count >= 0)
1598 {
1599 Info = (PINSTALLED_INFO) ListViewGetlParam(Count);
1600 if (Info)
1601 {
1602 RegCloseKey(Info->hSubKey);
1603 delete Info;
1604 }
1605 Count--;
1606 }
1607 }
1608
1609 static BOOL SearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle)
1610 {
1611 if (!*szNeedle)
1612 return TRUE;
1613 /* TODO: Improve pattern search beyond a simple case-insensitive substring search. */
1614 return StrStrIW(szHaystack, szNeedle) != NULL;
1615 }
1616
1617 BOOL CALLBACK EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName, PINSTALLED_INFO Info)
1618 {
1619 PINSTALLED_INFO ItemInfo;
1620 ATL::CStringW szText;
1621 INT Index;
1622
1623 if (!SearchPatternMatch(m_szName.GetString(), szSearchPattern))
1624 {
1625 RegCloseKey(Info->hSubKey);
1626 return TRUE;
1627 }
1628
1629 ItemInfo = new INSTALLED_INFO(*Info);
1630 if (!ItemInfo)
1631 {
1632 RegCloseKey(Info->hSubKey);
1633 return FALSE;
1634 }
1635
1636 Index = m_ListView->AddItem(ItemIndex, 0, m_szName.GetString(), (LPARAM) ItemInfo);
1637
1638 /* Get version info */
1639 ItemInfo->GetApplicationString(L"DisplayVersion", szText);
1640 m_ListView->SetItemText(Index, 1, szText.GetString());
1641
1642 /* Get comments */
1643 ItemInfo->GetApplicationString(L"Comments", szText);
1644 m_ListView->SetItemText(Index, 2, szText.GetString());
1645
1646 return TRUE;
1647 }
1648
1649 BOOL EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR szFolderPath)
1650 {
1651 INT Index;
1652 HICON hIcon = NULL;
1653
1654 HIMAGELIST hImageListView = ListView_GetImageList(hListView, LVSIL_SMALL);
1655
1656 if (!SearchPatternMatch(Info->m_szName.GetString(), szSearchPattern) &&
1657 !SearchPatternMatch(Info->m_szDesc.GetString(), szSearchPattern))
1658 {
1659 return TRUE;
1660 }
1661
1662 /* Load icon from file */
1663 ATL::CStringW szIconPath;
1664 szIconPath.Format(L"%lsicons\\%ls.ico", szFolderPath, Info->m_szName.GetString());
1665 hIcon = (HICON) LoadImageW(NULL,
1666 szIconPath.GetString(),
1667 IMAGE_ICON,
1668 LISTVIEW_ICON_SIZE,
1669 LISTVIEW_ICON_SIZE,
1670 LR_LOADFROMFILE);
1671
1672 if (!hIcon || GetLastError() != ERROR_SUCCESS)
1673 {
1674 /* Load default icon */
1675 hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1676 }
1677
1678 Index = ImageList_AddIcon(hImageListView, hIcon);
1679 DestroyIcon(hIcon);
1680
1681 Index = m_ListView->AddItem(Info->m_Category, Index, Info->m_szName.GetString(), (LPARAM) Info);
1682 m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1683 m_ListView->SetItemText(Index, 1, Info->m_szVersion.GetString());
1684 m_ListView->SetItemText(Index, 2, Info->m_szDesc.GetString());
1685 m_ListView->SetCheckState(Index, Info->m_IsSelected);
1686
1687 return TRUE;
1688 }
1689
1690 static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName, PINSTALLED_INFO Info, PVOID param)
1691 {
1692 CMainWindow* pThis = (CMainWindow*)param;
1693 return pThis->EnumInstalledAppProc(ItemIndex, m_szName, Info);
1694 }
1695
1696 static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR szFolderPath, PVOID param)
1697 {
1698 CMainWindow* pThis = (CMainWindow*)param;
1699 return pThis->EnumAvailableAppProc(Info, szFolderPath);
1700 }
1701
1702 VOID UpdateStatusBarText()
1703 {
1704 if (m_StatusBar)
1705 {
1706 ATL::CStringW szBuffer;
1707
1708 szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), nSelectedApps);
1709 m_StatusBar->SetText(szBuffer);
1710 }
1711 }
1712
1713 VOID UpdateApplicationsList(INT EnumType)
1714 {
1715 ATL::CStringW szBuffer1, szBuffer2;
1716 HIMAGELIST hImageListView;
1717 BOOL bWasInInstalled = IsInstalledEnum(SelectedEnumType);
1718
1719 bUpdating = TRUE;
1720 m_ListView->SetRedraw(FALSE);
1721
1722 if (EnumType < 0)
1723 {
1724 EnumType = SelectedEnumType;
1725 }
1726
1727 //if previous one was INSTALLED purge the list
1728 //TODO: make the Installed category a separate class to avoid doing this
1729 if (bWasInInstalled)
1730 {
1731 FreeInstalledAppList();
1732 }
1733
1734 m_ListView->DeleteAllItems();
1735
1736 // Create new ImageList
1737 hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
1738 LISTVIEW_ICON_SIZE,
1739 GetSystemColorDepth() | ILC_MASK,
1740 0, 1);
1741 HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
1742 if (hImageListBuf)
1743 {
1744 ImageList_Destroy(hImageListBuf);
1745 }
1746
1747 if (IsInstalledEnum(EnumType))
1748 {
1749 if (!bWasInInstalled)
1750 {
1751 m_ListView->SetCheckboxesVisible(FALSE);
1752 }
1753
1754 HICON hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
1755 ImageList_AddIcon(hImageListView, hIcon);
1756 DestroyIcon(hIcon);
1757
1758 // Enum installed applications and updates
1759 EnumInstalledApplications(EnumType, TRUE, s_EnumInstalledAppProc, this);
1760 EnumInstalledApplications(EnumType, FALSE, s_EnumInstalledAppProc, this);
1761 }
1762 else if (IsAvailableEnum(EnumType))
1763 {
1764 if (bWasInInstalled)
1765 {
1766 m_ListView->SetCheckboxesVisible(TRUE);
1767 }
1768
1769 // Enum available applications
1770 m_AvailableApps.Enum(EnumType, s_EnumAvailableAppProc, this);
1771 }
1772
1773 SelectedEnumType = EnumType;
1774 UpdateStatusBarText();
1775 m_RichEdit->SetWelcomeText();
1776
1777 // Set automatic column width for program names if the list is not empty
1778 if (m_ListView->GetItemCount() > 0)
1779 {
1780 ListView_SetColumnWidth(m_ListView->GetWindow(), 0, LVSCW_AUTOSIZE);
1781 }
1782
1783 bUpdating = FALSE;
1784 m_ListView->SetRedraw(TRUE);
1785 }
1786
1787 public:
1788 static ATL::CWndClassInfo& GetWndClassInfo()
1789 {
1790 DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
1791 static ATL::CWndClassInfo wc =
1792 {
1793 {
1794 sizeof(WNDCLASSEX),
1795 csStyle,
1796 StartWindowProc,
1797 0,
1798 0,
1799 NULL,
1800 LoadIconW(_AtlBaseModule.GetModuleInstance(), MAKEINTRESOURCEW(IDI_MAIN)),
1801 LoadCursorW(NULL, IDC_ARROW),
1802 (HBRUSH) (COLOR_BTNFACE + 1),
1803 MAKEINTRESOURCEW(IDR_MAINMENU),
1804 L"RAppsWnd",
1805 NULL
1806 },
1807 NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
1808 };
1809 return wc;
1810 }
1811
1812 HWND Create()
1813 {
1814 ATL::CStringW szWindowName;
1815 szWindowName.LoadStringW(IDS_APPTITLE);
1816
1817 RECT r = {
1818 (SettingsInfo.bSaveWndPos ? SettingsInfo.Left : CW_USEDEFAULT),
1819 (SettingsInfo.bSaveWndPos ? SettingsInfo.Top : CW_USEDEFAULT),
1820 (SettingsInfo.bSaveWndPos ? SettingsInfo.Width : 680),
1821 (SettingsInfo.bSaveWndPos ? SettingsInfo.Height : 450)
1822 };
1823 r.right += r.left;
1824 r.bottom += r.top;
1825
1826 return CWindowImpl::Create(NULL, r, szWindowName.GetString(), WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
1827 }
1828
1829 CStatusBar * GetStatusBar()
1830 {
1831 return m_StatusBar;
1832 }
1833
1834 CAppsListView * GetListView()
1835 {
1836 return m_ListView;
1837 }
1838
1839 CRichEdit * GetRichEdit()
1840 {
1841 return m_RichEdit;
1842 }
1843
1844 CAvailableApps * GetAvailableApps()
1845 {
1846 return &m_AvailableApps;
1847 }
1848 };
1849
1850 // global interface
1851 CMainWindow * g_MainWindow;
1852
1853 HWND CreateMainWindow()
1854 {
1855 g_MainWindow = new CMainWindow();
1856 return g_MainWindow->Create();
1857 }
1858
1859 DWORD_PTR ListViewGetlParam(INT item)
1860 {
1861 if (item < 0)
1862 {
1863 item = g_MainWindow->GetListView()->GetSelectionMark();
1864 }
1865 return g_MainWindow->GetListView()->GetItemData(item);
1866 }
1867
1868 VOID SetStatusBarText(LPCWSTR szText)
1869 {
1870 g_MainWindow->GetStatusBar()->SetText(szText);
1871 }
1872
1873 INT ListViewAddItem(INT ItemIndex, INT IconIndex, LPWSTR lpName, LPARAM lParam)
1874 {
1875 return g_MainWindow->GetListView()->AddItem(ItemIndex, IconIndex, lpName, lParam);
1876 }
1877
1878 VOID NewRichEditText(LPCWSTR szText, DWORD flags)
1879 {
1880 g_MainWindow->GetRichEdit()->SetText(szText, flags);
1881 }
1882
1883 VOID InsertRichEditText(LPCWSTR szText, DWORD flags)
1884 {
1885 g_MainWindow->GetRichEdit()->InsertText(szText, flags);
1886 }
1887
1888 CAvailableApps* GetAvailableApps()
1889 {
1890 return g_MainWindow->GetAvailableApps();
1891 }
1892
1893 // ATL version of functions above
1894 VOID SetStatusBarText(const ATL::CStringW& szText)
1895 {
1896 SetStatusBarText(szText.GetString());
1897 }
1898
1899 INT ListViewAddItem(INT ItemIndex, INT IconIndex, const ATL::CStringW& Name, LPARAM lParam)
1900 {
1901 return ListViewAddItem(ItemIndex, IconIndex, const_cast<LPWSTR>(Name.GetString()), lParam);
1902 }
1903
1904 VOID NewRichEditText(const ATL::CStringW& szText, DWORD flags)
1905 {
1906 NewRichEditText(szText.GetString(), flags);
1907 }
1908
1909 VOID InsertRichEditText(const ATL::CStringW& szText, DWORD flags)
1910 {
1911 InsertRichEditText(szText.GetString(), flags);
1912 }
1913
1914 VOID ShowMainWindow(INT nShowCmd)
1915 {
1916 HACCEL KeyBrd;
1917 MSG Msg;
1918
1919 hMainWnd = CreateMainWindow();
1920
1921 if (hMainWnd)
1922 {
1923 /* Maximize it if we must */
1924 ShowWindow(hMainWnd, ((SettingsInfo.bSaveWndPos && SettingsInfo.Maximized) ? SW_MAXIMIZE : nShowCmd));
1925 UpdateWindow(hMainWnd);
1926
1927 /* Load the menu hotkeys */
1928 KeyBrd = LoadAcceleratorsW(NULL, MAKEINTRESOURCEW(HOTKEYS));
1929
1930 /* Message Loop */
1931 while (GetMessageW(&Msg, NULL, 0, 0))
1932 {
1933 if (!TranslateAcceleratorW(hMainWnd, KeyBrd, &Msg))
1934 {
1935 TranslateMessage(&Msg);
1936 DispatchMessageW(&Msg);
1937 }
1938 }
1939 }
1940 }