[EXPLORER][SHELL32][USER32] Implement 'Show the Desktop' action of Task Bar (#668)
[reactos.git] / base / shell / explorer / taskswnd.cpp
index 9701ab8..3cadd49 100644 (file)
 #include "precomp.h"
 #include <commoncontrols.h>
 
-#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
-#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))
-
 /* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
    5 seconds */
 #define DUMP_TASKS  0
 #define DEBUG_SHELL_HOOK 0
 
-const WCHAR szTaskSwitchWndClass [] = TEXT("MSTaskSwWClass");
-const WCHAR szRunningApps [] = TEXT("Running Applications");
+#define MAX_TASKS_COUNT (0x7FFF)
+#define TASK_ITEM_ARRAY_ALLOC   64
+
+const WCHAR szTaskSwitchWndClass[] = L"MSTaskSwWClass";
+const WCHAR szRunningApps[] = L"Running Applications";
 
 #if DEBUG_SHELL_HOOK
 const struct {
@@ -83,8 +83,6 @@ typedef struct _TASK_ITEM
     INT Index;
     INT IconIndex;
 
-
-
     union
     {
         DWORD dwFlags;
@@ -101,10 +99,105 @@ typedef struct _TASK_ITEM
     };
 } TASK_ITEM, *PTASK_ITEM;
 
-#define TASK_ITEM_ARRAY_ALLOC   64
+
+class CHardErrorThread
+{
+    DWORD m_ThreadId;
+    HANDLE m_hThread;
+    LONG m_bThreadRunning;
+    DWORD m_Status;
+    DWORD m_dwType;
+    CStringW m_Title;
+    CStringW m_Text;
+public:
+
+    CHardErrorThread():
+        m_ThreadId(0),
+        m_hThread(NULL),
+        m_bThreadRunning(FALSE),
+        m_Status(NULL),
+        m_dwType(NULL)
+    {
+    }
+
+    ~CHardErrorThread()
+    {
+        if (m_bThreadRunning)
+        {
+            /* Try to unstuck Show */
+            PostThreadMessage(m_ThreadId, WM_QUIT, 0, 0);
+            DWORD ret = WaitForSingleObject(m_hThread, 3*1000);
+            if (ret == WAIT_TIMEOUT)
+                TerminateThread(m_hThread, 0);
+            CloseHandle(m_hThread);
+        }
+    }
+
+    HRESULT ThreadProc()
+    {
+        HRESULT hr;
+        CComPtr<IUserNotification> pnotification;
+
+        hr = OleInitialize(NULL);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        hr = CoCreateInstance(CLSID_UserNotification,
+                              NULL,
+                              CLSCTX_INPROC_SERVER,
+                              IID_PPV_ARG(IUserNotification, &pnotification));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        hr = pnotification->SetBalloonInfo(m_Title, m_Text, NIIF_WARNING);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        hr = pnotification->SetIconInfo(NULL, NULL);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        /* Show will block until the balloon closes */
+        hr = pnotification->Show(NULL, 0);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        return S_OK;
+    }
+
+    static DWORD CALLBACK s_HardErrorThreadProc(IN OUT LPVOID lpParameter)
+    {
+        CHardErrorThread* pThis = reinterpret_cast<CHardErrorThread*>(lpParameter);
+        pThis->ThreadProc();
+        CloseHandle(pThis->m_hThread);
+        OleUninitialize();
+        InterlockedExchange(&pThis->m_bThreadRunning, FALSE);
+        return 0;
+    }
+
+    void StartThread(PBALLOON_HARD_ERROR_DATA pData)
+    {
+        BOOL bIsRunning = InterlockedExchange(&m_bThreadRunning, TRUE);
+
+        /* Ignore the new message if we are already showing one */
+        if (bIsRunning)
+            return;
+
+        m_Status = pData->Status;
+        m_dwType = pData->dwType;
+        m_Title = (PWCHAR)((ULONG_PTR)pData + pData->TitleOffset);
+        m_Text = (PWCHAR)((ULONG_PTR)pData + pData->MessageOffset);
+        m_hThread = CreateThread(NULL, 0, s_HardErrorThreadProc, this, 0, &m_ThreadId);
+        if (!m_hThread)
+        {
+            m_bThreadRunning = FALSE;
+            CloseHandle(m_hThread);
+        }
+    }
+};
 
 class CTaskToolbar :
-    public CToolbar<TASK_ITEM>
+    public CWindowImplBaseT< CToolbar<TASK_ITEM>, CControlWinTraits >
 {
 public:
     INT UpdateTbButtonSpacing(IN BOOL bHorizontal, IN BOOL bThemed, IN UINT uiRows = 0, IN UINT uiBtnsPerLine = 0)
@@ -161,8 +254,29 @@ public:
         return SetButtonInfo(iButtonIndex, &tbbi) != 0;
     }
 
+    LRESULT OnNcHitTestToolbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        POINT pt;
+
+        /* See if the mouse is on a button */
+        pt.x = GET_X_LPARAM(lParam);
+        pt.y = GET_Y_LPARAM(lParam);
+        ScreenToClient(&pt);
+
+        INT index = HitTest(&pt);
+        if (index < 0)
+        {
+            /* Make the control appear to be transparent outside of any buttons */
+            return HTTRANSPARENT;
+        }
+
+        bHandled = FALSE;
+        return 0;
+    }
+
 public:
     BEGIN_MSG_MAP(CNotifyToolbar)
+        MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTestToolbar)
     END_MSG_MAP()
 
     BOOL Initialize(HWND hWndParent)
@@ -171,76 +285,68 @@ public:
             TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT |
             CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER;
 
-        return SubclassWindow(Create(hWndParent, styles));
+        return SubclassWindow(CToolbar::Create(hWndParent, styles));
     }
 };
 
 class CTaskSwitchWnd :
