https://git.reactos.org/?p=reactos.git;a=commitdiff;h=10c0ff7416d6e8066c170bb3abdfb22303c472ed

commit 10c0ff7416d6e8066c170bb3abdfb22303c472ed
Author:     He Yang <[email protected]>
AuthorDate: Tue Jul 21 22:13:39 2020 +0800
Commit:     Mark Jansen <[email protected]>
CommitDate: Sun Sep 6 17:09:20 2020 +0200

    [RAPPS] listview refactor (#2970)
    
    This makes it easier to maintain the listview, and better separates the 
application list and listview.
    
    * [RAPPS] fix memory leak when cleanup. some renaming are also done
    * [RAPPS] move the code adding apps info inside class CAppsListView
    * [RAPPS] add table view, create listview and AppInfoDisplay inside it
    * [RAPPS] rename INSTALLED_INFO as CInstalledApplicationInfo
    now it corresponds with CAvailableApplicationInfo
    * [RAPPS] add CInstalledApps
    * [RAPPS] optimize the speed when refreshing listview
    * [RAPPS] correctly handle Enum for InstalledApps
    * [RAPPS] make check all working properly (this also fixes some bugs)
    the old version has some bugs when check all items after switching tags in 
tree-view
    * [RAPPS] add handling for wow64
    * [RAPPS] use an inline function to replace INSERT_TEXT macro
    * [RAPPS] fix the bug that StatusBar won't update when switching tags
    * [RAPPS] now TableView always reset bIsAscending in SetDisplayMode
    * [RAPPS] rename TableView to ApplicationView
    * [RAPPS] now bIsAscending would be reset when switching column in listview
---
 base/applications/rapps/available.cpp       |  169 ++--
 base/applications/rapps/gui.cpp             | 1335 ++++++++++++++++-----------
 base/applications/rapps/include/available.h |   16 +-
 base/applications/rapps/include/installed.h |   46 +-
 base/applications/rapps/include/misc.h      |    2 +
 base/applications/rapps/include/rosui.h     |    5 +-
 base/applications/rapps/installed.cpp       |  306 ++++--
 base/applications/rapps/misc.cpp            |   33 +
 8 files changed, 1203 insertions(+), 709 deletions(-)

diff --git a/base/applications/rapps/available.cpp 
b/base/applications/rapps/available.cpp
index 8af6c78a8b9..62d4585d3a5 100644
--- a/base/applications/rapps/available.cpp
+++ b/base/applications/rapps/available.cpp
@@ -19,7 +19,7 @@
 
  // CAvailableApplicationInfo
 CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW& 
sFileNameParam, AvailableStrings& AvlbStrings)
-    : m_IsSelected(FALSE), m_LicenseType(LICENSE_NONE), m_SizeBytes(0), 
m_sFileName(sFileNameParam),
+    : m_LicenseType(LICENSE_NONE), m_SizeBytes(0), m_sFileName(sFileNameParam),
     m_IsInstalled(FALSE), m_HasLanguageInfo(FALSE), 
m_HasInstalledVersion(FALSE)
 {
     RetrieveGeneralInfo(AvlbStrings);
@@ -400,71 +400,127 @@ BOOL CAvailableApps::ForceUpdateAppsDB()
 
 BOOL CAvailableApps::Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param)
 {
+    if (EnumType == ENUM_CAT_SELECTED)
+    {
+        CAvailableApplicationInfo *EnumAvlbInfo = NULL;
 
-    HANDLE hFind = INVALID_HANDLE_VALUE;
-    WIN32_FIND_DATAW FindFileData;
-
-    hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), &FindFileData);
+        // enum all object in m_SelectedList and invoke callback
+        for(POSITION CurrentPosition = m_SelectedList.GetHeadPosition();
+            CurrentPosition && (EnumAvlbInfo = 
m_SelectedList.GetAt(CurrentPosition));
+            m_SelectedList.GetNext(CurrentPosition))
+        {
+            EnumAvlbInfo->RefreshAppInfo(m_Strings);
 
-    if (hFind == INVALID_HANDLE_VALUE)
-    {
-        //no db yet
-        return FALSE;
+            if (lpEnumProc)
+                lpEnumProc(EnumAvlbInfo, TRUE, param);
+        }
+        return TRUE;
     }
-
-    do
+    else
     {
-        // loop for all the cached entries
-        POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
-        CAvailableApplicationInfo* Info = NULL;
+        HANDLE hFind = INVALID_HANDLE_VALUE;
+        WIN32_FIND_DATAW FindFileData;
+
+        hFind = FindFirstFileW(m_Strings.szSearchPath.GetString(), 
&FindFileData);
+
+        if (hFind == INVALID_HANDLE_VALUE)
+        {
+            //no db yet
+            return FALSE;
+        }
 
-        while (CurrentListPosition != NULL)
+        do
         {
-            POSITION LastListPosition = CurrentListPosition;
-            Info = m_InfoList.GetNext(CurrentListPosition);
+            // loop for all the cached entries
+            POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
+            CAvailableApplicationInfo *Info = NULL;
 
-            // do we already have this entry in cache?
-            if (Info->m_sFileName == FindFileData.cFileName)
+            while (CurrentListPosition != NULL)
             {
-                // is it current enough, or the file has been modified since 
our last time here?
-                if (CompareFileTime(&FindFileData.ftLastWriteTime, 
&Info->m_ftCacheStamp) == 1)
-                {
-                    // recreate our cache, this is the slow path
-                    m_InfoList.RemoveAt(LastListPosition);
+                POSITION LastListPosition = CurrentListPosition;
+                Info = m_InfoList.GetNext(CurrentListPosition);
 
-                    delete Info;
-                    Info = NULL;
-                    break;
+                // do we already have this entry in cache?
+                if (Info->m_sFileName == FindFileData.cFileName)
+                {
+                    // is it current enough, or the file has been modified 
since our last time here?
+                    if (CompareFileTime(&FindFileData.ftLastWriteTime, 
&Info->m_ftCacheStamp) == 1)
+                    {
+                        // recreate our cache, this is the slow path
+                        m_InfoList.RemoveAt(LastListPosition);
+
+                        // also remove this in selected list (if exist)
+                        RemoveSelected(Info);
+
+                        delete Info;
+                        Info = NULL;
+                        break;
+                    }
+                    else
+                    {
+                        // speedy path, compare directly, we already have the 
data
+                        goto skip_if_cached;
+                    }
                 }
-                else
+            }
+
+            // create a new entry
+            Info = new CAvailableApplicationInfo(FindFileData.cFileName, 
m_Strings);
+
+            // set a timestamp for the next time
+            Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
+            m_InfoList.AddTail(Info);
+
+        skip_if_cached:
+            if (EnumType == Info->m_Category
+                || EnumType == ENUM_ALL_AVAILABLE)
+            {
+                Info->RefreshAppInfo(m_Strings);
+
+                if (lpEnumProc)
                 {
-                    // speedy path, compare directly, we already have the data
-                    goto skip_if_cached;
+                    if (m_SelectedList.Find(Info))
+                    {
+                        lpEnumProc(Info, TRUE, param);
+                    }
+                    else
+                    {
+                        lpEnumProc(Info, FALSE, param);
+                    }
                 }
             }
-        }
+        } while (FindNextFileW(hFind, &FindFileData));
 
-        // create a new entry
-        Info = new CAvailableApplicationInfo(FindFileData.cFileName, 
m_Strings);
+        FindClose(hFind);
+        return TRUE;
+    }
+}
 
-        // set a timestamp for the next time
-        Info->SetLastWriteTime(&FindFileData.ftLastWriteTime);
-        m_InfoList.AddTail(Info);
+BOOL CAvailableApps::AddSelected(CAvailableApplicationInfo *AvlbInfo)
+{
+        return m_SelectedList.AddTail(AvlbInfo) != 0;
+}
 
-skip_if_cached:
-        if (EnumType == Info->m_Category
-            || EnumType == ENUM_ALL_AVAILABLE
-            || (EnumType == ENUM_CAT_SELECTED && Info->m_IsSelected))
-        {
-            Info->RefreshAppInfo(m_Strings);
+BOOL CAvailableApps::RemoveSelected(CAvailableApplicationInfo *AvlbInfo)
+{
+    POSITION Position = m_SelectedList.Find(AvlbInfo);
+    if (Position)
+    {
+        m_SelectedList.RemoveAt(Position);
+        return TRUE;
+    }
+    return FALSE;
+}
 
-            if (lpEnumProc)
-                lpEnumProc(Info, m_Strings.szAppsPath.GetString(), param);
-        }
-    } while (FindNextFileW(hFind, &FindFileData) != 0);
+VOID CAvailableApps::RemoveAllSelected()
+{
+    m_SelectedList.RemoveAll();
+    return;
+}
 
-    FindClose(hFind);
-    return TRUE;
+int CAvailableApps::GetSelectedCount()
+{
+    return m_SelectedList.GetCount();
 }
 
 CAvailableApplicationInfo* CAvailableApps::FindInfo(const ATL::CStringW& 
szAppName) const
@@ -502,23 +558,6 @@ ATL::CSimpleArray<CAvailableApplicationInfo> 
CAvailableApps::FindInfoList(const
     return result;
 }
 
-ATL::CSimpleArray<CAvailableApplicationInfo> CAvailableApps::GetSelected() 
const
-{
-    ATL::CSimpleArray<CAvailableApplicationInfo> result;
-    POSITION CurrentListPosition = m_InfoList.GetHeadPosition();
-    CAvailableApplicationInfo* Info;
-
-    while (CurrentListPosition != NULL)
-    {
-        Info = m_InfoList.GetNext(CurrentListPosition);
-        if (Info->m_IsSelected)
-        {
-            result.Add(*Info);
-        }
-    }
-    return result;
-}
-
 const ATL::CStringW& CAvailableApps::GetFolderPath() const
 {
     return m_Strings.szPath;
diff --git a/base/applications/rapps/gui.cpp b/base/applications/rapps/gui.cpp
index b0599074a47..e3aeccc579f 100644
--- a/base/applications/rapps/gui.cpp
+++ b/base/applications/rapps/gui.cpp
@@ -65,6 +65,21 @@ enum SCRNSHOT_STATUS
 
 #define PI 3.1415927
 
+// retrieve the value using a mask
+#define STATEIMAGETOINDEX(x) (((x) & LVIS_STATEIMAGEMASK) >> 12)
+
+// for listview with extend style LVS_EX_CHECKBOXES, State image 1 is the 
unchecked box, and state image 2 is the checked box.
+// see this: 
https://docs.microsoft.com/en-us/windows/win32/controls/extended-list-view-styles
+#define STATEIMAGE_UNCHECKED 1
+#define STATEIMAGE_CHECKED 2
+
+enum APPLICATION_VIEW_MODE
+{
+    ApplicationViewEmpty,
+    ApplicationViewAvailableApps,
+    ApplicationViewInstalledApps
+};
+
 typedef struct __ScrnshotDownloadParam
 {
     LONGLONG ID;
@@ -73,6 +88,8 @@ typedef struct __ScrnshotDownloadParam
     ATL::CStringW DownloadFileName;
 } ScrnshotDownloadParam;
 
+class CMainWindow;
+
 INT GetSystemColorDepth()
 {
     DEVMODEW pDevMode;
@@ -250,41 +267,37 @@ public:
         return TRUE;
     }
 
-    BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
+    inline VOID InsertTextWithString(UINT StringID, DWORD StringFlags, const 
ATL::CStringW& Text, DWORD TextFlags)
     {
-        ATL::CStringW szText;
-        ATL::CStringW szInfo;
+        if (!Text.IsEmpty())
+        {
+            LoadAndInsertText(StringID, Text, StringFlags, TextFlags);
+        }
+    }
 
-        if (!Info || !Info->hSubKey)
-            return FALSE;
+    BOOL ShowInstalledAppInfo(CInstalledApplicationInfo * Info)
+    {
+        if (!Info) return FALSE;
 
-        Info->GetApplicationString(L"DisplayName", szText);
-        SetText(szText, CFE_BOLD);
+        SetText(Info->szDisplayName, CFE_BOLD);
         InsertText(L"\n", 0);
 
-#define GET_INFO(a, b, c, d) \
-    if (Info->GetApplicationString(a, szInfo)) \
-    { \
-        LoadAndInsertText(b, szInfo, c, d); \
-    }
-
-        GET_INFO(L"DisplayVersion", IDS_INFO_VERSION, CFE_BOLD, 0);
-        GET_INFO(L"Publisher", IDS_INFO_PUBLISHER, CFE_BOLD, 0);
-        GET_INFO(L"RegOwner", IDS_INFO_REGOWNER, CFE_BOLD, 0);
-        GET_INFO(L"ProductID", IDS_INFO_PRODUCTID, CFE_BOLD, 0);
-        GET_INFO(L"HelpLink", IDS_INFO_HELPLINK, CFE_BOLD, CFM_LINK);
-        GET_INFO(L"HelpTelephone", IDS_INFO_HELPPHONE, CFE_BOLD, 0);
-        GET_INFO(L"Readme", IDS_INFO_README, CFE_BOLD, 0);
-        GET_INFO(L"Contact", IDS_INFO_CONTACT, CFE_BOLD, 0);
-        GET_INFO(L"URLUpdateInfo", IDS_INFO_UPDATEINFO, CFE_BOLD, CFM_LINK);
-        GET_INFO(L"URLInfoAbout", IDS_INFO_INFOABOUT, CFE_BOLD, CFM_LINK);
-        GET_INFO(L"Comments", IDS_INFO_COMMENTS, CFE_BOLD, 0);
-        GET_INFO(L"InstallDate", IDS_INFO_INSTALLDATE, CFE_BOLD, 0);
-        GET_INFO(L"InstallLocation", IDS_INFO_INSTLOCATION, CFE_BOLD, 0);
-        GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
-        GET_INFO(L"UninstallString", IDS_INFO_UNINSTALLSTR, CFE_BOLD, 0);
-        GET_INFO(L"InstallSource", IDS_INFO_INSTALLSRC, CFE_BOLD, 0);
-        GET_INFO(L"ModifyPath", IDS_INFO_MODIFYPATH, CFE_BOLD, 0);
+        InsertTextWithString(IDS_INFO_VERSION, CFE_BOLD, 
Info->szDisplayVersion, 0);
+        InsertTextWithString(IDS_INFO_PUBLISHER, CFE_BOLD, Info->szPublisher, 
0);
+        InsertTextWithString(IDS_INFO_REGOWNER, CFE_BOLD, Info->szRegOwner, 0);
+        InsertTextWithString(IDS_INFO_PRODUCTID, CFE_BOLD, Info->szProductID, 
0);
+        InsertTextWithString(IDS_INFO_HELPLINK, CFE_BOLD, Info->szHelpLink, 
CFM_LINK);
+        InsertTextWithString(IDS_INFO_HELPPHONE, CFE_BOLD, 
Info->szHelpTelephone, 0);
+        InsertTextWithString(IDS_INFO_README, CFE_BOLD, Info->szReadme, 0);
+        InsertTextWithString(IDS_INFO_CONTACT, CFE_BOLD, Info->szContact, 0);
+        InsertTextWithString(IDS_INFO_UPDATEINFO, CFE_BOLD, 
Info->szURLUpdateInfo, CFM_LINK);
+        InsertTextWithString(IDS_INFO_INFOABOUT, CFE_BOLD, 
Info->szURLInfoAbout, CFM_LINK);
+        InsertTextWithString(IDS_INFO_COMMENTS, CFE_BOLD, Info->szComments, 0);
+        InsertTextWithString(IDS_INFO_INSTALLDATE, CFE_BOLD, 
Info->szInstallDate, 0);
+        InsertTextWithString(IDS_INFO_INSTLOCATION, CFE_BOLD, 
Info->szInstallLocation, 0);
+        InsertTextWithString(IDS_INFO_INSTALLSRC, CFE_BOLD, 
Info->szInstallSource, 0);
+        InsertTextWithString(IDS_INFO_UNINSTALLSTR, CFE_BOLD, 
Info->szUninstallString, 0);
+        InsertTextWithString(IDS_INFO_MODIFYPATH, CFE_BOLD, 
Info->szModifyPath, 0);
 
         return TRUE;
     }
@@ -908,8 +921,8 @@ private:
 
 public:
 
-    CAppRichEdit * RichEdit;
-    CAppScrnshotPreview * ScrnshotPrev;
+    CAppRichEdit * RichEdit = NULL;
+    CAppScrnshotPreview * ScrnshotPrev = NULL;
 
     static ATL::CWndClassInfo& GetWndClassInfo()
     {
@@ -957,7 +970,7 @@ public:
         return RichEdit->ShowAvailableAppInfo(Info);
     }
 
-    BOOL ShowInstalledAppInfo(PINSTALLED_INFO Info)
+    BOOL ShowInstalledAppInfo(CInstalledApplicationInfo * Info)
     {
         ScrnshotPrev->DisplayEmpty();
         ResizeChildren();
@@ -993,6 +1006,11 @@ public:
         }
     }
 
+    ~CAppInfoDisplay()
+    {
+        delete RichEdit;
+        delete ScrnshotPrev;
+    }
 };
 
 class CMainToolbar :
@@ -1177,16 +1195,19 @@ class CAppsListView :
         INT iSubItem;
     };
 
-    BOOL bHasAllChecked;
-    BOOL bIsAscending;
+    BOOL bIsAscending = TRUE;
     BOOL bHasCheckboxes;
 
+    INT ItemCount = 0;
+    INT CheckedItemCount = 0;
+    INT ColumnCount = 0;
+
     INT nLastHeaderID;
 
+    APPLICATION_VIEW_MODE ApplicationViewMode = ApplicationViewEmpty;
+
 public:
     CAppsListView() :
-        bHasAllChecked(FALSE),
-        bIsAscending(TRUE),
         bHasCheckboxes(FALSE),
         nLastHeaderID(-1)
     {
@@ -1221,6 +1242,7 @@ public:
         /* If the sorting column changed, remove the sorting style from the 
old column */
         if ((nLastHeaderID != -1) && (nLastHeaderID != nHeaderID))
         {
+            bIsAscending = TRUE; // also reset sorting method to ascending
             hColumn.mask = HDI_FORMAT;
             Header_GetItem(hHeader, nLastHeaderID, &hColumn);
             hColumn.fmt &= ~(HDF_SORTUP | HDF_SORTDOWN);
@@ -1249,7 +1271,7 @@ public:
         return AddColumn(Index, const_cast<LPWSTR>(Text.GetString()), Width, 
Format);
     }
 
-    BOOL AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
+    int AddColumn(INT Index, LPWSTR lpText, INT Width, INT Format)
     {
         LVCOLUMNW Column;
 
@@ -1261,7 +1283,13 @@ public:
         Column.cx = Width;
         Column.fmt = Format;
 
-        return (InsertColumn(Index, &Column) == -1) ? FALSE : TRUE;
+        return SendMessage(LVM_INSERTCOLUMN, Index, (LPARAM)(&Column));
+    }
+
+    void DeleteColumn(INT Index)
+    {
+        SendMessage(LVM_DELETECOLUMN, Index, 0);
+        return;
     }
 
     INT AddItem(INT ItemIndex, INT IconIndex, LPCWSTR lpText, LPARAM lParam)
@@ -1270,15 +1298,25 @@ public:
 
         ZeroMemory(&Item, sizeof(Item));
 
-        Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
+        Item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
         Item.pszText = const_cast<LPWSTR>(lpText);
         Item.lParam = lParam;
         Item.iItem = ItemIndex;
         Item.iImage = IconIndex;
 
+        if (IconIndex >= 0)
+        {
+            Item.iImage = IconIndex;
+            Item.mask |= LVIF_IMAGE;
+        }
         return InsertItem(&Item);
     }
 
+    HIMAGELIST GetImageList(int iImageList)
+    {
+        return (HIMAGELIST)SendMessage(LVM_GETIMAGELIST, iImageList, 0);
+    }
+
     static INT CALLBACK s_CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM 
lParamSort)
     {
         SortContext * ctx = ((SortContext*) lParamSort);
@@ -1319,6 +1357,12 @@ public:
             SetCheckboxesVisible(FALSE);
         }
 
+        HIMAGELIST hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
+                                                  LISTVIEW_ICON_SIZE,
+                                                  GetSystemColorDepth() | 
ILC_MASK,
+                                                  0, 1);
+        SetImageList(hImageListView, LVSIL_SMALL);
+
         return hwnd;
     }
 
@@ -1332,219 +1376,656 @@ public:
         if (bHasCheckboxes)
         {
             SetItemState(item, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), 
LVIS_STATEIMAGEMASK);
-            SetSelected(item, fCheck);
         }
     }
 
-    VOID SetSelected(INT item, BOOL value)
+    VOID CheckAll()
     {
-        if (item < 0)
+        if (bHasCheckboxes)
         {
-            for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
+            if (CheckedItemCount == ItemCount)
             {
-                CAvailableApplicationInfo* pAppInfo = 
(CAvailableApplicationInfo*) GetItemData(i);
-                if (pAppInfo)
-                {
-                    pAppInfo->m_IsSelected = value;
-                }
+                // clear all
+                SetCheckState(-1, FALSE);
             }
-        }
-        else
-        {
-            CAvailableApplicationInfo* pAppInfo = (CAvailableApplicationInfo*) 
GetItemData(item);
-            if (pAppInfo)
+            else
             {
-                pAppInfo->m_IsSelected = value;
+                // check all
+                SetCheckState(-1, TRUE);
             }
         }
     }
-
-    VOID CheckAll()
+    
+    PVOID GetFocusedItemData()
     {
-        if (bHasCheckboxes)
+        INT item = GetSelectionMark();
+        if (item == -1)
         {
-            bHasAllChecked = !bHasAllChecked;
-            SetCheckState(-1, bHasAllChecked);
+            return (PVOID)0;
         }
+        return (PVOID)GetItemData(item);
     }
 
-    ATL::CSimpleArray<CAvailableApplicationInfo> GetCheckedItems()
+    BOOL SetDisplayMode(APPLICATION_VIEW_MODE Mode)
     {
-        if (!bHasCheckboxes)
+        if (!DeleteAllItems()) return FALSE;
+        ApplicationViewMode = Mode;
+
+        bIsAscending = TRUE;
+        
+        ItemCount = 0;
+        CheckedItemCount = 0;
+
+        // delete old columns
+        while (ColumnCount)
         {
-            return ATL::CSimpleArray<CAvailableApplicationInfo>();
+            DeleteColumn(--ColumnCount);
         }
 
-        ATL::CSimpleArray<CAvailableApplicationInfo> list;
-        for (INT i = 0; i >= 0; i = GetNextItem(i, LVNI_ALL))
+        ImageList_RemoveAll(GetImageList(LVSIL_SMALL));
+
+        // add new columns
+        ATL::CStringW szText;
+        switch (Mode)
         {
-            if (GetCheckState(i) != FALSE)
-            {
-                CAvailableApplicationInfo* pAppInfo = 
(CAvailableApplicationInfo*) GetItemData(i);
-                list.Add(*pAppInfo);
-            }
+        case ApplicationViewInstalledApps:
+
+            /* Add columns to ListView */
+            szText.LoadStringW(IDS_APP_NAME);
+            AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
+
+            szText.LoadStringW(IDS_APP_INST_VERSION);
+            AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
+
+            szText.LoadStringW(IDS_APP_DESCRIPTION);
+            AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
+
+            // disable checkboxes
+            SetCheckboxesVisible(FALSE);
+            break;
+
+        case ApplicationViewAvailableApps:
+
+            /* Add columns to ListView */
+            szText.LoadStringW(IDS_APP_NAME);
+            AddColumn(ColumnCount++, szText, 250, LVCFMT_LEFT);
+
+            szText.LoadStringW(IDS_APP_INST_VERSION);
+            AddColumn(ColumnCount++, szText, 90, LVCFMT_RIGHT);
+
+            szText.LoadStringW(IDS_APP_DESCRIPTION);
+            AddColumn(ColumnCount++, szText, 300, LVCFMT_LEFT);
+
+            // enable checkboxes
+            SetCheckboxesVisible(TRUE);
+            break;
+
+        case ApplicationViewEmpty:
+        default:
+            break;
         }
-        return list;
+
+        
+        return TRUE;
     }
 