-    public CWindowImpl < CTaskSwitchWnd, CWindow, CControlWinTraits >
+    public CComCoClass<CTaskSwitchWnd>,
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public CWindowImpl < CTaskSwitchWnd, CWindow, CControlWinTraits >,
+    public IOleWindow
 {
-    CTaskToolbar TaskBar;
+    CTaskToolbar m_TaskBar;
 
-    HWND hWndNotify;
+    CComPtr<ITrayWindow> m_Tray;
 
-    UINT ShellHookMsg;
-    CComPtr<ITrayWindow> Tray;
+    UINT m_ShellHookMsg;
 
-    PTASK_GROUP TaskGroups;
+    WORD m_TaskItemCount;
+    WORD m_AllocatedTaskItems;
 
-    WORD TaskItemCount;
-    WORD AllocatedTaskItems;
-    PTASK_ITEM TaskItems;
-    PTASK_ITEM ActiveTaskItem;
+    PTASK_GROUP m_TaskGroups;
+    PTASK_ITEM m_TaskItems;
+    PTASK_ITEM m_ActiveTaskItem;
 
-    HTHEME TaskBandTheme;
-    UINT TbButtonsPerLine;
-    WORD ToolbarBtnCount;
+    HTHEME m_Theme;
+    UINT m_ButtonsPerLine;
+    WORD m_ButtonCount;
 
-    HIMAGELIST TaskIcons;
+    HIMAGELIST m_ImageList;
 
-    BOOL IsGroupingEnabled;
-    BOOL IsDestroying;
+    BOOL m_IsGroupingEnabled;
+    BOOL m_IsDestroying;
 
-    SIZE ButtonSize;
-    WCHAR szBuf[255];
+    SIZE m_ButtonSize;
+
+    UINT m_uHardErrorMsg;
+    CHardErrorThread m_HardErrorThread;
 
 public:
     CTaskSwitchWnd() :
-        hWndNotify(NULL),
-        ShellHookMsg(NULL),
-        TaskGroups(NULL),
-        TaskItemCount(0),
-        AllocatedTaskItems(0),
-        TaskItems(0),
-        ActiveTaskItem(0),
-        TaskBandTheme(NULL),
-        TbButtonsPerLine(0),
-        ToolbarBtnCount(0),
-        TaskIcons(NULL),
-        IsGroupingEnabled(FALSE),
-        IsDestroying(FALSE)
-    {
-        ZeroMemory(&ButtonSize, sizeof(ButtonSize));
-        szBuf[0] = 0;
+        m_ShellHookMsg(NULL),
+        m_TaskItemCount(0),
+        m_AllocatedTaskItems(0),
+        m_TaskGroups(NULL),
+        m_TaskItems(NULL),
+        m_ActiveTaskItem(NULL),
+        m_Theme(NULL),
+        m_ButtonsPerLine(0),
+        m_ButtonCount(0),
+        m_ImageList(NULL),
+        m_IsGroupingEnabled(FALSE),
+        m_IsDestroying(FALSE)
+    {
+        ZeroMemory(&m_ButtonSize, sizeof(m_ButtonSize));
+        m_uHardErrorMsg = RegisterWindowMessageW(L"HardError");
     }
     virtual ~CTaskSwitchWnd() { }
 
-#define MAX_TASKS_COUNT (0x7FFF)
-
-    VOID TaskSwitchWnd_UpdateButtonsSize(IN BOOL bRedrawDisabled);
-
-    LPTSTR GetWndTextFromTaskItem(IN PTASK_ITEM TaskItem)
+    INT GetWndTextFromTaskItem(IN PTASK_ITEM TaskItem, LPWSTR szBuf, DWORD cchBuf)
     {
         /* Get the window text without sending a message so we don't hang if an
            application isn't responding! */
-        if (InternalGetWindowText(TaskItem->hWnd,
-            szBuf,
-            sizeof(szBuf) / sizeof(szBuf[0])) > 0)
-        {
-            return szBuf;
-        }
-
-        return NULL;
+        return InternalGetWindowText(TaskItem->hWnd, szBuf, cchBuf);
     }
 
 
@@ -251,15 +357,15 @@ public:
         PTASK_ITEM CurrentTaskItem, LastTaskItem;
 
         TRACE("Tasks dump:\n");
-        if (IsGroupingEnabled)
+        if (m_IsGroupingEnabled)
         {
-            CurrentGroup = TaskGroups;
+            CurrentGroup = m_TaskGroups;
             while (CurrentGroup != NULL)
             {
                 TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup->dwProcessId, CurrentGroup->dwTaskCount, CurrentGroup->Index);
 
-                CurrentTaskItem = TaskItems;
-                LastTaskItem = CurrentTaskItem + TaskItemCount;
+                CurrentTaskItem = m_TaskItems;
+                LastTaskItem = CurrentTaskItem + m_TaskItemCount;
                 while (CurrentTaskItem != LastTaskItem)
                 {
                     if (CurrentTaskItem->Group == CurrentGroup)
@@ -272,8 +378,8 @@ public:
                 CurrentGroup = CurrentGroup->Next;
             }
 
-            CurrentTaskItem = TaskItems;
-            LastTaskItem = CurrentTaskItem + TaskItemCount;
+            CurrentTaskItem = m_TaskItems;
+            LastTaskItem = CurrentTaskItem + m_TaskItemCount;
             while (CurrentTaskItem != LastTaskItem)
             {
                 if (CurrentTaskItem->Group == NULL)
@@ -285,8 +391,8 @@ public:
         }
         else
         {
-            CurrentTaskItem = TaskItems;
-            LastTaskItem = CurrentTaskItem + TaskItemCount;
+            CurrentTaskItem = m_TaskItems;
+            LastTaskItem = CurrentTaskItem + m_TaskItemCount;
             while (CurrentTaskItem != LastTaskItem)
             {
                 TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
@@ -304,10 +410,10 @@ public:
 
         int offset = bInserted ? +1 : -1;
 
-        if (IsGroupingEnabled)
+        if (m_IsGroupingEnabled)
         {
             /* Update all affected groups */
-            CurrentGroup = TaskGroups;
+            CurrentGroup = m_TaskGroups;
             while (CurrentGroup != NULL)
             {
                 if (CurrentGroup->IsCollapsed &&
@@ -315,7 +421,7 @@ public:
                 {
                     /* Update the toolbar buttons */
                     NewIndex = CurrentGroup->Index + offset;
-                    if (TaskBar.SetButtonCommandId(CurrentGroup->Index + offset, NewIndex))
+                    if (m_TaskBar.SetButtonCommandId(CurrentGroup->Index + offset, NewIndex))
                     {
                         CurrentGroup->Index = NewIndex;
                     }
@@ -328,8 +434,8 @@ public:
         }
 
         /* Update all affected task items */
-        CurrentTaskItem = TaskItems;
-        LastTaskItem = CurrentTaskItem + TaskItemCount;
+        CurrentTaskItem = m_TaskItems;
+        LastTaskItem = CurrentTaskItem + m_TaskItemCount;
         while (CurrentTaskItem != LastTaskItem)
         {
             CurrentGroup = CurrentTaskItem->Group;
@@ -346,7 +452,7 @@ public:
             UpdateTaskItemBtn:
                 /* Update the toolbar buttons */
                 NewIndex = CurrentTaskItem->Index + offset;
-                if (TaskBar.SetButtonCommandId(CurrentTaskItem->Index + offset, NewIndex))
+                if (m_TaskBar.SetButtonCommandId(CurrentTaskItem->Index + offset, NewIndex))
                 {
                     CurrentTaskItem->Index = NewIndex;
                 }
@@ -392,11 +498,11 @@ public:
         SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) &hIcon);
         if (hIcon)
             return hIcon;
-        
+
         hIcon = (HICON) GetClassLongPtr(hwnd, GCL_HICONSM);
         if (hIcon)
             return hIcon;
-        
+
         hIcon = (HICON) GetClassLongPtr(hwnd, GCL_HICON);
 
         return hIcon;
@@ -404,15 +510,16 @@ public:
 
     INT UpdateTaskItemButton(IN PTASK_ITEM TaskItem)
     {
-        TBBUTTONINFO tbbi;
+        TBBUTTONINFO tbbi = { 0 };
         HICON icon;
+        WCHAR windowText[255];
 
         ASSERT(TaskItem->Index >= 0);
 
         tbbi.cbSize = sizeof(tbbi);
         tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE;
         tbbi.fsState = TBSTATE_ENABLED;
-        if (ActiveTaskItem == TaskItem)
+        if (m_ActiveTaskItem == TaskItem)
             tbbi.fsState |= TBSTATE_CHECKED;
 
         if (TaskItem->RenderFlashed)
@@ -420,19 +527,24 @@ public:
 
         /* Check if we're updating a button that is the last one in the
            line. If so, we need to set the TBSTATE_WRAP flag! */
-        if (!Tray->IsHorizontal() || (TbButtonsPerLine != 0 &&
-            (TaskItem->Index + 1) % TbButtonsPerLine == 0))
+        if (!m_Tray->IsHorizontal() || (m_ButtonsPerLine != 0 &&
+            (TaskItem->Index + 1) % m_ButtonsPerLine == 0))
         {
             tbbi.fsState |= TBSTATE_WRAP;
         }
 
-        tbbi.pszText = GetWndTextFromTaskItem(TaskItem);
+        if (GetWndTextFromTaskItem(TaskItem, windowText, _countof(windowText)) > 0)
+        {
+            tbbi.pszText = windowText;
+        }
 
         icon = GetWndIcon(TaskItem->hWnd);
-        TaskItem->IconIndex = ImageList_ReplaceIcon(TaskIcons, TaskItem->IconIndex, icon);
+        if (!icon)
+            icon = static_cast<HICON>(LoadImageW(NULL, MAKEINTRESOURCEW(OIC_SAMPLE), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
+        TaskItem->IconIndex = ImageList_ReplaceIcon(m_ImageList, TaskItem->IconIndex, icon);
         tbbi.iImage = TaskItem->IconIndex;
 
-        if (!TaskBar.SetButtonInfo(TaskItem->Index, &tbbi))
+        if (!m_TaskBar.SetButtonInfo(TaskItem->Index, &tbbi))
         {
             TaskItem->Index = -1;
             return -1;
@@ -453,8 +565,8 @@ public:
         tbbi.cbSize = sizeof(tbbi);
         tbbi.dwMask = TBIF_IMAGE;
 
-        currentTaskItem = TaskItems;
-        LastItem = currentTaskItem + TaskItemCount;
+        currentTaskItem = m_TaskItems;
+        LastItem = currentTaskItem + m_TaskItemCount;
         while (currentTaskItem != LastItem)
         {
             if (currentTaskItem->IconIndex > TaskItem->IconIndex)
@@ -462,12 +574,12 @@ public:
                 currentTaskItem->IconIndex--;
                 tbbi.iImage = currentTaskItem->IconIndex;
 
-                TaskBar.SetButtonInfo(currentTaskItem->Index, &tbbi);
+                m_TaskBar.SetButtonInfo(currentTaskItem->Index, &tbbi);
             }
             currentTaskItem++;
         }
 
-        ImageList_Remove(TaskIcons, TaskItem->IconIndex);
+        ImageList_Remove(m_ImageList, TaskItem->IconIndex);
     }
 
     PTASK_ITEM FindLastTaskItemOfGroup(
@@ -477,10 +589,10 @@ public:
         PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL;
         DWORD dwTaskCount;
 
-        ASSERT(IsGroupingEnabled);
+        ASSERT(m_IsGroupingEnabled);
 
-        TaskItem = TaskItems;
-        LastTaskItem = TaskItem + TaskItemCount;
+        TaskItem = m_TaskItems;
+        LastTaskItem = TaskItem + m_TaskItemCount;
 
         dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT);
 
@@ -516,7 +628,7 @@ public:
         /* NOTE: This routine assumes that the group is *not* collapsed! */
 
         TaskGroup = TaskItem->Group;
-        if (IsGroupingEnabled)
+        if (m_IsGroupingEnabled)
         {
             if (TaskGroup != NULL)
             {
@@ -549,12 +661,13 @@ public:
             }
         }
 
-        return ToolbarBtnCount;
+        return m_ButtonCount;
     }
 
     INT AddTaskItemButton(IN OUT PTASK_ITEM TaskItem)
     {
-        TBBUTTON tbBtn;
+        WCHAR windowText[255];
+        TBBUTTON tbBtn = { 0 };
         INT iIndex;
         HICON icon;
 
@@ -571,37 +684,42 @@ public:
         }
 
         icon = GetWndIcon(TaskItem->hWnd);
-        TaskItem->IconIndex = ImageList_ReplaceIcon(TaskIcons, -1, icon);
+        if (!icon)
+            icon = static_cast<HICON>(LoadImageW(NULL, MAKEINTRESOURCEW(OIC_SAMPLE), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE));
+        TaskItem->IconIndex = ImageList_ReplaceIcon(m_ImageList, -1, icon);
 
         tbBtn.iBitmap = TaskItem->IconIndex;
         tbBtn.fsState = TBSTATE_ENABLED | TBSTATE_ELLIPSES;
         tbBtn.fsStyle = BTNS_CHECK | BTNS_NOPREFIX | BTNS_SHOWTEXT;
         tbBtn.dwData = TaskItem->Index;
 
-        tbBtn.iString = (DWORD_PTR) GetWndTextFromTaskItem(TaskItem);
+        if (GetWndTextFromTaskItem(TaskItem, windowText, _countof(windowText)) > 0)
+        {
+            tbBtn.iString = (DWORD_PTR) windowText;
+        }
 
         /* Find out where to insert the new button */
         iIndex = CalculateTaskItemNewButtonIndex(TaskItem);
         ASSERT(iIndex >= 0);
         tbBtn.idCommand = iIndex;
 
-        TaskBar.BeginUpdate();
+        m_TaskBar.BeginUpdate();
 
-        if (TaskBar.InsertButton(iIndex, &tbBtn))
+        if (m_TaskBar.InsertButton(iIndex, &tbBtn))
         {
             UpdateIndexesAfter(iIndex, TRUE);
 
             TRACE("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd);
 
             TaskItem->Index = iIndex;
-            ToolbarBtnCount++;
+            m_ButtonCount++;
 
             /* Update button sizes and fix the button wrapping */
             UpdateButtonsSize(TRUE);
             return iIndex;
         }
 
-        TaskBar.EndUpdate();
+        m_TaskBar.EndUpdate();
 
         return -1;
     }
@@ -618,14 +736,14 @@ public:
             if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) ||
                 TaskGroup == NULL)
             {
-                TaskBar.BeginUpdate();
+                m_TaskBar.BeginUpdate();
 
                 RemoveIcon(TaskItem);
                 iIndex = TaskItem->Index;
-                if (TaskBar.DeleteButton(iIndex))
+                if (m_TaskBar.DeleteButton(iIndex))
                 {
                     TaskItem->Index = -1;
-                    ToolbarBtnCount--;
+                    m_ButtonCount--;
 
                     UpdateIndexesAfter(iIndex, FALSE);
 
@@ -634,7 +752,7 @@ public:
                     return TRUE;
                 }
 
-                TaskBar.EndUpdate();
+                m_TaskBar.EndUpdate();
             }
         }
 
@@ -654,8 +772,8 @@ public:
         }
 
         /* Try to find an existing task group */
-        TaskGroup = TaskGroups;
-        PrevLink = &TaskGroups;
+        TaskGroup = m_TaskGroups;
+        PrevLink = &m_TaskGroups;
         while (TaskGroup != NULL)
         {
             if (TaskGroup->dwProcessId == dwProcessId)
@@ -696,8 +814,8 @@ public:
             if (dwNewTaskCount == 0)
             {
                 /* Find the previous pointer in the chain */
-                CurrentGroup = TaskGroups;
-                PrevLink = &TaskGroups;
+                CurrentGroup = m_TaskGroups;
+                PrevLink = &m_TaskGroups;
                 while (CurrentGroup != TaskGroup)
                 {
                     PrevLink = &CurrentGroup->Next;
@@ -735,8 +853,8 @@ public:
     {
         PTASK_ITEM TaskItem, LastItem;
 
-        TaskItem = TaskItems;
-        LastItem = TaskItem + TaskItemCount;
+        TaskItem = m_TaskItems;
+        LastItem = TaskItem + m_TaskItemCount;
         while (TaskItem != LastItem)
         {
             if (TaskItem->hWnd == hWnd)
@@ -761,8 +879,8 @@ public:
 
         /* Try to find another task that belongs to the same
            process as the given window */
-        TaskItem = TaskItems;
-        LastItem = TaskItem + TaskItemCount;
+        TaskItem = m_TaskItems;
+        LastItem = TaskItem + m_TaskItemCount;
         while (TaskItem != LastItem)
         {
             TaskGroup = TaskItem->Group;
@@ -791,77 +909,77 @@ public:
 
     PTASK_ITEM AllocTaskItem()
     {
-        if (TaskItemCount >= MAX_TASKS_COUNT)
+        if (m_TaskItemCount >= MAX_TASKS_COUNT)
         {
             /* We need the most significant bit in 16 bit command IDs to indicate whether it
                is a task group or task item. WM_COMMAND limits command IDs to 16 bits! */
             return NULL;
         }
 
-        ASSERT(AllocatedTaskItems >= TaskItemCount);
+        ASSERT(m_AllocatedTaskItems >= m_TaskItemCount);
 
-        if (TaskItemCount == 0)
+        if (m_TaskItemCount == 0)
         {
-            TaskItems = (PTASK_ITEM) HeapAlloc(hProcessHeap,
+            m_TaskItems = (PTASK_ITEM) HeapAlloc(hProcessHeap,
                 0,
-                TASK_ITEM_ARRAY_ALLOC * sizeof(*TaskItems));
-            if (TaskItems != NULL)
+                TASK_ITEM_ARRAY_ALLOC * sizeof(*m_TaskItems));
+            if (m_TaskItems != NULL)
             {
-                AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC;
+                m_AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC;
             }
             else
                 return NULL;
         }
-        else if (TaskItemCount >= AllocatedTaskItems)
+        else if (m_TaskItemCount >= m_AllocatedTaskItems)
         {
             PTASK_ITEM NewArray;
             SIZE_T NewArrayLength, ActiveTaskItemIndex;
 
-            NewArrayLength = AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC;
+            NewArrayLength = m_AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC;
 
             NewArray = (PTASK_ITEM) HeapReAlloc(hProcessHeap,
                 0,
-                TaskItems,
-                NewArrayLength * sizeof(*TaskItems));
+                m_TaskItems,
+                NewArrayLength * sizeof(*m_TaskItems));
             if (NewArray != NULL)
             {
-                if (ActiveTaskItem != NULL)
+                if (m_ActiveTaskItem != NULL)
                 {
                     /* Fixup the ActiveTaskItem pointer */
-                    ActiveTaskItemIndex = ActiveTaskItem - TaskItems;
-                    ActiveTaskItem = NewArray + ActiveTaskItemIndex;
+                    ActiveTaskItemIndex = m_ActiveTaskItem - m_TaskItems;
+                    m_ActiveTaskItem = NewArray + ActiveTaskItemIndex;
                 }
-                AllocatedTaskItems = (WORD) NewArrayLength;
-                TaskItems = NewArray;
+                m_AllocatedTaskItems = (WORD) NewArrayLength;
+                m_TaskItems = NewArray;
             }
             else
                 return NULL;
         }
 
-        return TaskItems + TaskItemCount++;
+        return m_TaskItems + m_TaskItemCount++;
     }
 
     VOID FreeTaskItem(IN OUT PTASK_ITEM TaskItem)
     {
         WORD wIndex;
 
-        if (TaskItem == ActiveTaskItem)
-            ActiveTaskItem = NULL;
+        if (TaskItem == m_ActiveTaskItem)
+            m_ActiveTaskItem = NULL;
 
-        wIndex = (WORD) (TaskItem - TaskItems);
-        if (wIndex + 1 < TaskItemCount)
+        wIndex = (WORD) (TaskItem - m_TaskItems);
+        if (wIndex + 1 < m_TaskItemCount)
         {
             MoveMemory(TaskItem,
                 TaskItem + 1,
-                (TaskItemCount - wIndex - 1) * sizeof(*TaskItem));
+                (m_TaskItemCount - wIndex - 1) * sizeof(*TaskItem));
         }
 
-        TaskItemCount--;
+        m_TaskItemCount--;
     }
 
     VOID DeleteTaskItem(IN OUT PTASK_ITEM TaskItem)
     {
-        if (!IsDestroying)
+        if (!m_IsDestroying)
         {
             /* Delete the task button from the toolbar */
             DeleteTaskItemButton(TaskItem);
@@ -879,12 +997,12 @@ public:
         PTASK_ITEM CurrentTaskItem;
         PTASK_GROUP TaskGroup = NULL;
 
-        CurrentTaskItem = ActiveTaskItem;
+        CurrentTaskItem = m_ActiveTaskItem;
 
         if (TaskItem != NULL)
             TaskGroup = TaskItem->Group;
 
-        if (IsGroupingEnabled &&
+        if (m_IsGroupingEnabled &&
             TaskGroup != NULL &&
             TaskGroup->IsCollapsed)
         {
@@ -901,7 +1019,7 @@ public:
 
             CurrentTaskGroup = CurrentTaskItem->Group;
 
-            if (IsGroupingEnabled &&
+            if (m_IsGroupingEnabled &&
                 CurrentTaskGroup != NULL &&
                 CurrentTaskGroup->IsCollapsed)
             {
@@ -912,7 +1030,7 @@ public:
             }
             else
             {
-                ActiveTaskItem = NULL;
+                m_ActiveTaskItem = NULL;
                 if (CurrentTaskItem->Index >= 0)
                 {
                     UpdateTaskItemButton(CurrentTaskItem);
@@ -920,7 +1038,7 @@ public:
             }
         }
 
-        ActiveTaskItem = TaskItem;
+        m_ActiveTaskItem = TaskItem;
 
         if (TaskItem != NULL && TaskItem->Index >= 0)
         {
@@ -936,8 +1054,8 @@ public:
     {
         PTASK_ITEM TaskItem, LastItem;
 
-        TaskItem = TaskItems;
-        LastItem = TaskItem + TaskItemCount;
+        TaskItem = m_TaskItems;
+        LastItem = TaskItem + m_TaskItemCount;
         while (TaskItem != LastItem)
         {
             if (TaskItem->Index == Index)
@@ -953,7 +1071,7 @@ public:
     {
         PTASK_GROUP CurrentGroup;
 
-        CurrentGroup = TaskGroups;
+        CurrentGroup = m_TaskGroups;
         while (CurrentGroup != NULL)
         {
             if (CurrentGroup->Index == Index)
@@ -969,7 +1087,7 @@ public:
     {
         PTASK_ITEM TaskItem;
 
-        if (!::IsWindow(hWnd) || Tray->IsSpecialHWND(hWnd))
+        if (!::IsWindow(hWnd) || m_Tray->IsSpecialHWND(hWnd))
             return FALSE;
 
         TaskItem = FindTaskItem(hWnd);
@@ -979,13 +1097,12 @@ public:
             TaskItem = AllocTaskItem();
             if (TaskItem != NULL)
             {
-                ZeroMemory(TaskItem,
-                    sizeof(*TaskItem));
+                ZeroMemory(TaskItem, sizeof(*TaskItem));
                 TaskItem->hWnd = hWnd;
                 TaskItem->Index = -1;
                 TaskItem->Group = AddToTaskGroup(hWnd);
 
-                if (!IsDestroying)
+                if (!m_IsDestroying)
                 {
                     AddTaskItemButton(TaskItem);
                 }
@@ -1052,13 +1169,13 @@ public:
     {
         PTASK_ITEM CurrentTask;
 
-        if (TaskItemCount > 0)
+        if (m_TaskItemCount > 0)
         {
-            CurrentTask = TaskItems + TaskItemCount;
+            CurrentTask = m_TaskItems + m_TaskItemCount;
             do
             {
                 DeleteTaskItem(--CurrentTask);
-            } while (CurrentTask != TaskItems);
+            } while (CurrentTask != m_TaskItems);
         }
     }
 
@@ -1088,7 +1205,7 @@ public:
         PTASK_GROUP TaskGroup;
 
         TaskGroup = TaskItem->Group;
-        if (IsGroupingEnabled && TaskGroup != NULL)
+        if (m_IsGroupingEnabled && TaskGroup != NULL)
         {
             if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0)
             {
@@ -1129,39 +1246,61 @@ public:
         LONG NewBtnSize;
         BOOL Horizontal;
 
+        /* Update the size of the image list if needed */
+        int cx, cy;
+        ImageList_GetIconSize(m_ImageList, &cx, &cy);
+        if (cx != GetSystemMetrics(SM_CXSMICON) || cy != GetSystemMetrics(SM_CYSMICON))
+        {
+            ImageList_SetIconSize(m_ImageList, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
+
+            /* SetIconSize removes all icons so we have to reinsert them */
+            PTASK_ITEM TaskItem = m_TaskItems;
+            PTASK_ITEM LastTaskItem = m_TaskItems + m_TaskItemCount;
+            while (TaskItem != LastTaskItem)
+            {
+                TaskItem->IconIndex = -1;
+                UpdateTaskItemButton(TaskItem);
+
+                TaskItem++;
+            }
+            m_TaskBar.SetImageList(m_ImageList);
+        }
+
         if (GetClientRect(&rcClient) && !IsRectEmpty(&rcClient))
         {
-            if (ToolbarBtnCount > 0)
+            if (m_ButtonCount > 0)
             {
-                Horizontal = Tray->IsHorizontal();
+                Horizontal = m_Tray->IsHorizontal();
 
                 if (Horizontal)
                 {
-                    DbgPrint("HORIZONTAL!\n");
                     TBMETRICS tbm = { 0 };
                     tbm.cbSize = sizeof(tbm);
                     tbm.dwMask = TBMF_BUTTONSPACING;
-                    TaskBar.GetMetrics(&tbm);
+                    m_TaskBar.GetMetrics(&tbm);
+
+                    if (m_ButtonSize.cy + tbm.cyButtonSpacing != 0)
+                        uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (m_ButtonSize.cy + tbm.cyButtonSpacing);
+                    else
+                        uiRows = 1;
 
-                    uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (ButtonSize.cy + tbm.cyButtonSpacing);
                     if (uiRows == 0)
                         uiRows = 1;
 
-                    uiBtnsPerLine = (ToolbarBtnCount + uiRows - 1) / uiRows;
+                    uiBtnsPerLine = (m_ButtonCount + uiRows - 1) / uiRows;
                 }
                 else
                 {
-                    DbgPrint("VERTICAL!\n");
                     uiBtnsPerLine = 1;
-                    uiRows = ToolbarBtnCount;
+                    uiRows = m_ButtonCount;
                 }
 
                 if (!bRedrawDisabled)
-                    TaskBar.BeginUpdate();
+                    m_TaskBar.BeginUpdate();
 
                 /* We might need to update the button spacing */
-                int cxButtonSpacing = TaskBar.UpdateTbButtonSpacing(
-                    Horizontal, TaskBandTheme != NULL,
+                int cxButtonSpacing = m_TaskBar.UpdateTbButtonSpacing(
+                    Horizontal, m_Theme != NULL,
                     uiRows, uiBtnsPerLine);
 
                 /* Determine the minimum and maximum width of a button */
@@ -1188,11 +1327,11 @@ public:
                     NewBtnSize = uiMax = rcClient.right;
                 }
 
-                ButtonSize.cx = NewBtnSize;
+                m_ButtonSize.cx = NewBtnSize;
 
-                TbButtonsPerLine = uiBtnsPerLine;
+                m_ButtonsPerLine = uiBtnsPerLine;
 
-                for (ui = 0; ui != ToolbarBtnCount; ui++)
+                for (ui = 0; ui != m_ButtonCount; ui++)
                 {
                     TBBUTTONINFOW tbbi = { 0 };
                     tbbi.cbSize = sizeof(tbbi);
@@ -1212,24 +1351,24 @@ public:
                         tbbi.fsState |= TBSTATE_WRAP;
                     }
 
-                    if (ActiveTaskItem != NULL &&
-                        ActiveTaskItem->Index == (INT)ui)
+                    if (m_ActiveTaskItem != NULL &&
+                        m_ActiveTaskItem->Index == (INT)ui)
                     {
                         tbbi.fsState |= TBSTATE_CHECKED;
                     }
 
-                    TaskBar.SetButtonInfo(ui, &tbbi);
+                    m_TaskBar.SetButtonInfo(ui, &tbbi);
                 }
             }
             else
             {
-                TbButtonsPerLine = 0;
-                ButtonSize.cx = 0;
+                m_ButtonsPerLine = 0;
+                m_ButtonSize.cx = 0;
             }
         }
 
         // FIXME: This seems to be enabling redraws prematurely, but moving it to its right place doesn't work!
-        TaskBar.EndUpdate();
+        m_TaskBar.EndUpdate();
     }
 
     BOOL CALLBACK EnumWindowsProc(IN HWND hWnd)
@@ -1237,11 +1376,11 @@ public:
         /* Only show windows that still exist and are visible and none of explorer's
         special windows (such as the desktop or the tray window) */
         if (::IsWindow(hWnd) && ::IsWindowVisible(hWnd) &&
-            !Tray->IsSpecialHWND(hWnd))
+            !m_Tray->IsSpecialHWND(hWnd))
         {
-            DWORD exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
+            DWORD exStyle = ::GetWindowLong(hWnd, GWL_EXSTYLE);
             /* Don't list popup windows and also no tool windows */
-            if ((GetWindow(hWnd, GW_OWNER) == NULL || exStyle & WS_EX_APPWINDOW) &&
+            if ((::GetWindow(hWnd, GW_OWNER) == NULL || exStyle & WS_EX_APPWINDOW) &&
                 !(exStyle & WS_EX_TOOLWINDOW))
             {
                 TRACE("Adding task for %p...\n", hWnd);
@@ -1267,63 +1406,40 @@ public:
         return EnumWindows(s_EnumWindowsProc, (LPARAM)this);
     }
 
-    LRESULT OnThemeChanged()
+    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         TRACE("OmThemeChanged\n");
 
-        if (TaskBandTheme)
-            CloseThemeData(TaskBandTheme);
+        if (m_Theme)
+            CloseThemeData(m_Theme);
 
         if (IsThemeActive())
-            TaskBandTheme = OpenThemeData(m_hWnd, L"TaskBand");
+            m_Theme = OpenThemeData(m_hWnd, L"TaskBand");
         else
-            TaskBandTheme = NULL;
+            m_Theme = NULL;
 
         return TRUE;
     }
 
-    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
-    {        
-        return OnThemeChanged();
-    }
-
     LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        if (!TaskBar.Initialize(m_hWnd))
+        if (!m_TaskBar.Initialize(m_hWnd))
             return FALSE;
 
-        SetWindowTheme(TaskBar.m_hWnd, L"TaskBand", NULL);
-        OnThemeChanged();
+        SetWindowTheme(m_TaskBar.m_hWnd, L"TaskBand", NULL);
 
-        TaskIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000);
-        TaskBar.SetImageList(TaskIcons);
-
-        /* Calculate the default button size. Don't save this in ButtonSize.cx so that
-        the actual button width gets updated correctly on the first recalculation */
-        int cx = GetSystemMetrics(SM_CXMINIMIZED);
-        int cy = ButtonSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
-        TaskBar.SetButtonSize(cx, cy);
+        m_ImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 0, 1000);
+        m_TaskBar.SetImageList(m_ImageList);
 
         /* Set proper spacing between buttons */
-        TaskBar.UpdateTbButtonSpacing(Tray->IsHorizontal(), TaskBandTheme != NULL);
+        m_TaskBar.UpdateTbButtonSpacing(m_Tray->IsHorizontal(), m_Theme != NULL);
 
         /* Register the shell hook */
-        ShellHookMsg = RegisterWindowMessage(TEXT("SHELLHOOK"));
-
-        TRACE("ShellHookMsg got assigned number %d\n", ShellHookMsg);
+        m_ShellHookMsg = RegisterWindowMessageW(L"SHELLHOOK");
 
-        HMODULE hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-        if (hShell32 != NULL)
-        {
-            REGSHELLHOOK RegShellHook;
+        TRACE("ShellHookMsg got assigned number %d\n", m_ShellHookMsg);
 
-            /* RegisterShellHook */
-            RegShellHook = (REGSHELLHOOK) GetProcAddress(hShell32, (LPCSTR) ((LONG) 181));
-            if (RegShellHook != NULL)
-            {
-                RegShellHook(m_hWnd, 3); /* 1 if no NT! We're targeting NT so we don't care! */
-            }
-        }
+        RegisterShellHook(m_hWnd, 3); /* 1 if no NT! We're targeting NT so we don't care! */
 
         RefreshWindowList();
 
@@ -1338,27 +1454,12 @@ public:
 
     LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        HMODULE hShell32;
-
-        IsDestroying = TRUE;
+        m_IsDestroying = TRUE;
 
         /* Unregister the shell hook */
-        hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-        if (hShell32 != NULL)
-        {
-            REGSHELLHOOK RegShellHook;
+        RegisterShellHook(m_hWnd, FALSE);
 
-            /* RegisterShellHook */
-            RegShellHook = (REGSHELLHOOK) GetProcAddress(hShell32,
-                (LPCSTR) ((LONG) 181));
-            if (RegShellHook != NULL)
-            {
-                RegShellHook(m_hWnd,
-                    FALSE);
-            }
-        }
-
-        CloseThemeData(TaskBandTheme);
+        CloseThemeData(m_Theme);
         DeleteAllTasks();
         return TRUE;
     }
@@ -1383,8 +1484,8 @@ public:
 
         return Ret;
     }
-    
-    LRESULT HandleShellHookMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+
+    LRESULT OnShellHook(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         BOOL Ret = FALSE;
 
@@ -1400,41 +1501,33 @@ public:
         switch ((INT) wParam)
         {
         case HSHELL_APPCOMMAND:
-            HandleAppCommand(wParam, lParam);
-            Ret = TRUE;
+            Ret = HandleAppCommand(wParam, lParam);
             break;
 
         case HSHELL_WINDOWCREATED:
-            Ret = AddTask((HWND) lParam);
+            AddTask((HWND) lParam);
             break;
 
         case HSHELL_WINDOWDESTROYED:
             /* The window still exists! Delay destroying it a bit */
             DeleteTask((HWND) lParam);
-            Ret = TRUE;
             break;
 
         case HSHELL_RUDEAPPACTIVATED:
         case HSHELL_WINDOWACTIVATED:
-            if (lParam)
-            {
-                ActivateTask((HWND) lParam);
-                Ret = TRUE;
-            }
+            ActivateTask((HWND) lParam);
             break;
 
         case HSHELL_FLASH:
             FlashTask((HWND) lParam);
-            Ret = TRUE;
             break;
 
         case HSHELL_REDRAW:
             RedrawTask((HWND) lParam);
-            Ret = TRUE;
             break;
 
         case HSHELL_TASKMAN:
-            PostMessage(Tray->GetHWND(), TWM_OPENSTARTMENU, 0, 0);
+            ::PostMessage(m_Tray->GetHWND(), TWM_OPENSTARTMENU, 0, 0);
             break;
 
         case HSHELL_ACTIVATESHELLWINDOW:
@@ -1450,7 +1543,7 @@ public:
         {
 #if DEBUG_SHELL_HOOK
             int i, found;
-            for (i = 0, found = 0; i != sizeof(hshell_msg) / sizeof(hshell_msg[0]); i++)
+            for (i = 0, found = 0; i != _countof(hshell_msg); i++)
             {
                 if (hshell_msg[i].msg == (INT) wParam)
                 {
@@ -1470,14 +1563,6 @@ public:
         return Ret;
     }
 
-    VOID EnableGrouping(IN BOOL bEnable)
-    {
-        IsGroupingEnabled = bEnable;
-
-        /* Collapse or expand groups if neccessary */
-        UpdateButtonsSize(FALSE);
-    }
-
     VOID HandleTaskItemClick(IN OUT PTASK_ITEM TaskItem)
     {
         BOOL bIsMinimized;
@@ -1485,37 +1570,25 @@ public:
 
         if (::IsWindow(TaskItem->hWnd))
         {
-            bIsMinimized = IsIconic(TaskItem->hWnd);
-            bIsActive = (TaskItem == ActiveTaskItem);
+            bIsMinimized = ::IsIconic(TaskItem->hWnd);
+            bIsActive = (TaskItem == m_ActiveTaskItem);
 
-            TRACE("Active TaskItem %p, selected TaskItem %p\n", ActiveTaskItem, TaskItem);
-            if (ActiveTaskItem)
-                TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", ActiveTaskItem->hWnd, TaskItem->hWnd);
+            TRACE("Active TaskItem %p, selected TaskItem %p\n", m_ActiveTaskItem, TaskItem);
+            if (m_ActiveTaskItem)
+                TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", m_ActiveTaskItem->hWnd, TaskItem->hWnd);
 
             TRACE("Valid button clicked. HWND=%p, IsMinimized=%s, IsActive=%s...\n",
                 TaskItem->hWnd, bIsMinimized ? "Yes" : "No", bIsActive ? "Yes" : "No");
 
             if (!bIsMinimized && bIsActive)
             {
-                PostMessage(TaskItem->hWnd,
-                    WM_SYSCOMMAND,
-                    SC_MINIMIZE,
-                    0);
+                ::ShowWindowAsync(TaskItem->hWnd, SW_MINIMIZE);
                 TRACE("Valid button clicked. App window Minimized.\n");
             }
             else
             {
-                if (bIsMinimized)
-                {
-                    PostMessage(TaskItem->hWnd,
-                        WM_SYSCOMMAND,
-                        SC_RESTORE,
-                        0);
-                    TRACE("Valid button clicked. App window Restored.\n");
-                }
-
-                SetForegroundWindow(TaskItem->hWnd);
-                TRACE("Valid button clicked. App window Activated.\n");
+                ::SwitchToThisWindow(TaskItem->hWnd, TRUE);
+                TRACE("Valid button clicked. App window Restored.\n");
             }
         }
     }
@@ -1530,7 +1603,7 @@ public:
         PTASK_ITEM TaskItem;
         PTASK_GROUP TaskGroup;
 
-        if (IsGroupingEnabled)
+        if (m_IsGroupingEnabled)
         {
             TaskGroup = FindTaskGroupByIndex((INT) wIndex);
             if (TaskGroup != NULL && TaskGroup->IsCollapsed)
@@ -1553,21 +1626,14 @@ public:
 
     VOID HandleTaskItemRightClick(IN OUT PTASK_ITEM TaskItem)
     {
+        POINT pt;
+        GetCursorPos(&pt);
 
-        HMENU hmenu = GetSystemMenu(TaskItem->hWnd, FALSE);
+        SetForegroundWindow(TaskItem->hWnd);
 
-        if (hmenu) 
-        {
-            POINT pt;
-            int cmd;
-            GetCursorPos(&pt);
-            cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, TaskBar.m_hWnd, NULL);
-            if (cmd)
-            {
-                SetForegroundWindow(TaskItem->hWnd);    // reactivate window after the context menu has closed
-                PostMessage(TaskItem->hWnd, WM_SYSCOMMAND, cmd, 0);
-            }
-        }
+        ActivateTask(TaskItem->hWnd);
+
+        ::SendMessageW(TaskItem->hWnd, WM_POPUPSYSTEMMENU, 0, MAKELPARAM(pt.x, pt.y));
     }
 
     VOID HandleTaskGroupRightClick(IN OUT PTASK_GROUP TaskGroup)
@@ -1579,7 +1645,7 @@ public:
     {
         PTASK_ITEM TaskItem;
         PTASK_GROUP TaskGroup;
-        if (IsGroupingEnabled)
+        if (m_IsGroupingEnabled)
         {
             TaskGroup = FindTaskGroupByIndex((INT) wIndex);
             if (TaskGroup != NULL && TaskGroup->IsCollapsed)
@@ -1615,11 +1681,11 @@ public:
 
             if (TaskItem != NULL && ::IsWindow(TaskItem->hWnd))
             {
-                /* Make the entire button flashing if neccessary */
+                /* Make the entire button flashing if necessary */
                 if (nmtbcd->nmcd.uItemState & CDIS_MARKED)
                 {
                     Ret = TBCDRF_NOBACKGROUND;
-                    if (!TaskBandTheme)
+                    if (!m_Theme)
                     {
                         SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT));
                         Rectangle(nmtbcd->nmcd.hdc,
@@ -1630,7 +1696,7 @@ public:
                     }
                     else
                     {
-                        DrawThemeBackground(TaskBandTheme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0);
+                        DrawThemeBackground(m_Theme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0);
                     }
                     nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
                     return Ret;
@@ -1676,16 +1742,6 @@ public:
         return Ret;
     }
 
-    LRESULT DrawBackground(HDC hdc)
-    {
-        RECT rect;
-
-        GetClientRect(&rect);
-        DrawThemeParentBackground(m_hWnd, hdc, &rect);
-
-        return TRUE;
-    }
-
     LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         HDC hdc = (HDC) wParam;
@@ -1696,7 +1752,11 @@ public:
             return 0;
         }
 
-        return DrawBackground(hdc);
+        RECT rect;
+        GetClientRect(&rect);
+        DrawThemeParentBackground(m_hWnd, hdc, &rect);
+
+        return TRUE;
     }
 
     LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
@@ -1705,35 +1765,15 @@ public:
 
         szClient.cx = LOWORD(lParam);
         szClient.cy = HIWORD(lParam);
-        if (TaskBar.m_hWnd != NULL)
+        if (m_TaskBar.m_hWnd != NULL)
         {
-            TaskBar.SetWindowPos(NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER);
+            m_TaskBar.SetWindowPos(NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER);
 
             UpdateButtonsSize(FALSE);
         }
         return TRUE;
     }
 
-    LRESULT OnNcHitTestToolbar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
-    {
-        POINT pt;
-
-        /* See if the mouse is on a button */
-        pt.x = GET_X_LPARAM(lParam);
-        pt.y = GET_Y_LPARAM(lParam);
-        ScreenToClient(&pt);
-
-        INT index = TaskBar.SendMessage(TB_HITTEST, 0, (LPARAM) &pt);
-        if (index < 0)
-        {
-            /* Make the control appear to be transparent outside of any buttons */
-            return HTTRANSPARENT;
-        }
-
-        bHandled = FALSE;
-        return 0;
-    }
-
     LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         LRESULT Ret = TRUE;
@@ -1748,7 +1788,7 @@ public:
     LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         LRESULT Ret = TRUE;
-        if (lParam != 0 && (HWND) lParam == TaskBar.m_hWnd)
+        if (lParam != 0 && (HWND) lParam == m_TaskBar.m_hWnd)
         {
             HandleButtonClick(LOWORD(wParam));
         }
@@ -1760,56 +1800,60 @@ public:
         LRESULT Ret = TRUE;
         const NMHDR *nmh = (const NMHDR *) lParam;
 
-        if (nmh->hwndFrom == TaskBar.m_hWnd)
+        if (nmh->hwndFrom == m_TaskBar.m_hWnd)
         {
             Ret = HandleToolbarNotification(nmh);
         }
         return Ret;
     }
 
-    LRESULT OnEnableGrouping(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
-    {
-        LRESULT Ret = IsGroupingEnabled;
-        if ((BOOL)wParam != IsGroupingEnabled)
-        {
-            EnableGrouping((BOOL) wParam);
-        }
-        return Ret;
-    }
-
     LRESULT OnUpdateTaskbarPos(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
         /* Update the button spacing */
-        TaskBar.UpdateTbButtonSpacing(Tray->IsHorizontal(), TaskBandTheme != NULL);
+        m_TaskBar.UpdateTbButtonSpacing(m_Tray->IsHorizontal(), m_Theme != NULL);
         return TRUE;
     }
 
+    LRESULT OnTaskbarSettingsChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        TaskbarSettings* newSettings = (TaskbarSettings*)lParam;
+        if (newSettings->bGroupButtons != g_TaskbarSettings.bGroupButtons)
+        {
+            g_TaskbarSettings.bGroupButtons = newSettings->bGroupButtons;
+            m_IsGroupingEnabled = g_TaskbarSettings.bGroupButtons;
+
+            /* Collapse or expand groups if necessary */
+            RefreshWindowList();
+            UpdateButtonsSize(FALSE);
+        }
+
+        return 0;
+    }
+
     LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
-        LRESULT Ret;
-        if (TaskBar.m_hWnd != NULL)
+        LRESULT Ret = 0;
+        INT_PTR iBtn = -1;
+
+        if (m_TaskBar.m_hWnd != NULL)
         {
             POINT pt;
-            INT_PTR iBtn;
 
             pt.x = GET_X_LPARAM(lParam);
             pt.y = GET_Y_LPARAM(lParam);
 
-            ::ScreenToClient(TaskBar.m_hWnd, &pt);
+            ::ScreenToClient(m_TaskBar.m_hWnd, &pt);
 
-            iBtn = TaskBar.HitTest(&pt);
+            iBtn = m_TaskBar.HitTest(&pt);
             if (iBtn >= 0)
             {
                 HandleButtonRightClick(iBtn);
             }
-            else
-                goto ForwardContextMenuMsg;
         }
-        else
+        if (iBtn < 0)
         {
-        ForwardContextMenuMsg:
-            /* Forward message */
-            Ret = SendMessage(Tray->GetHWND(), uMsg, wParam, lParam);
+            /* Not on a taskbar button, so forward message to tray */
+            Ret = SendMessage(m_Tray->GetHWND(), uMsg, wParam, lParam);
         }
         return Ret;
     }
@@ -1821,8 +1865,8 @@ public:
         {
             RECT* prcMinRect = (RECT*) lParam;
             RECT rcItem, rcToolbar;
-            TaskBar.GetItemRect(TaskItem->Index, &rcItem);
-            GetWindowRect(TaskBar.m_hWnd, &rcToolbar);
+            m_TaskBar.GetItemRect(TaskItem->Index, &rcItem);
+            m_TaskBar.GetWindowRect(&rcToolbar);
 
             OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top);
 
@@ -1832,6 +1876,11 @@ public:
         return FALSE;
     }
 
+    LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return MA_NOACTIVATE;
+    }
+
     LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
     {
 #if DUMP_TASKS != 0
@@ -1845,6 +1894,61 @@ public:
         return TRUE;
     }
 
+    LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return m_TaskBar.SendMessageW(uMsg, wParam, lParam);
+    }
+
+    LRESULT OnSettingChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (wParam == SPI_SETNONCLIENTMETRICS)
+        {
+            /*  Don't update the font, this will be done when we get a WM_SETFONT from our parent */
+            UpdateButtonsSize(FALSE);
+        }
+
+        return 0;
+    }
+
+    LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam;
+        if (cpData->dwData == m_uHardErrorMsg)
+        {
+            /* A hard error balloon message */
+            PBALLOON_HARD_ERROR_DATA pData = (PBALLOON_HARD_ERROR_DATA)cpData->lpData;
+            ERR("Got balloon data 0x%x, 0x%x, %S, %S!\n", pData->Status, pData->dwType, (WCHAR*)((ULONG_PTR)pData + pData->TitleOffset), (WCHAR*)((ULONG_PTR)pData + pData->MessageOffset));
+            if (pData->cbHeaderSize == sizeof(BALLOON_HARD_ERROR_DATA))
+                m_HardErrorThread.StartThread(pData);
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
+    HRESULT Initialize(IN HWND hWndParent, IN OUT ITrayWindow *tray)
+    {
+        m_Tray = tray;
+        m_IsGroupingEnabled = g_TaskbarSettings.bGroupButtons;
+        Create(hWndParent, 0, szRunningApps, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP);
+        if (!m_hWnd)
+            return E_FAIL;
+        return S_OK;
+    }
+
+    HRESULT WINAPI GetWindow(HWND* phwnd)
+    {
+        if (!phwnd)
+            return E_INVALIDARG;
+        *phwnd = m_hWnd;
+        return S_OK;
+    }
+
+    HRESULT WINAPI ContextSensitiveHelp(BOOL fEnterMode)
+    {
+        return E_NOTIMPL;
+    }
+
     DECLARE_WND_CLASS_EX(szTaskSwitchWndClass, CS_DBLCLKS, COLOR_3DFACE)
 
     BEGIN_MSG_MAP(CTaskSwitchWnd)
@@ -1856,31 +1960,27 @@ public:
         MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
         MESSAGE_HANDLER(WM_COMMAND, OnCommand)
         MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
-        MESSAGE_HANDLER(TSWM_ENABLEGROUPING, OnEnableGrouping)
         MESSAGE_HANDLER(TSWM_UPDATETASKBARPOS, OnUpdateTaskbarPos)
+        MESSAGE_HANDLER(TWM_SETTINGSCHANGED, OnTaskbarSettingsChanged)
         MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
         MESSAGE_HANDLER(WM_TIMER, OnTimer)
-        MESSAGE_HANDLER(ShellHookMsg, HandleShellHookMsg)
-    ALT_MSG_MAP(1)
-        MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTestToolbar)
+        MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
+        MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChanged)
+        MESSAGE_HANDLER(m_ShellHookMsg, OnShellHook)
+        MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
+        MESSAGE_HANDLER(WM_KLUDGEMINRECT, OnKludgeItemRect)
+        MESSAGE_HANDLER(WM_COPYDATA, OnCopyData)
     END_MSG_MAP()
 
-    HWND _Init(IN HWND hWndParent, IN OUT ITrayWindow *tray)
-    {
-        Tray = tray;
-        hWndNotify = GetParent();
-        IsGroupingEnabled = TRUE; /* FIXME */
-        return Create(hWndParent, 0, szRunningApps, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP);
-    }
+    DECLARE_NOT_AGGREGATABLE(CTaskSwitchWnd)
+
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+    BEGIN_COM_MAP(CTaskSwitchWnd)
+        COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
+    END_COM_MAP()
 };
 
-HWND
-CreateTaskSwitchWnd(IN HWND hWndParent, IN OUT ITrayWindow *Tray)
+HRESULT CTaskSwitchWnd_CreateInstance(IN HWND hWndParent, IN OUT ITrayWindow *Tray, REFIID riid, void **ppv)
 {
-    CTaskSwitchWnd * instance;
-
-    // TODO: Destroy after the window is destroyed
-    instance = new CTaskSwitchWnd();
-
-    return instance->_Init(hWndParent, Tray);
+    return ShellObjectCreatorInit<CTaskSwitchWnd>(hWndParent, Tray, riid, ppv);
 }