-    CAvailableApplicationInfo* GetSelectedData()
+    BOOL AddInstalledApplication(CInstalledApplicationInfo *InstAppInfo, 
LPVOID CallbackParam)
     {
-        INT item = GetSelectionMark();
-        return (CAvailableApplicationInfo*) GetItemData(item);
-    }
-};
+        if (ApplicationViewMode != ApplicationViewInstalledApps)
+        {
+            return FALSE;
+        }
 
-class CSideTreeView :
-    public CUiWindow<CTreeView>
-{
-    HIMAGELIST hImageTreeView;
+        HICON hIcon = (HICON)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
+        HIMAGELIST hImageList = GetImageList(LVSIL_SMALL);
+        int IconIndex = ImageList_AddIcon(hImageList, hIcon);
+        DestroyIcon(hIcon);
 
-public:
-    CSideTreeView() :
-        CUiWindow(),
-        hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
-                                        GetSystemColorDepth() | ILC_MASK,
-                                        0, 1))
-    {
-    }
+        int Index = AddItem(ItemCount, IconIndex, InstAppInfo->szDisplayName, 
(LPARAM)CallbackParam);
+        SetItemText(Index, 1, InstAppInfo->szDisplayVersion.IsEmpty() ? L"---" 
: InstAppInfo->szDisplayVersion);
+        SetItemText(Index, 2, InstAppInfo->szComments.IsEmpty() ? L"---" : 
InstAppInfo->szComments);
 
-    HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT 
SelectedImage, LPARAM lParam)
-    {
-        return CUiWindow<CTreeView>::AddItem(hParent, 
const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
+        ItemCount++;
+        return TRUE;
     }
 
-    HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
+    BOOL AddAvailableApplication(CAvailableApplicationInfo *AvlbAppInfo, BOOL 
InitCheckState, LPVOID CallbackParam)
     {
-        ATL::CStringW szText;
-        INT Index;
-        HICON hIcon;
+        if (ApplicationViewMode != ApplicationViewAvailableApps)
+        {
+            return FALSE;
+        }
 
-        hIcon = (HICON) LoadImageW(hInst,
-                                   MAKEINTRESOURCE(IconIndex),
-                                   IMAGE_ICON,
-                                   TREEVIEW_ICON_SIZE,
-                                   TREEVIEW_ICON_SIZE,
-                                   LR_CREATEDIBSECTION);
-        if (hIcon)
+        /* Load icon from file */
+        HICON hIcon = NULL;
+        ATL::CStringW szIconPath;
+        if (AvlbAppInfo->RetrieveIcon(szIconPath))
         {
-            Index = ImageList_AddIcon(hImageTreeView, hIcon);
-            DestroyIcon(hIcon);
+            hIcon = (HICON)LoadImageW(NULL,
+                szIconPath.GetString(),
+                IMAGE_ICON,
+                LISTVIEW_ICON_SIZE,
+                LISTVIEW_ICON_SIZE,
+                LR_LOADFROMFILE);
         }
 
-        szText.LoadStringW(TextIndex);
-        return AddItem(hRootItem, szText, Index, Index, TextIndex);
-    }
+        if (!hIcon || GetLastError() != ERROR_SUCCESS)
+        {
+            /* Load default icon */
+            hIcon = (HICON)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
+        }
 
-    HIMAGELIST SetImageList()
-    {
-        return CUiWindow<CTreeView>::SetImageList(hImageTreeView, 
TVSIL_NORMAL);
-    }
+        HIMAGELIST hImageList = GetImageList(LVSIL_SMALL);
 
-    VOID DestroyImageList()
-    {
-        if (hImageTreeView)
-            ImageList_Destroy(hImageTreeView);
-    }
+        int IconIndex = ImageList_AddIcon(hImageList, hIcon);
+        DestroyIcon(hIcon);
 
-    ~CSideTreeView()
-    {
-        DestroyImageList();
-    }
-};
+        int Index = AddItem(ItemCount, IconIndex, AvlbAppInfo->m_szName, 
(LPARAM)CallbackParam);
 
-class CSearchBar :
-    public CWindow
-{
-public:
-    const INT m_Width;
-    const INT m_Height;
+        if (InitCheckState)
+        {
+            SetCheckState(Index, TRUE);
+        }
 
-    CSearchBar() : m_Width(200), m_Height(22)
-    {
-    }
+        SetItemText(Index, 1, AvlbAppInfo->m_szVersion);
+        SetItemText(Index, 2, AvlbAppInfo->m_szDesc);
 
-    VOID SetText(LPCWSTR lpszText)
-    {
-        SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
+        ItemCount++;
+        return TRUE;
     }
 
-    HWND Create(HWND hwndParent)
+    // this function is called when parent window receiving an notification 
about checkstate changing
+    VOID ItemCheckStateNotify(int iItem, BOOL bCheck)
     {
-        ATL::CStringW szBuf;
-        m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
-                                 WS_CHILD | WS_VISIBLE | ES_LEFT | 
ES_AUTOHSCROLL,
-                                 0, 0, m_Width, m_Height,
-                                 hwndParent, (HMENU) NULL,
-                                 hInst, 0);
-
-        SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
-        szBuf.LoadStringW(IDS_SEARCH_TEXT);
-        SetWindowTextW(szBuf);
-        return m_hWnd;
+        if (bCheck)
+        {
+            CheckedItemCount++;
+        }
+        else
+        {
+            CheckedItemCount--;
+        }
     }
-
 };
 
-class CMainWindow :
-    public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
+class CApplicationView :
+    public CUiWindow<CWindowImpl<CApplicationView>>
 {
-    CUiPanel* m_ClientPanel;
-    CUiSplitPanel* m_VSplitter;
-    CUiSplitPanel* m_HSplitter;
+private:
+    CUiPanel *m_Panel = NULL;
 
-    CMainToolbar* m_Toolbar;
-    CAppsListView* m_ListView;
+    CAppsListView *m_ListView = NULL;
+    CAppInfoDisplay *m_AppsInfo = NULL;
+    CUiSplitPanel *m_HSplitter = NULL;
+    CMainWindow *m_MainWindow = NULL;
+    APPLICATION_VIEW_MODE ApplicationViewMode = ApplicationViewEmpty;
 
-    CSideTreeView* m_TreeView;
-    CUiWindow<CStatusBar>* m_StatusBar;
-    CAppInfoDisplay* m_AppInfo;
+    BOOL ProcessWindowMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM 
lParam, LRESULT& theResult, DWORD dwMapId)
+    {
+        theResult = 0;
+        switch (message)
+        {
+        case WM_CREATE:
+        {
+            BOOL bSuccess = TRUE;
+            m_Panel = new CUiPanel();
+            m_Panel->m_VerticalAlignment = UiAlign_Stretch;
+            m_Panel->m_HorizontalAlignment = UiAlign_Stretch;
 
-    CUiWindow<CSearchBar>* m_SearchBar;
-    CAvailableApps m_AvailableApps;
+            bSuccess &= CreateHSplitter();
+            bSuccess &= CreateListView();
+            bSuccess &= CreateAppInfoDisplay();
 
-    INT nSelectedApps;
+            if (!bSuccess)
+            {
+                return -1; // creation failure
+            }
+        }
+            break;
+        case WM_NOTIFY:
+        {
+            LPNMHDR pNotifyHeader = (LPNMHDR)lParam;
+            if (pNotifyHeader->hwndFrom == m_ListView->GetWindow())
+            {
+                switch (pNotifyHeader->code)
+                {
+                case LVN_ITEMCHANGED:
+                {
+                    LPNMLISTVIEW pnic = (LPNMLISTVIEW)lParam;
 
-    BOOL bSearchEnabled;
-    BOOL bUpdating;
+                    /* Check if this is a valid item
+                    * (technically, it can be also an unselect) */
+                    INT ItemIndex = pnic->iItem;
+                    if (ItemIndex == -1 ||
+                        ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
+                    {
+                        break;
+                    }
 
-    ATL::CStringW szSearchPattern;
-    INT SelectedEnumType;
+                    /* Check if the focus has been moved to another item */
+                    if ((pnic->uChanged & LVIF_STATE) &&
+                        (pnic->uNewState & LVIS_FOCUSED) &&
+                        !(pnic->uOldState & LVIS_FOCUSED))
+                    {
+                        ItemGetFocus((LPVOID)pnic->lParam);
+                    }
 
-public:
-    CMainWindow() :
-        m_ClientPanel(NULL),
-        bSearchEnabled(FALSE),
-        SelectedEnumType(ENUM_ALL_INSTALLED)
-    {
-    }
+                    /* Check if the item is checked/unchecked */
+                    if (pnic->uChanged & LVIF_STATE)
+                    {
+                        int iOldState = STATEIMAGETOINDEX(pnic->uOldState);
+                        int iNewState = STATEIMAGETOINDEX(pnic->uNewState);
+
+                        if (iOldState == STATEIMAGE_UNCHECKED && iNewState == 
STATEIMAGE_CHECKED)
+                        {
+                            // this item is just checked
+                            m_ListView->ItemCheckStateNotify(pnic->iItem, 
TRUE);
+                            ItemCheckStateChanged(TRUE, (LPVOID)pnic->lParam);
+                        }
+                        else if (iOldState == STATEIMAGE_CHECKED && iNewState 
== STATEIMAGE_UNCHECKED)
+                        {
+                            // this item is just unchecked
+                            m_ListView->ItemCheckStateNotify(pnic->iItem, 
FALSE);
+                            ItemCheckStateChanged(FALSE, (LPVOID)pnic->lParam);
+                        }
+                    }
+                }
+                break;
 
-private:
-    VOID InitApplicationsList()
-    {
-        ATL::CStringW szText;
+                case LVN_COLUMNCLICK:
+                {
+                    LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam;
+
+                    m_ListView->ColumnClick(pnmv);
+                }
+                break;
 
-        /* Add columns to ListView */
-        szText.LoadStringW(IDS_APP_NAME);
-        m_ListView->AddColumn(0, szText, 250, LVCFMT_LEFT);
+                case NM_DBLCLK:
+                {
+                    if (((LPNMLISTVIEW)lParam)->iItem != -1)
+                    {
+                        /* this won't do anything if the program is already 
installed */
+
+                        // TODO: the same problem I've mentioned in NM_RCLICK
+                        // I think if user double-click this app, then this 
app should be installed, not those checked apps.
+                        if (ApplicationViewMode == 
ApplicationViewAvailableApps)
+                        {
+                            SendMessageW(GetParent(), WM_COMMAND, ID_INSTALL, 
0);
+                        }
+                    }
+                }
+                break;
 
-        szText.LoadStringW(IDS_APP_INST_VERSION);
-        m_ListView->AddColumn(1, szText, 90, LVCFMT_RIGHT);
+                case NM_RCLICK:
+                {
+                    if (((LPNMLISTVIEW)lParam)->iItem != -1)
+                    {
+                        // TODO: currently the menu will send WM_COMMAND 
directly to MainWindow.
+                        // possibly it should be handled by this 
application-view first
+                        // and then forward to mainwindow.
+
+                        // TODO: I think if user right-click on one item, and 
select "Install"
+                        // that means the user want install "this" application
+                        // but if some apps are checked, this will lead to 
those checked apps to be installed.
+                        // this should be improved.
+                        ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
+                    }
+                }
+                break;
+                }
+            }
+        }
+            break;
 
-        szText.LoadStringW(IDS_APP_DESCRIPTION);
-        m_ListView->AddColumn(3, szText, 300, LVCFMT_LEFT);
+        case WM_SYSCOLORCHANGE:
+        {
+            /* Forward WM_SYSCOLORCHANGE to common controls */
+            m_ListView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
+            m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, 
GetSysColor(COLOR_BTNFACE));
+        }
+            break;
 
-        // Unnesesary since the list updates on every TreeView selection
-        // UpdateApplicationsList(ENUM_ALL_COMPONENTS);
+        case WM_SIZE:
+        {
+            OnSize(hwnd, wParam, lParam);
+            break;
+        }
+        }
+        return FALSE;
     }
 
-    VOID InitCategoriesList()
+    BOOL CreateHSplitter()
     {
-        HTREEITEM hRootItemInstalled, hRootItemAvailable;
-
-        hRootItemInstalled = m_TreeView->AddCategory(TVI_ROOT, IDS_INSTALLED, 
IDI_CATEGORY);
-        m_TreeView->AddCategory(hRootItemInstalled, IDS_APPLICATIONS, 
IDI_APPS);
-        m_TreeView->AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
-
+        m_HSplitter = new CUiSplitPanel();
+        m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
+        m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
+        m_HSplitter->m_DynamicFirst = TRUE;
+        m_HSplitter->m_Horizontal = TRUE;
+        m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible 
position (m_MinSecond)
+        m_HSplitter->m_MinFirst = 10;
+        m_HSplitter->m_MinSecond = 140;
+        m_Panel->Children().Append(m_HSplitter);
+
+        return m_HSplitter->Create(m_hWnd) != NULL;
+    }
+
+    BOOL CreateListView()
+    {
+        m_ListView = new CAppsListView();
+        m_ListView->m_VerticalAlignment = UiAlign_Stretch;
+        m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
+        m_HSplitter->First().Append(m_ListView);
+        
+        return m_ListView->Create(m_hWnd) != NULL;
+    }
+
+    BOOL CreateAppInfoDisplay()
+    {
+        m_AppsInfo = new CAppInfoDisplay();
+        m_AppsInfo->m_VerticalAlignment = UiAlign_Stretch;
+        m_AppsInfo->m_HorizontalAlignment = UiAlign_Stretch;
+        m_HSplitter->Second().Append(m_AppsInfo);
+
+        return m_AppsInfo->Create(m_hWnd) != NULL;
+    }
+
+    VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
+    {
+        if (wParam == SIZE_MINIMIZED)
+            return;
+        
+        RECT r = { 0, 0, LOWORD(lParam), HIWORD(lParam) };
+        HDWP hdwp = NULL;
+        INT count = m_Panel->CountSizableChildren();
+
+        hdwp = BeginDeferWindowPos(count);
+        if (hdwp)
+        {
+            hdwp = m_Panel->OnParentSize(r, hdwp);
+            if (hdwp)
+            {
+                EndDeferWindowPos(hdwp);
+            }
+        }
+    }
+
+public:
+
+    CApplicationView(CMainWindow *MainWindow)
+        : m_MainWindow(MainWindow)
+    {
+    }
+
+    ~CApplicationView()
+    {
+        delete m_ListView;
+        delete m_AppsInfo;
+        delete m_HSplitter;
+    }
+
+    static ATL::CWndClassInfo& GetWndClassInfo()
+    {
+        DWORD csStyle = CS_VREDRAW | CS_HREDRAW;
+        static ATL::CWndClassInfo wc =
+        {
+            {
+                sizeof(WNDCLASSEX),
+                csStyle,
+                StartWindowProc,
+                0,
+                0,
+                NULL,
+                NULL,
+                NULL,
+                (HBRUSH)(COLOR_BTNFACE + 1),
+                NULL,
+                L"RAppsApplicationView",
+                NULL
+            },
+            NULL, NULL, IDC_ARROW, TRUE, 0, _T("")
+        };
+        return wc;
+    }
+
+    HWND Create(HWND hwndParent)
+    {
+        RECT r = { 0,0,0,0 };
+
+        return CWindowImpl::Create(hwndParent, r, L"", WS_CHILD | WS_VISIBLE | 
WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+    }
+
+    BOOL SetDisplayMode(APPLICATION_VIEW_MODE Mode)
+    {
+        if (!m_ListView->SetDisplayMode(Mode))
+        {
+            return FALSE;
+        }
+        ApplicationViewMode = Mode;
+        m_AppsInfo->SetWelcomeText();
+
+        HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
+        switch (Mode)
+        {
+        case ApplicationViewEmpty:
+        default:
+            EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
+            EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
+            EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
+            EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
+            break;
+
+        case ApplicationViewInstalledApps:
+            EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
+            EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
+            EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
+            EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
+            break;
+
+        case ApplicationViewAvailableApps:
+            EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
+            EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
+            EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
+            EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
+            break;
+        }
+        return TRUE;
+    }
+
+    BOOL AddInstalledApplication(CInstalledApplicationInfo * InstAppInfo, 
LPVOID param)
+    {
+        if (ApplicationViewMode != ApplicationViewInstalledApps)
+        {
+            return FALSE;
+        }
+        return m_ListView->AddInstalledApplication(InstAppInfo, param);
+    }
+
+    BOOL AddAvailableApplication(CAvailableApplicationInfo * AvlbAppInfo, BOOL 
InitCheckState, LPVOID param)
+    {
+        if (ApplicationViewMode != ApplicationViewAvailableApps)
+        {
+            return FALSE;
+        }
+        return m_ListView->AddAvailableApplication(AvlbAppInfo, 
InitCheckState, param);
+    }
+
+    void CheckAll()
+    {
+        m_ListView->CheckAll();
+        return;
+    }
+
+    PVOID GetFocusedItemData()
+    {
+        return m_ListView->GetFocusedItemData();
+    }
+
+    int GetItemCount()
+    {
+        return m_ListView->GetItemCount();
+    }
+
+    // this function is called when a item of listview get focus.
+    // CallbackParam is the param passed to listview when adding the item (the 
one getting focus now).
+    BOOL ItemGetFocus(LPVOID CallbackParam)
+    {
+        switch (ApplicationViewMode)
+        {
+        case ApplicationViewInstalledApps:
+            return m_AppsInfo->ShowInstalledAppInfo((CInstalledApplicationInfo 
*)CallbackParam);
+
+        case ApplicationViewAvailableApps:
+            return m_AppsInfo->ShowAvailableAppInfo((CAvailableApplicationInfo 
*)CallbackParam);
+
+        case ApplicationViewEmpty:
+        default:
+            m_AppsInfo->SetWelcomeText();
+            return FALSE;
+        }
+    }
+
+    // this function is called when a item of listview is checked/unchecked
+    // CallbackParam is the param passed to listview when adding the item (the 
one getting focus now).
+    BOOL ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam);
+    
+};
+
+class CSideTreeView :
+    public CUiWindow<CTreeView>
+{
+    HIMAGELIST hImageTreeView;
+
+public:
+    CSideTreeView() :
+        CUiWindow(),
+        hImageTreeView(ImageList_Create(TREEVIEW_ICON_SIZE, TREEVIEW_ICON_SIZE,
+                                        GetSystemColorDepth() | ILC_MASK,
+                                        0, 1))
+    {
+    }
+
+    HTREEITEM AddItem(HTREEITEM hParent, ATL::CStringW &Text, INT Image, INT 
SelectedImage, LPARAM lParam)
+    {
+        return CUiWindow<CTreeView>::AddItem(hParent, 
const_cast<LPWSTR>(Text.GetString()), Image, SelectedImage, lParam);
+    }
+
+    HTREEITEM AddCategory(HTREEITEM hRootItem, UINT TextIndex, UINT IconIndex)
+    {
+        ATL::CStringW szText;
+        INT Index;
+        HICON hIcon;
+
+        hIcon = (HICON) LoadImageW(hInst,
+                                   MAKEINTRESOURCE(IconIndex),
+                                   IMAGE_ICON,
+                                   TREEVIEW_ICON_SIZE,
+                                   TREEVIEW_ICON_SIZE,
+                                   LR_CREATEDIBSECTION);
+        if (hIcon)
+        {
+            Index = ImageList_AddIcon(hImageTreeView, hIcon);
+            DestroyIcon(hIcon);
+        }
+
+        szText.LoadStringW(TextIndex);
+        return AddItem(hRootItem, szText, Index, Index, TextIndex);
+    }
+
+    HIMAGELIST SetImageList()
+    {
+        return CUiWindow<CTreeView>::SetImageList(hImageTreeView, 
TVSIL_NORMAL);
+    }
+
+    VOID DestroyImageList()
+    {
+        if (hImageTreeView)
+            ImageList_Destroy(hImageTreeView);
+    }
+
+    ~CSideTreeView()
+    {
+        DestroyImageList();
+    }
+};
+
+class CSearchBar :
+    public CWindow
+{
+public:
+    const INT m_Width;
+    const INT m_Height;
+
+    CSearchBar() : m_Width(200), m_Height(22)
+    {
+    }
+
+    VOID SetText(LPCWSTR lpszText)
+    {
+        SendMessageW(SB_SETTEXT, SBT_NOBORDERS, (LPARAM) lpszText);
+    }
+
+    HWND Create(HWND hwndParent)
+    {
+        ATL::CStringW szBuf;
+        m_hWnd = CreateWindowExW(WS_EX_CLIENTEDGE, L"Edit", NULL,
+                                 WS_CHILD | WS_VISIBLE | ES_LEFT | 
ES_AUTOHSCROLL,
+                                 0, 0, m_Width, m_Height,
+                                 hwndParent, (HMENU) NULL,
+                                 hInst, 0);
+
+        SendMessageW(WM_SETFONT, (WPARAM) GetStockObject(DEFAULT_GUI_FONT), 0);
+        szBuf.LoadStringW(IDS_SEARCH_TEXT);
+        SetWindowTextW(szBuf);
+        return m_hWnd;
+    }
+
+};
+
+class CMainWindow :
+    public CWindowImpl<CMainWindow, CWindow, CFrameWinTraits>
+{
+    CUiPanel* m_ClientPanel = NULL;
+    CUiSplitPanel* m_VSplitter = NULL;
+
+    CMainToolbar* m_Toolbar = NULL;
+
+    CSideTreeView* m_TreeView = NULL;
+    CUiWindow<CStatusBar>* m_StatusBar = NULL;
+
+    CApplicationView* m_ApplicationView = NULL;
+
+    CUiWindow<CSearchBar>* m_SearchBar = NULL;
+    CAvailableApps m_AvailableApps;
+    CInstalledApps m_InstalledApps;
+
+    BOOL bSearchEnabled;
+    BOOL bUpdating = FALSE;
+
+    ATL::CStringW szSearchPattern;
+    INT SelectedEnumType;
+
+public:
+    CMainWindow() :
+        m_ClientPanel(NULL),
+        bSearchEnabled(FALSE),
+        SelectedEnumType(ENUM_ALL_INSTALLED)
+    {
+    }
+
+    ~CMainWindow()
+    {
+        LayoutCleanup();
+    }
+private:
+
+    VOID InitCategoriesList()
+    {
+        HTREEITEM hRootItemInstalled, hRootItemAvailable;
+
+        hRootItemInstalled = m_TreeView->AddCategory(TVI_ROOT, IDS_INSTALLED, 
IDI_CATEGORY);
+        m_TreeView->AddCategory(hRootItemInstalled, IDS_APPLICATIONS, 
IDI_APPS);
+        m_TreeView->AddCategory(hRootItemInstalled, IDS_UPDATES, IDI_APPUPD);
+
         m_TreeView->AddCategory(TVI_ROOT, IDS_SELECTEDFORINST, 
IDI_SELECTEDFORINST);
 
         hRootItemAvailable = m_TreeView->AddCategory(TVI_ROOT, 
IDS_AVAILABLEFORINST, IDI_CATEGORY);
@@ -1601,24 +2082,14 @@ private:
         return m_TreeView->Create(m_hWnd) != NULL;
     }
 
-    BOOL CreateListView()
+    BOOL CreateApplicationView()
     {
-        m_ListView = new CAppsListView();
-        m_ListView->m_VerticalAlignment = UiAlign_Stretch;
-        m_ListView->m_HorizontalAlignment = UiAlign_Stretch;
-        m_HSplitter->First().Append(m_ListView);
+        m_ApplicationView = new CApplicationView(this); // pass this to 
ApplicationView for callback purpose
+        m_ApplicationView->m_VerticalAlignment = UiAlign_Stretch;
+        m_ApplicationView->m_HorizontalAlignment = UiAlign_Stretch;
+        m_VSplitter->Second().Append(m_ApplicationView);
 
-        return m_ListView->Create(m_hWnd) != NULL;
-    }
-
-    BOOL CreateRichEdit()
-    {
-        m_AppInfo = new CAppInfoDisplay();
-        m_AppInfo->m_VerticalAlignment = UiAlign_Stretch;
-        m_AppInfo->m_HorizontalAlignment = UiAlign_Stretch;
-        m_HSplitter->Second().Append(m_AppInfo);
-
-        return m_AppInfo->Create(m_hWnd) != NULL;
+        return m_ApplicationView->Create(m_hWnd) != NULL;
     }
 
     BOOL CreateVSplitter()
@@ -1636,21 +2107,6 @@ private:
         return m_VSplitter->Create(m_hWnd) != NULL;
     }
 
-    BOOL CreateHSplitter()
-    {
-        m_HSplitter = new CUiSplitPanel();
-        m_HSplitter->m_VerticalAlignment = UiAlign_Stretch;
-        m_HSplitter->m_HorizontalAlignment = UiAlign_Stretch;
-        m_HSplitter->m_DynamicFirst = TRUE;
-        m_HSplitter->m_Horizontal = TRUE;
-        m_HSplitter->m_Pos = INT_MAX; //set INT_MAX to use lowest possible 
position (m_MinSecond)
-        m_HSplitter->m_MinFirst = 10;
-        m_HSplitter->m_MinSecond = 140;
-        m_VSplitter->Second().Append(m_HSplitter);
-
-        return m_HSplitter->Create(m_hWnd) != NULL;
-    }
-
     BOOL CreateSearchBar()
     {
         m_SearchBar = new CUiWindow<CSearchBar>();
@@ -1678,12 +2134,8 @@ private:
         b = b && CreateVSplitter();
 
         // Inside V Splitter
-        b = b && CreateHSplitter();
         b = b && CreateTreeView();
-
-        // Inside H Splitter
-        b = b && CreateListView();
-        b = b && CreateRichEdit();
+        b = b && CreateApplicationView();
 
         if (b)
         {
@@ -1707,15 +2159,23 @@ private:
         return b;
     }
 
+    VOID LayoutCleanup()
+    {
+        delete m_TreeView;
+        delete m_ApplicationView;
+        delete m_VSplitter;
+        delete m_SearchBar;
+        delete m_Toolbar;
+        delete m_StatusBar;
+        return;
+    }
+
     BOOL InitControls()
     {
         if (CreateLayout())
         {
-
-            InitApplicationsList();
             InitCategoriesList();
 
-            nSelectedApps = 0;
             UpdateStatusBarText();
 
             return TRUE;
@@ -1724,28 +2184,6 @@ private:
         return FALSE;
     }
 
-    VOID ShowAppInfo(INT Index)
-    {
-        if (IsInstalledEnum(SelectedEnumType))
-        {
-            if (Index == -1)
-                Index = m_ListView->GetSelectionMark();
-
-            PINSTALLED_INFO Info = (PINSTALLED_INFO) 
m_ListView->GetItemData(Index);
-
-            m_AppInfo->ShowInstalledAppInfo(Info);
-        }
-        else if (IsAvailableEnum(SelectedEnumType))
-        {
-            if (Index == -1)
-                return;
-
-            CAvailableApplicationInfo* Info = (CAvailableApplicationInfo*) 
m_ListView->GetItemData(Index);
-
-            m_AppInfo->ShowAvailableAppInfo(Info);
-        }
-    }
-
     VOID OnSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
     {
         if (wParam == SIZE_MINIMIZED)
@@ -1782,7 +2220,6 @@ private:
             {
                 EndDeferWindowPos(hdwp);
             }
-
         }
 
         // TODO: Sub-layouts for children of children
@@ -1796,64 +2233,47 @@ private:
                 EndDeferWindowPos(hdwp);
             }
         }
-
     }
 
-    VOID RemoveSelectedAppFromRegistry()
+    BOOL RemoveSelectedAppFromRegistry()
     {
-        PINSTALLED_INFO Info;
-        WCHAR szFullName[MAX_PATH] = 
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\";
-        ATL::CStringW szMsgText, szMsgTitle;
-        INT ItemIndex = m_ListView->GetNextItem(-1, LVNI_FOCUSED);
-
         if (!IsInstalledEnum(SelectedEnumType))
-            return;
+            return FALSE;
 
-        Info = 
reinterpret_cast<PINSTALLED_INFO>(m_ListView->GetItemData(ItemIndex));
-        if (!Info || !Info->hSubKey || (ItemIndex == -1)) 
-            return;
+        ATL::CStringW szMsgText, szMsgTitle;
 
         if (!szMsgText.LoadStringW(IDS_APP_REG_REMOVE) ||
             !szMsgTitle.LoadStringW(IDS_INFORMATION))
-            return;
+            return FALSE;
 
         if (MessageBoxW(szMsgText, szMsgTitle, MB_YESNO | MB_ICONQUESTION) == 
IDYES)
         {
-            ATL::CStringW::CopyChars(szFullName,
-                                     MAX_PATH,
-                                     Info->szKeyName.GetString(),
-                                     MAX_PATH - wcslen(szFullName));
-
-            if (RegDeleteKeyW(Info->hRootKey, szFullName) == ERROR_SUCCESS)
+            CInstalledApplicationInfo *InstalledApp = 
(CInstalledApplicationInfo *)m_ApplicationView->GetFocusedItemData();
+            LSTATUS Result = InstalledApp->RemoveFromRegistry();
+            if (Result != ERROR_SUCCESS)
             {
-                m_ListView->DeleteItem(ItemIndex);
-                return;
+                // TODO: popup a messagebox telling user it fails somehow
+                return FALSE;
             }
 
-            if (!szMsgText.LoadStringW(IDS_UNABLE_TO_REMOVE))
-                return;
-
-            MessageBoxW(szMsgText.GetString(), NULL, MB_OK | MB_ICONERROR);
+            // as it's already removed form registry, this will also remove it 
from the list
+            UpdateApplicationsList(-1);
+            return TRUE;
         }
+
+        return FALSE;
     }
 
     BOOL UninstallSelectedApp(BOOL bModify)
     {
-        WCHAR szAppName[MAX_STR_LEN];
-
         if (!IsInstalledEnum(SelectedEnumType))
             return FALSE;
 
-        INT ItemIndex = m_ListView->GetNextItem(-1, LVNI_FOCUSED);
-        if (ItemIndex == -1)
-            return FALSE;
-
-        m_ListView->GetItemText(ItemIndex, 0, szAppName, _countof(szAppName));
-        WriteLogMessage(EVENTLOG_SUCCESS, MSG_SUCCESS_REMOVE, szAppName);
+        CInstalledApplicationInfo *InstalledApp = (CInstalledApplicationInfo 
*)m_ApplicationView->GetFocusedItemData();
 
-        PINSTALLED_INFO ItemInfo = 
(PINSTALLED_INFO)m_ListView->GetItemData(ItemIndex);
-        return UninstallApplication(ItemInfo, bModify);
+        return InstalledApp->UninstallApplication(bModify);
     }
+
     BOOL ProcessWindowMessage(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM 
lParam, LRESULT& theResult, DWORD dwMapId)
     {
         theResult = 0;
@@ -1871,9 +2291,7 @@ private:
 
             FreeLogs();
             m_AvailableApps.FreeCachedEntries();
-
-            if (IsInstalledEnum(SelectedEnumType))
-                FreeInstalledAppList();
+            m_InstalledApps.FreeCachedEntries();
 
             delete m_ClientPanel;
 
@@ -1984,7 +2402,6 @@ private:
                 }
 
                 HMENU mainMenu = ::GetMenu(hwnd);
-                HMENU lvwMenu = ::GetMenu(m_ListView->m_hWnd);
 
                 /* Disable/enable items based on treeview selection */
                 if (IsSelectedNodeInstalled())
@@ -1994,11 +2411,6 @@ private:
                     EnableMenuItem(mainMenu, ID_UNINSTALL, MF_ENABLED);
                     EnableMenuItem(mainMenu, ID_MODIFY, MF_ENABLED);
 
-                    EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_ENABLED);
-                    EnableMenuItem(lvwMenu, ID_INSTALL, MF_GRAYED);
-                    EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_ENABLED);
-                    EnableMenuItem(lvwMenu, ID_MODIFY, MF_ENABLED);
-
                     m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, 
TRUE);
                     m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, 
FALSE);
                     m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, 
TRUE);
@@ -2011,11 +2423,6 @@ private:
                     EnableMenuItem(mainMenu, ID_UNINSTALL, MF_GRAYED);
                     EnableMenuItem(mainMenu, ID_MODIFY, MF_GRAYED);
 
-                    EnableMenuItem(lvwMenu, ID_REGREMOVE, MF_GRAYED);
-                    EnableMenuItem(lvwMenu, ID_INSTALL, MF_ENABLED);
-                    EnableMenuItem(lvwMenu, ID_UNINSTALL, MF_GRAYED);
-                    EnableMenuItem(lvwMenu, ID_MODIFY, MF_GRAYED);
-
                     m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_REGREMOVE, 
FALSE);
                     m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_INSTALL, TRUE);
                     m_Toolbar->SendMessageW(TB_ENABLEBUTTON, ID_UNINSTALL, 
FALSE);
@@ -2024,91 +2431,6 @@ private:
             }
             break;
 
-            case LVN_ITEMCHANGED:
-            {
-                LPNMLISTVIEW pnic = (LPNMLISTVIEW) lParam;
-
-                if (pnic->hdr.hwndFrom == m_ListView->m_hWnd)
-                {
-                    /* Check if this is a valid item
-                    * (technically, it can be also an unselect) */
-                    INT ItemIndex = pnic->iItem;
-                    if (ItemIndex == -1 ||
-                        ItemIndex >= ListView_GetItemCount(pnic->hdr.hwndFrom))
-                    {
-                        break;
-                    }
-
-                    /* Check if the focus has been moved to another item */
-                    if ((pnic->uChanged & LVIF_STATE) &&
-                        (pnic->uNewState & LVIS_FOCUSED) &&
-                        !(pnic->uOldState & LVIS_FOCUSED))
-                    {
-                        ShowAppInfo(ItemIndex);
-                    }
-                    /* Check if the item is checked */
-                    if ((pnic->uNewState & LVIS_STATEIMAGEMASK) && !bUpdating)
-                    {
-                        BOOL checked = m_ListView->GetCheckState(pnic->iItem);
-                        /* FIXME: HAX!
-                        - preventing decremention below zero as a safeguard 
for ReactOS
-                          In ReactOS this action is triggered whenever user 
changes *selection*, but should be only when *checkbox* state toggled
-                          Maybe LVIS_STATEIMAGEMASK is set incorrectly
-                        */
-                        nSelectedApps +=
-                            (checked)
-                            ? 1
-                            : ((nSelectedApps > 0)
-                               ? -1
-                               : 0);
-
-                        /* Update item's selection status */
-                        m_ListView->SetSelected(pnic->iItem, checked);
-
-                        UpdateStatusBarText();
-                    }
-                }
-            }
-            break;
-
-            case LVN_COLUMNCLICK:
-            {
-                LPNMLISTVIEW pnmv = (LPNMLISTVIEW) lParam;
-
-                m_ListView->ColumnClick(pnmv);
-            }
-            break;
-
-            case NM_CLICK:
-            {
-                if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) 
lParam)->iItem != -1)
-                {
-                    ShowAppInfo(-1);
-                }
-            }
-            break;
-
-            case NM_DBLCLK:
-            {
-                if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) 
lParam)->iItem != -1)
-                {
-                    /* this won't do anything if the program is already 
installed */
-                    SendMessageW(hwnd, WM_COMMAND, ID_INSTALL, 0);
-                }
-            }
-            break;
-
-            case NM_RCLICK:
-            {
-                if (data->hwndFrom == m_ListView->m_hWnd && ((LPNMLISTVIEW) 
lParam)->iItem != -1)
-                {
-                    ShowPopupMenu(m_ListView->m_hWnd, 0, ID_INSTALL);
-                }
-            }
-            break;
-
-            
-
             case TTN_GETDISPINFO:
                 m_Toolbar->OnGetDispInfo((LPTOOLTIPTEXT) lParam);
                 break;
@@ -2136,10 +2458,9 @@ private:
         case WM_SYSCOLORCHANGE:
         {
             /* Forward WM_SYSCOLORCHANGE to common controls */
-            m_ListView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
-            m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
+            m_ApplicationView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
+            m_TreeView->SendMessageW(WM_SYSCOLORCHANGE, wParam, lParam);
             m_Toolbar->SendMessageW(WM_SYSCOLORCHANGE, 0, 0);
-            m_ListView->SendMessageW(EM_SETBKGNDCOLOR, 0, 
GetSysColor(COLOR_BTNFACE));
         }
         break;
 
@@ -2272,17 +2593,36 @@ private:
         case ID_INSTALL:
             if (IsAvailableEnum(SelectedEnumType))
             {
-                if (nSelectedApps > 0)
+                ATL::CSimpleArray<CAvailableApplicationInfo> AppsList;
+
+                // enum all selected apps
+                m_AvailableApps.Enum(ENUM_CAT_SELECTED, 
s_EnumSelectedAppForDownloadProc, (PVOID)&AppsList);
+
+                if (AppsList.GetSize())
                 {
-                    DownloadListOfApplications(m_AvailableApps.GetSelected(), 
FALSE);
-                    UpdateApplicationsList(-1);
-                    m_ListView->SetSelected(-1, FALSE);
+                    if (DownloadListOfApplications(AppsList, FALSE))
+                    {
+                        m_AvailableApps.RemoveAllSelected();
+                        UpdateApplicationsList(-1);
+                    }
                 }
-                else if (DownloadApplication(m_ListView->GetSelectedData(), 
FALSE))
+                else
                 {
-                    UpdateApplicationsList(-1);
+                    // use the currently focused item in application-view
+                    CAvailableApplicationInfo *FocusedApps = 
(CAvailableApplicationInfo *)m_ApplicationView->GetFocusedItemData();
+                    if (FocusedApps)
+                    {
+                        if (DownloadApplication(FocusedApps, FALSE))
+                        {
+                            UpdateApplicationsList(-1);
+                        }
+                    }
+                    else
+                    {
+                        // TODO: in this case, Install button in toolbar (and 
all other places) should be disabled
+                        // or at least popup a messagebox telling user to 
select/check some app first
+                    }
                 }
-
             }
             break;
 
@@ -2318,28 +2658,11 @@ private:
             break;
 
         case ID_CHECK_ALL:
-            m_ListView->CheckAll();
+            m_ApplicationView->CheckAll();
             break;
         }
     }
 
-    VOID FreeInstalledAppList()
-    {
-        INT Count = m_ListView->GetItemCount() - 1;
-        PINSTALLED_INFO Info;
-
-        while (Count >= 0)
-        {
-            Info = (PINSTALLED_INFO) m_ListView->GetItemData(Count);
-            if (Info)
-            {
-                RegCloseKey(Info->hSubKey);
-                delete Info;
-            }
-            Count--;
-        }
-    }
-
     static BOOL SearchPatternMatch(LPCWSTR szHaystack, LPCWSTR szNeedle)
     {
         if (!*szNeedle)
@@ -2348,91 +2671,42 @@ private:
         return StrStrIW(szHaystack, szNeedle) != NULL;
     }
 
-    BOOL CALLBACK EnumInstalledAppProc(INT ItemIndex, ATL::CStringW &m_szName, 
PINSTALLED_INFO Info)
+    BOOL CALLBACK EnumInstalledAppProc(CInstalledApplicationInfo * Info)
     {
-        PINSTALLED_INFO ItemInfo;
-        ATL::CStringW szText;
-        INT Index;
-
-        if (!SearchPatternMatch(m_szName.GetString(), szSearchPattern))
+        if (!SearchPatternMatch(Info->szDisplayName.GetString(), 
szSearchPattern))
         {
-            RegCloseKey(Info->hSubKey);
             return TRUE;
         }
-
-        ItemInfo = new INSTALLED_INFO(*Info);
-        if (!ItemInfo)
-        {
-            RegCloseKey(Info->hSubKey);
-            return FALSE;
-        }
-
-        Index = m_ListView->AddItem(ItemIndex, 0, m_szName.GetString(), 
(LPARAM) ItemInfo);
-
-        /* Get version info */
-        ItemInfo->GetApplicationString(L"DisplayVersion", szText);
-        m_ListView->SetItemText(Index, 1, szText.GetString());
-
-        /* Get comments */
-        ItemInfo->GetApplicationString(L"Comments", szText);
-        m_ListView->SetItemText(Index, 2, szText.GetString());
-
-        return TRUE;
+        return m_ApplicationView->AddInstalledApplication(Info, Info); // 
currently, the callback param is Info itself
     }
 
-    BOOL EnumAvailableAppProc(CAvailableApplicationInfo* Info, LPCWSTR 
szFolderPath)
+    BOOL CALLBACK EnumAvailableAppProc(CAvailableApplicationInfo * Info, BOOL 
bInitialCheckState)
     {
-        INT Index;
-        HICON hIcon = NULL;
-
-        HIMAGELIST hImageListView = 
(HIMAGELIST)m_ListView->SendMessage(LVM_GETIMAGELIST, LVSIL_SMALL, 0);
-
         if (!SearchPatternMatch(Info->m_szName.GetString(), szSearchPattern) &&
             !SearchPatternMatch(Info->m_szDesc.GetString(), szSearchPattern))
         {
             return TRUE;
         }
-
-        /* Load icon from file */
-        ATL::CStringW szIconPath;
-        if (Info->RetrieveIcon(szIconPath))
-        {
-            hIcon = (HICON)LoadImageW(NULL,
-                szIconPath.GetString(),
-                IMAGE_ICON,
-                LISTVIEW_ICON_SIZE,
-                LISTVIEW_ICON_SIZE,
-                LR_LOADFROMFILE);
-        }
-
-        if (!hIcon || GetLastError() != ERROR_SUCCESS)
-        {
-            /* Load default icon */
-            hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
-        }
-
-        Index = ImageList_AddIcon(hImageListView, hIcon);
-        DestroyIcon(hIcon);
-
-        Index = m_ListView->AddItem(Info->m_Category, Index, 
Info->m_szName.GetString(), (LPARAM) Info);
-        m_ListView->SetImageList(hImageListView, LVSIL_SMALL);
-        m_ListView->SetItemText(Index, 1, Info->m_szVersion.GetString());
-        m_ListView->SetItemText(Index, 2, Info->m_szDesc.GetString());
-        m_ListView->SetCheckState(Index, Info->m_IsSelected);
-
-        return TRUE;
+        return m_ApplicationView->AddAvailableApplication(Info, 
bInitialCheckState, Info); // currently, the callback param is Info itself
     }
 
-    static BOOL CALLBACK s_EnumInstalledAppProc(INT ItemIndex, ATL::CStringW 
&m_szName, PINSTALLED_INFO Info, PVOID param)
+    static BOOL CALLBACK s_EnumInstalledAppProc(CInstalledApplicationInfo * 
Info, PVOID param)
     {
         CMainWindow* pThis = (CMainWindow*)param;
-        return pThis->EnumInstalledAppProc(ItemIndex, m_szName, Info);
+        return pThis->EnumInstalledAppProc(Info);
     }
 
-    static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo* 
Info, LPCWSTR szFolderPath, PVOID param)
+    static BOOL CALLBACK s_EnumAvailableAppProc(CAvailableApplicationInfo* 
Info, BOOL bInitialCheckState, PVOID param)
     {
         CMainWindow* pThis = (CMainWindow*)param;
-        return pThis->EnumAvailableAppProc(Info, szFolderPath);
+        return pThis->EnumAvailableAppProc(Info, bInitialCheckState);
+    }
+
+    static BOOL CALLBACK 
s_EnumSelectedAppForDownloadProc(CAvailableApplicationInfo *Info, BOOL 
bInitialCheckState, PVOID param)
+    {
+        ATL::CSimpleArray<CAvailableApplicationInfo> *pAppList = 
(ATL::CSimpleArray<CAvailableApplicationInfo> *)param;
+        pAppList->Add(*Info);
+        return TRUE;
     }
 
     VOID UpdateStatusBarText()
@@ -2441,83 +2715,46 @@ private:
         {
             ATL::CStringW szBuffer;
 
-            szBuffer.Format(IDS_APPS_COUNT, m_ListView->GetItemCount(), 
nSelectedApps);
+            szBuffer.Format(IDS_APPS_COUNT, m_ApplicationView->GetItemCount(), 
m_AvailableApps.GetSelectedCount());
             m_StatusBar->SetText(szBuffer);
         }
     }
 
     VOID UpdateApplicationsList(INT EnumType)
     {
-        ATL::CStringW szBuffer1, szBuffer2;
-        HIMAGELIST hImageListView;
-        BOOL bWasInInstalled = IsInstalledEnum(SelectedEnumType);
-
         bUpdating = TRUE;
-        m_ListView->SetRedraw(FALSE);
 
-        if (EnumType < 0)
+        if (EnumType == -1)
         {
+            // keep the old enum type
             EnumType = SelectedEnumType;
         }
-
-        //if previous one was INSTALLED purge the list
-        //TODO: make the Installed category a separate class to avoid doing 
this
-        if (bWasInInstalled)
-        {
-            FreeInstalledAppList();
-        }
-
-        m_ListView->DeleteAllItems();
-
-        // Create new ImageList
-        hImageListView = ImageList_Create(LISTVIEW_ICON_SIZE,
-                                          LISTVIEW_ICON_SIZE,
-                                          GetSystemColorDepth() | ILC_MASK,
-                                          0, 1);
-        HIMAGELIST hImageListBuf = m_ListView->SetImageList(hImageListView, 
LVSIL_SMALL);
-        if (hImageListBuf)
+        else
         {
-            ImageList_Destroy(hImageListBuf);
+            SelectedEnumType = EnumType;
         }
 
+        m_ApplicationView->SetRedraw(FALSE);
         if (IsInstalledEnum(EnumType))
         {
-            if (!bWasInInstalled)
-            {
-                m_ListView->SetCheckboxesVisible(FALSE);
-            }
+            // set the display mode of application-view. this will remove all 
the item in application-view too.
+            m_ApplicationView->SetDisplayMode(ApplicationViewInstalledApps);
 
-            HICON hIcon = (HICON) LoadIconW(hInst, MAKEINTRESOURCEW(IDI_MAIN));
-            ImageList_AddIcon(hImageListView, hIcon);
-            DestroyIcon(hIcon);
-
-            // Enum installed applications and updates
-            EnumInstalledApplications(EnumType, TRUE, s_EnumInstalledAppProc, 
this);
-            EnumInstalledApplications(EnumType, FALSE, s_EnumInstalledAppProc, 
this);
+            // enum installed softwares 
+            m_InstalledApps.Enum(EnumType, s_EnumInstalledAppProc, this);
         }
         else if (IsAvailableEnum(EnumType))
         {
-            if (bWasInInstalled)
-            {
-                m_ListView->SetCheckboxesVisible(TRUE);
-            }
+            // set the display mode of application-view. this will remove all 
the item in application-view too.
+            m_ApplicationView->SetDisplayMode(ApplicationViewAvailableApps);
 
-            // Enum available applications
+            // enum available softwares 
             m_AvailableApps.Enum(EnumType, s_EnumAvailableAppProc, this);
         }
-
-        SelectedEnumType = EnumType;
+        m_ApplicationView->SetRedraw(TRUE);
+        m_ApplicationView->RedrawWindow(0, 0, RDW_INVALIDATE | 
RDW_ALLCHILDREN); // force the child window to repaint
         UpdateStatusBarText();
-        m_AppInfo->SetWelcomeText();
-
-        // Set automatic column width for program names if the list is not 
empty
-        if (m_ListView->GetItemCount() > 0)
-        {
-            ListView_SetColumnWidth(m_ListView->GetWindow(), 0, 
LVSCW_AUTOSIZE);
-        }
-
         bUpdating = FALSE;
-        m_ListView->SetRedraw(TRUE);
     }
 
 public:
@@ -2562,9 +2799,39 @@ public:
         return CWindowImpl::Create(NULL, r, szWindowName.GetString(), 
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, WS_EX_WINDOWEDGE);
     }
 
+    // this function is called when a item of application-view is 
checked/unchecked
+    // CallbackParam is the param passed to application-view when adding the 
item (the one getting focus now).
+    BOOL ItemCheckStateChanged(BOOL bChecked, LPVOID CallbackParam)
+    {
+        if (!bUpdating)
+        {
+            if (bChecked)
+            {
+                if (!m_AvailableApps.AddSelected((CAvailableApplicationInfo 
*)CallbackParam))
+                {
+                    return FALSE;
+                }
+            }
+            else
+            {
+                if (!m_AvailableApps.RemoveSelected((CAvailableApplicationInfo 
*)CallbackParam))
+                {
+                    return FALSE;
+                }
+            }
+
+            UpdateStatusBarText();
+            return TRUE;
+        }
+        else
+        {
+            return TRUE;
+        }
+    }
+
     void HandleTabOrder(int direction)
     {
-        HWND Controls[] = { m_Toolbar->m_hWnd, m_SearchBar->m_hWnd, 
m_TreeView->m_hWnd, m_ListView->m_hWnd, m_AppInfo->m_hWnd };
+        HWND Controls[] = { m_Toolbar->m_hWnd, m_SearchBar->m_hWnd, 
m_TreeView->m_hWnd, m_ApplicationView->m_hWnd};
         // When there is no control found, go to the first or last (depending 
on tab vs shift-tab)
         int current = direction > 0 ? 0 : (_countof(Controls) - 1);
         HWND hActive = ::GetFocus();
@@ -2586,6 +2853,12 @@ public:
     }
 };
 
+BOOL CApplicationView::ItemCheckStateChanged(BOOL bChecked, LPVOID 
CallbackParam)
+{
+    m_MainWindow->ItemCheckStateChanged(bChecked, CallbackParam);
+    return TRUE;
+}
+
 VOID ShowMainWindow(INT nShowCmd)
 {
     HACCEL KeyBrd;
diff --git a/base/applications/rapps/include/available.h 
b/base/applications/rapps/include/available.h
index 259b644dce1..2ee8136cc91 100644
--- a/base/applications/rapps/include/available.h
+++ b/base/applications/rapps/include/available.h
@@ -37,10 +37,11 @@ struct AvailableStrings
     AvailableStrings();
 };
 
-struct CAvailableApplicationInfo
+class CAvailableApplicationInfo
 {
+public:
     INT m_Category;
-    BOOL m_IsSelected;
+    //BOOL m_IsSelected;
     LicenseType m_LicenseType;
     ATL::CStringW m_szName;
     ATL::CStringW m_szRegName;
@@ -98,11 +99,12 @@ private:
     inline BOOL FindInLanguages(LCID what) const;
 };
 
-typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, LPCWSTR 
szFolderPath, PVOID param);
+typedef BOOL(CALLBACK *AVAILENUMPROC)(CAvailableApplicationInfo *Info, BOOL 
bInitialCheckState, PVOID param);
 
 class CAvailableApps
 {
     ATL::CAtlList<CAvailableApplicationInfo*> m_InfoList;
+    ATL::CAtlList< CAvailableApplicationInfo*> m_SelectedList;
 
 public:
     static AvailableStrings m_Strings;
@@ -116,9 +118,15 @@ public:
     VOID FreeCachedEntries();
     BOOL Enum(INT EnumType, AVAILENUMPROC lpEnumProc, PVOID param);
 
+    BOOL AddSelected(CAvailableApplicationInfo *AvlbInfo);
+    BOOL RemoveSelected(CAvailableApplicationInfo *AvlbInfo);
+
+    VOID RemoveAllSelected();
+    int GetSelectedCount();
+
     CAvailableApplicationInfo* FindInfo(const ATL::CStringW& szAppName) const;
     ATL::CSimpleArray<CAvailableApplicationInfo> FindInfoList(const 
ATL::CSimpleArray<ATL::CStringW> &arrAppsNames) const;
-    ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const;
+    //ATL::CSimpleArray<CAvailableApplicationInfo> GetSelected() const;
 
     const ATL::CStringW& GetFolderPath() const;
     const ATL::CStringW& GetAppPath() const;
diff --git a/base/applications/rapps/include/installed.h 
b/base/applications/rapps/include/installed.h
index 76a12418c1c..f13e37e1b48 100644
--- a/base/applications/rapps/include/installed.h
+++ b/base/applications/rapps/include/installed.h
@@ -3,19 +3,51 @@
 #include <windef.h>
 #include <atlstr.h>
 
-struct INSTALLED_INFO
+class CInstalledApplicationInfo
 {
-    HKEY hRootKey;
+public:
+    BOOL IsUserKey;
+    REGSAM WowKey;
     HKEY hSubKey;
+    BOOL bIsUpdate = FALSE;
+
     ATL::CStringW szKeyName;
 
+    CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM RegWowKey, HKEY hKey);
     BOOL GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& String);
+    BOOL UninstallApplication(BOOL bModify);
+    LSTATUS RemoveFromRegistry();
+
+    ATL::CStringW szDisplayName;
+    ATL::CStringW szDisplayVersion;
+    ATL::CStringW szPublisher;
+    ATL::CStringW szRegOwner;
+    ATL::CStringW szProductID;
+    ATL::CStringW szHelpLink;
+    ATL::CStringW szHelpTelephone;
+    ATL::CStringW szReadme;
+    ATL::CStringW szContact;
+    ATL::CStringW szURLUpdateInfo;
+    ATL::CStringW szURLInfoAbout;
+    ATL::CStringW szComments;
+    ATL::CStringW szInstallDate;
+    ATL::CStringW szInstallLocation;
+    ATL::CStringW szInstallSource;
+    ATL::CStringW szUninstallString;
+    ATL::CStringW szModifyPath;
+
+    ~CInstalledApplicationInfo();
 };
 
-typedef INSTALLED_INFO *PINSTALLED_INFO;
-typedef BOOL(CALLBACK *APPENUMPROC)(INT ItemIndex, ATL::CStringW &Name, 
PINSTALLED_INFO Info, PVOID param);
+typedef BOOL(CALLBACK *APPENUMPROC)(CInstalledApplicationInfo * Info, PVOID 
param);
 
-BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC 
lpEnumProc, PVOID param);
-BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString);
+class CInstalledApps
+{
+    ATL::CAtlList<CInstalledApplicationInfo *> m_InfoList;
+
+public:
+    BOOL Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param);
+
+    VOID FreeCachedEntries();
+};
 
-BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify);
diff --git a/base/applications/rapps/include/misc.h 
b/base/applications/rapps/include/misc.h
index 4c1fc6a4b1d..7e3b1567b65 100644
--- a/base/applications/rapps/include/misc.h
+++ b/base/applications/rapps/include/misc.h
@@ -46,3 +46,5 @@ public:
 };
 
 BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR pszMore);
+
+BOOL IsSystem64Bit();
diff --git a/base/applications/rapps/include/rosui.h 
b/base/applications/rapps/include/rosui.h
index 378e677c053..19ba8d26f0d 100644
--- a/base/applications/rapps/include/rosui.h
+++ b/base/applications/rapps/include/rosui.h
@@ -495,7 +495,10 @@ public:
 
     virtual ~CUiWindow()
     {
-        T::DestroyWindow();
+        if (T::IsWindow())
+        {
+            T::DestroyWindow();
+        }
     }
 
     VOID GetWindowTextW(ATL::CStringW& szText)
diff --git a/base/applications/rapps/installed.cpp 
b/base/applications/rapps/installed.cpp
index c35f141f526..065422762ad 100644
--- a/base/applications/rapps/installed.cpp
+++ b/base/applications/rapps/installed.cpp
@@ -12,149 +12,253 @@
 
 #include "misc.h"
 
-BOOL INSTALLED_INFO::GetApplicationString(LPCWSTR lpKeyName, ATL::CStringW& 
String)
+CInstalledApplicationInfo::CInstalledApplicationInfo(BOOL bIsUserKey, REGSAM 
RegWowKey, HKEY hKey)
+    : IsUserKey(bIsUserKey), WowKey(RegWowKey), hSubKey(hKey)
 {
-    BOOL result = ::GetApplicationString(hSubKey, lpKeyName, 
String.GetBuffer(MAX_PATH));
-    String.ReleaseBuffer();
-    return result;
+    // if Initialize failed, hSubKey will be closed automatically and set to 
zero
+
+    DWORD dwSize = MAX_PATH, dwType, dwValue;
+    BOOL bIsSystemComponent;
+    ATL::CStringW szParentKeyName;
+
+    dwType = REG_DWORD;
+    dwSize = sizeof(DWORD);
+
+    if (RegQueryValueExW(hSubKey,
+        L"SystemComponent",
+        NULL,
+        &dwType,
+        (LPBYTE)&dwValue,
+        &dwSize) == ERROR_SUCCESS)
+    {
+        bIsSystemComponent = (dwValue == 0x1);
+    }
+    else
+    {
+        bIsSystemComponent = FALSE;
+    }
+
+    dwType = REG_SZ;
+    dwSize = MAX_PATH * sizeof(WCHAR);
+    bIsUpdate = (RegQueryValueExW(hSubKey,
+        L"ParentKeyName",
+        NULL,
+        &dwType,
+        (LPBYTE)szParentKeyName.GetBuffer(MAX_PATH),
+        &dwSize) == ERROR_SUCCESS);
+    szParentKeyName.ReleaseBuffer();
+
+    if (bIsSystemComponent)
+    {
+        CloseHandle(hSubKey);
+        hSubKey = NULL;
+    }
+
 }
 
-BOOL GetApplicationString(HKEY hKey, LPCWSTR lpKeyName, LPWSTR szString)
+CInstalledApplicationInfo::~CInstalledApplicationInfo()
 {
-    DWORD dwSize = MAX_PATH * sizeof(WCHAR);
-
-    if (RegQueryValueExW(hKey,
-                         lpKeyName,
-                         NULL,
-                         NULL,
-                         (LPBYTE) szString,
-                         &dwSize) == ERROR_SUCCESS)
+    if (hSubKey)
     {
-        return TRUE;
+        CloseHandle(hSubKey);
+        hSubKey = NULL;
     }
-
-    StringCchCopyW(szString, MAX_PATH, L"---");
-    return FALSE;
 }
 
-BOOL UninstallApplication(PINSTALLED_INFO ItemInfo, BOOL bModify)
+BOOL CInstalledApplicationInfo::GetApplicationString(LPCWSTR lpKeyName, 
ATL::CStringW& String)
 {
-    LPCWSTR szModify = L"ModifyPath";
-    LPCWSTR szUninstall = L"UninstallString";
-    DWORD dwType, dwSize;
-    WCHAR szPath[MAX_PATH];
+    DWORD dwSize = 0;
+    String.Empty();
+    DWORD dwType;
 
-    dwType = REG_SZ;
-    dwSize = MAX_PATH * sizeof(WCHAR);
-    if (RegQueryValueExW(ItemInfo->hSubKey,
-                         bModify ? szModify : szUninstall,
-                         NULL,
-                         &dwType,
-                         (LPBYTE) szPath,
-                         &dwSize) != ERROR_SUCCESS)
+    // retrieve the size of value first.
+    if (RegQueryValueExW(hSubKey,
+        lpKeyName,
+        NULL,
+        &dwType,
+        NULL,
+        &dwSize) != ERROR_SUCCESS)
     {
         return FALSE;
     }
 
-    return StartProcess(szPath, TRUE);
+    // TODO: I assume the type as REG_SZ. but I think REG_EXPAND_SZ should be 
handled correctly too.
+    if (dwType != REG_SZ)
+    {
+        return FALSE;
+    }
+
+    // allocate buffer.
+    // attention: dwSize is size in bytes, and RegQueryValueExW does not 
guarantee the terminating null character.
+    String.GetBuffer(dwSize + sizeof(WCHAR));
+
+    // query the value
+    if (RegQueryValueExW(hSubKey,
+        lpKeyName,
+        NULL,
+        NULL,
+        (LPBYTE)String.GetBuffer(),
+        &dwSize) != ERROR_SUCCESS)
+    {
+        String.ReleaseBuffer();
+        String.Empty();
+        return FALSE;
+    }
+    String.GetBuffer()[dwSize / sizeof(WCHAR)] = L'\0'; // ensure zero 
terminated
+    String.ReleaseBuffer();
+    return TRUE;
 }
 
-BOOL EnumInstalledApplications(INT EnumType, BOOL IsUserKey, APPENUMPROC 
lpEnumProc, PVOID param)
+BOOL CInstalledApplicationInfo::UninstallApplication(BOOL bModify)
 {
-    DWORD dwSize = MAX_PATH, dwType, dwValue;
-    BOOL bIsSystemComponent, bIsUpdate;
-    ATL::CStringW szParentKeyName;
-    ATL::CStringW szDisplayName;
-    INSTALLED_INFO Info;
-    HKEY hKey;
-    LONG ItemIndex = 0;
+    return StartProcess(bModify ? szModifyPath : szUninstallString, TRUE);
+}
+
+LSTATUS CInstalledApplicationInfo::RemoveFromRegistry()
+{
+    ATL::CStringW szFullName = 
L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + szKeyName;
 
-    Info.hRootKey = IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
+    // TODO: if there are subkeys inside, simply RegDeleteKeyExW will fail
+    // we don't have RegDeleteTree for ReactOS now. (It's a WinVista API)
+    // write a function to delete all subkeys recursively to solve this
+    // or consider letting ReactOS having this API
 
-    if (RegOpenKeyW(Info.hRootKey,
-                    L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
-                    &hKey) != ERROR_SUCCESS)
+    return RegDeleteKeyExW(IsUserKey ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, 
szFullName, WowKey, 0);
+}
+
+BOOL CInstalledApps::Enum(INT EnumType, APPENUMPROC lpEnumProc, PVOID param)
+{
+    FreeCachedEntries();
+
+    HKEY RootKeyEnum[3]  = { HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, 
HKEY_LOCAL_MACHINE };
+    REGSAM RegSamEnum[3] = { KEY_WOW64_32KEY,   KEY_WOW64_32KEY,    
KEY_WOW64_64KEY    };
+
+    int LoopTime;
+
+    // test if the OS is 64 bit.
+    if (IsSystem64Bit())
     {
-        return FALSE;
+        // loop for all 3 combination.
+        // note that HKEY_CURRENT_USER\Software don't have a redirect
+        // 
https://docs.microsoft.com/en-us/windows/win32/winprog64/shared-registry-keys#redirected-shared-and-reflected-keys-under-wow64
+        LoopTime = 3;
+    }
+    else
+    {
+        // loop for 2 combination for KEY_WOW64_32KEY only
+        LoopTime = 2;
     }
 
-    while (RegEnumKeyExW(hKey, ItemIndex, Info.szKeyName.GetBuffer(MAX_PATH), 
&dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+    // loop for all combination
+    for (int i = 0; i < LoopTime; i++)
     {
-        Info.szKeyName.ReleaseBuffer();
-        if (RegOpenKeyW(hKey, Info.szKeyName.GetString(), &Info.hSubKey) == 
ERROR_SUCCESS)
+        DWORD dwSize = MAX_PATH;
+        HKEY hKey, hSubKey;
+        LONG ItemIndex = 0;
+        ATL::CStringW szKeyName;
+
+        if (RegOpenKeyExW(RootKeyEnum[i],
+            L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
+            NULL,
+            KEY_READ | RegSamEnum[i],
+            &hKey) != ERROR_SUCCESS)
         {
-            dwType = REG_DWORD;
-            dwSize = sizeof(DWORD);
-
-            if (RegQueryValueExW(Info.hSubKey,
-                                 L"SystemComponent",
-                                 NULL,
-                                 &dwType,
-                                 (LPBYTE) &dwValue,
-                                 &dwSize) == ERROR_SUCCESS)
-            {
-                bIsSystemComponent = (dwValue == 0x1);
-            }
-            else
+            return FALSE;
+        }
+
+        while (1)
+        {
+            dwSize = MAX_PATH;
+            if (RegEnumKeyExW(hKey, ItemIndex, szKeyName.GetBuffer(MAX_PATH), 
&dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
             {
-                bIsSystemComponent = FALSE;
+                break;
             }
 
-            dwType = REG_SZ;
-            dwSize = MAX_PATH * sizeof(WCHAR);
-            bIsUpdate = (RegQueryValueExW(Info.hSubKey,
-                                          L"ParentKeyName",
-                                          NULL,
-                                          &dwType,
-                                          (LPBYTE) 
szParentKeyName.GetBuffer(MAX_PATH),
-                                          &dwSize) == ERROR_SUCCESS);
-            szParentKeyName.ReleaseBuffer();
-
-            dwType = REG_SZ;
-            dwSize = MAX_PATH * sizeof(WCHAR);
-            if (RegQueryValueExW(Info.hSubKey,
-                                 L"DisplayName",
-                                 NULL,
-                                 &dwType,
-                                 (LPBYTE) szDisplayName.GetBuffer(MAX_PATH),
-                                 &dwSize) == ERROR_SUCCESS)
+            ItemIndex++;
+
+            szKeyName.ReleaseBuffer();
+            if (RegOpenKeyW(hKey, szKeyName.GetString(), &hSubKey) == 
ERROR_SUCCESS)
             {
-                szDisplayName.ReleaseBuffer();
-                if (EnumType < ENUM_ALL_INSTALLED || EnumType > ENUM_UPDATES)
-                    EnumType = ENUM_ALL_INSTALLED;
+                BOOL bSuccess = FALSE;
+                CInstalledApplicationInfo *Info = new 
CInstalledApplicationInfo(RootKeyEnum[i] == HKEY_CURRENT_USER, RegSamEnum[i], 
hSubKey);
+                Info->szKeyName = szKeyName;
 
-                if (!bIsSystemComponent)
+                // check for failure. if failed to init, Info->hSubKey will be 
set to NULL
+                if (Info->hSubKey)
                 {
-                    if ((EnumType == ENUM_ALL_INSTALLED) || /* All components 
*/
-                        ((EnumType == ENUM_INSTALLED_APPLICATIONS) && 
(!bIsUpdate)) || /* Applications only */
-                        ((EnumType == ENUM_UPDATES) && (bIsUpdate))) /* 
Updates only */
+                    // those items without display name are ignored
+                    if (Info->GetApplicationString(L"DisplayName", 
Info->szDisplayName))
                     {
-                        if (!lpEnumProc(ItemIndex, szDisplayName, &Info, 
param))
-                            break;
+                        Info->GetApplicationString(L"DisplayVersion", 
Info->szDisplayVersion);
+                        Info->GetApplicationString(L"Publisher", 
Info->szPublisher);
+                        Info->GetApplicationString(L"RegOwner", 
Info->szRegOwner);
+                        Info->GetApplicationString(L"ProductID", 
Info->szProductID);
+                        Info->GetApplicationString(L"HelpLink", 
Info->szHelpLink);
+                        Info->GetApplicationString(L"HelpTelephone", 
Info->szHelpTelephone);
+                        Info->GetApplicationString(L"Readme", Info->szReadme);
+                        Info->GetApplicationString(L"Contact", 
Info->szContact);
+                        Info->GetApplicationString(L"URLUpdateInfo", 
Info->szURLUpdateInfo);
+                        Info->GetApplicationString(L"URLInfoAbout", 
Info->szURLInfoAbout);
+                        Info->GetApplicationString(L"Comments", 
Info->szComments);
+                        Info->GetApplicationString(L"InstallDate", 
Info->szInstallDate);
+                        Info->GetApplicationString(L"InstallLocation", 
Info->szInstallLocation);
+                        Info->GetApplicationString(L"InstallSource", 
Info->szInstallSource);
+                        Info->GetApplicationString(L"UninstallString", 
Info->szUninstallString);
+                        Info->GetApplicationString(L"ModifyPath", 
Info->szModifyPath);
+
+                        bSuccess = TRUE;
                     }
-                    else
+                }
+
+                // close handle
+                if (Info->hSubKey)
+                {
+                    CloseHandle(Info->hSubKey);
+                    Info->hSubKey = NULL;
+                }
+
+                if (bSuccess)
+                {
+                    // add to InfoList.
+                    m_InfoList.AddTail(Info);
+
+                    // invoke callback
+                    if (lpEnumProc)
                     {
-                        RegCloseKey(Info.hSubKey);
+                        if ((EnumType == ENUM_ALL_INSTALLED) || /* All 
components */
+                            ((EnumType == ENUM_INSTALLED_APPLICATIONS) && 
(!Info->bIsUpdate)) || /* Applications only */
+                            ((EnumType == ENUM_UPDATES) && (Info->bIsUpdate))) 
/* Updates only */
+                        {
+                            lpEnumProc(Info, param);
+                        }
                     }
                 }
                 else
                 {
-                    RegCloseKey(Info.hSubKey);
+                    // destory object
+                    delete Info;
                 }
             }
-            else
-            {
-                szDisplayName.ReleaseBuffer();
-                RegCloseKey(Info.hSubKey);
-            }
         }
 
-        dwSize = MAX_PATH;
-        ItemIndex++;
+        szKeyName.ReleaseBuffer();
+        RegCloseKey(hKey);
     }
-
-    Info.szKeyName.ReleaseBuffer();
-    RegCloseKey(hKey);
+    
 
     return TRUE;
 }
+
+VOID CInstalledApps::FreeCachedEntries()
+{
+    POSITION InfoListPosition = m_InfoList.GetHeadPosition();
+
+    /* loop and deallocate all the cached app infos in the list */
+    while (InfoListPosition)
+    {
+        CInstalledApplicationInfo *Info = m_InfoList.GetNext(InfoListPosition);
+        delete Info;
+    }
+
+    m_InfoList.RemoveAll();
+}
diff --git a/base/applications/rapps/misc.cpp b/base/applications/rapps/misc.cpp
index 8e164db8648..90f4e88cd3c 100644
--- a/base/applications/rapps/misc.cpp
+++ b/base/applications/rapps/misc.cpp
@@ -13,6 +13,9 @@
 
 static HANDLE hLog = NULL;
 
+static BOOL bIsSys64ResultCached = FALSE;
+static BOOL bIsSys64Result = FALSE;
+
 INT GetWindowWidth(HWND hwnd)
 {
     RECT Rect;
@@ -453,3 +456,33 @@ BOOL PathAppendNoDirEscapeW(LPWSTR pszPath, LPCWSTR 
pszMore)
 
     return TRUE;
 }
+
+
+
+BOOL IsSystem64Bit()
+{
+    if (bIsSys64ResultCached)
+    {
+        // just return cached result
+        return bIsSys64Result;
+    }
+
+    SYSTEM_INFO si;
+    typedef void (WINAPI *LPFN_PGNSI)(LPSYSTEM_INFO);
+    LPFN_PGNSI pGetNativeSystemInfo = 
(LPFN_PGNSI)GetProcAddress(GetModuleHandle(L"kernel32.dll"), 
"GetNativeSystemInfo");
+    if (pGetNativeSystemInfo)
+    {
+        pGetNativeSystemInfo(&si);
+        if (si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 || 
si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64)
+        {
+            bIsSys64Result = TRUE;
+        }
+    }
+    else
+    {
+        bIsSys64Result = FALSE;
+    }
+
+    bIsSys64ResultCached = TRUE; // next time calling this function, it will 
directly return bIsSys64Result
+    return bIsSys64Result;
+}

Reply via email to