[EXPLORER-NEW]
authorDavid Quintana <gigaherz@gmail.com>
Sun, 2 Nov 2014 20:18:54 +0000 (20:18 +0000)
committerDavid Quintana <gigaherz@gmail.com>
Sun, 2 Nov 2014 20:18:54 +0000 (20:18 +0000)
* Convert codebase to C++ and make use of C++ classes for the COM objects.

svn path=/branches/shell-experiments/; revision=65197

26 files changed:
base/shell/explorer-new/CMakeLists.txt
base/shell/explorer-new/desktop.cpp [moved from base/shell/explorer-new/desktop.c with 88% similarity]
base/shell/explorer-new/dragdrop.c [deleted file]
base/shell/explorer-new/dragdrop.cpp [new file with mode: 0644]
base/shell/explorer-new/explorer.c [deleted file]
base/shell/explorer-new/explorer.cpp [new file with mode: 0644]
base/shell/explorer-new/precomp.h
base/shell/explorer-new/rshell.cpp [moved from base/shell/explorer-new/rshell.c with 93% similarity]
base/shell/explorer-new/settings.cpp [moved from base/shell/explorer-new/settings.c with 96% similarity]
base/shell/explorer-new/shellservice.cpp [moved from base/shell/explorer-new/shellservice.c with 82% similarity]
base/shell/explorer-new/startmnu.c [deleted file]
base/shell/explorer-new/startmnu.cpp [new file with mode: 0644]
base/shell/explorer-new/startup.cpp [moved from base/shell/explorer-new/startup.c with 99% similarity]
base/shell/explorer-new/taskband.c [deleted file]
base/shell/explorer-new/taskband.cpp [new file with mode: 0644]
base/shell/explorer-new/taskswnd.c [deleted file]
base/shell/explorer-new/taskswnd.cpp [new file with mode: 0644]
base/shell/explorer-new/tbsite.c [deleted file]
base/shell/explorer-new/tbsite.cpp [new file with mode: 0644]
base/shell/explorer-new/trayntfy.c [deleted file]
base/shell/explorer-new/trayntfy.cpp [new file with mode: 0644]
base/shell/explorer-new/trayprop.cpp [moved from base/shell/explorer-new/trayprop.c with 99% similarity]
base/shell/explorer-new/traywnd.c [deleted file]
base/shell/explorer-new/traywnd.cpp [new file with mode: 0644]
base/shell/explorer-new/util.cpp [new file with mode: 0644]
dll/win32/browseui/bandsite.cpp

index 2672ce3..821d88f 100644 (file)
@@ -1,28 +1,34 @@
-
 PROJECT(SHELL)
 
-add_definitions(-DWIN32)
+set_cpp(WITH_RUNTIME)
+
+include_directories(${REACTOS_SOURCE_DIR}/lib/atl)
 
 list(APPEND SOURCE
-    desktop.c
-    dragdrop.c
-    explorer.c
-    rshell.c
-    settings.c
-    shellservice.c
-    startmnu.c
-    startup.c
-    taskband.c
-    taskswnd.c
-    tbsite.c
-    trayntfy.c
-    trayprop.c
-    traywnd.c
+    desktop.cpp
+    dragdrop.cpp
+    explorer.cpp
+    rshell.cpp
+    settings.cpp
+    shellservice.cpp
+    startmnu.cpp
+    startup.cpp
+    taskband.cpp
+    taskswnd.cpp
+    tbsite.cpp
+    trayntfy.cpp
+    trayprop.cpp
+    traywnd.cpp
+       util.cpp
     precomp.h)
 
 add_executable(explorer ${SOURCE} explorer.rc)
-target_link_libraries(explorer uuid wine)
+
+target_link_libraries(explorer uuid atlnew wine)
+
 set_module_type(explorer win32gui UNICODE)
 add_importlibs(explorer advapi32 gdi32 user32 comctl32 ole32 oleaut32 shell32 browseui shlwapi shdocvw version uxtheme msvcrt kernel32 ntdll)
+
 add_pch(explorer precomp.h SOURCE)
+
 add_cd_file(TARGET explorer DESTINATION reactos FOR all)
similarity index 88%
rename from base/shell/explorer-new/desktop.c
rename to base/shell/explorer-new/desktop.cpp
index 2ccebb3..99c71d4 100644 (file)
@@ -27,30 +27,29 @@ typedef struct _DESKCREATEINFO
     HANDLE hDesktop;
 } DESKCREATEINFO, *PDESKCREATEINFO;
 
+HANDLE WINAPI _SHCreateDesktop(IShellDesktopTray *ShellDesk);
+BOOL WINAPI _SHDesktopMessageLoop(HANDLE hDesktop);
+
 static DWORD CALLBACK
 DesktopThreadProc(IN OUT LPVOID lpParameter)
 {
     volatile DESKCREATEINFO *DeskCreateInfo = (volatile DESKCREATEINFO *)lpParameter;
-    IShellDesktopTray *pSdt;
+    CComPtr<IShellDesktopTray> pSdt;
     HANDLE hDesktop;
     HRESULT hRet;
 
     OleInitialize(NULL);
 
-    hRet = ITrayWindow_QueryInterface(DeskCreateInfo->Tray,
-                                      &IID_IShellDesktopTray,
-                                      (PVOID*)&pSdt);
+    hRet = DeskCreateInfo->Tray->QueryInterface(IID_PPV_ARG(IShellDesktopTray, &pSdt));
     if (!SUCCEEDED(hRet))
         return 1;
 
-    hDesktop = SHCreateDesktop(pSdt);
+    hDesktop = _SHCreateDesktop(pSdt);
 
-    IShellDesktopTray_Release(pSdt);
     if (hDesktop == NULL)
         return 1;
 
-    (void)InterlockedExchangePointer(&DeskCreateInfo->hDesktop,
-                                     hDesktop);
+    (void)InterlockedExchangePointer(&DeskCreateInfo->hDesktop, hDesktop);
 
     if (!SetEvent(DeskCreateInfo->hEvent))
     {
@@ -59,7 +58,7 @@ DesktopThreadProc(IN OUT LPVOID lpParameter)
         return 1;
     }
 
-    SHDesktopMessageLoop(hDesktop);
+    _SHDesktopMessageLoop(hDesktop);
 
     /* FIXME: Properly rundown the main thread! */
     ExitProcess(0);
diff --git a/base/shell/explorer-new/dragdrop.c b/base/shell/explorer-new/dragdrop.c
deleted file mode 100644 (file)
index ae1cb64..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * ReactOS Explorer
- *
- * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "precomp.h"
-
-static const IDropTargetVtbl IDropTargetImpl_Vtbl;
-
-/*
- * IDropTarget
- */
-
-typedef struct
-{
-    const IDropTargetVtbl *lpVtbl;
-    LONG Ref;
-    HWND hwndTarget;
-    IDropTargetHelper *DropTargetHelper;
-    PVOID Context;
-    BOOL CanDrop;
-    DROPTARGET_CALLBACKS Callbacks;
-    DWORD FormatsCount;
-    FORMATETC Formats[0];
-} IDropTargetImpl;
-
-static IUnknown *
-IUnknown_from_impl(IDropTargetImpl *This)
-{
-    return (IUnknown *)&This->lpVtbl;
-}
-
-static IDropTarget *
-IDropTarget_from_impl(IDropTargetImpl *This)
-{
-    return (IDropTarget *)&This->lpVtbl;
-}
-
-static IDropTargetImpl *
-impl_from_IDropTarget(IDropTarget *iface)
-{
-    return (IDropTargetImpl *)((ULONG_PTR)iface - FIELD_OFFSET(IDropTargetImpl,
-                                                               lpVtbl));
-}
-
-static VOID
-IDropTargetImpl_Free(IDropTargetImpl *This)
-{
-    IDropTargetHelper_Release(This->DropTargetHelper);
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-static ULONG STDMETHODCALLTYPE
-IDropTargetImpl_Release(IN OUT IDropTarget *iface)
-{
-    IDropTargetImpl *This = impl_from_IDropTarget(iface);
-    ULONG Ret;
-
-    Ret = InterlockedDecrement(&This->Ref);
-    if (Ret == 0)
-        IDropTargetImpl_Free(This);
-
-    return Ret;
-}
-
-static ULONG STDMETHODCALLTYPE
-IDropTargetImpl_AddRef(IN OUT IDropTarget *iface)
-{
-    IDropTargetImpl *This = impl_from_IDropTarget(iface);
-
-    return InterlockedIncrement(&This->Ref);
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDropTargetImpl_QueryInterface(IN OUT IDropTarget *iface,
-                               IN REFIID riid,
-                               OUT LPVOID *ppvObj)
-{
-    IDropTargetImpl *This;
-
-    if (ppvObj == NULL)
-        return E_POINTER;
-
-    This = impl_from_IDropTarget(iface);
-
-    if (IsEqualIID(riid,
-                   &IID_IUnknown))
-    {
-        *ppvObj = IUnknown_from_impl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IDropTarget))
-    {
-        *ppvObj = IDropTarget_from_impl(This);
-    }
-    else
-    {
-        *ppvObj = NULL;
-        return E_NOINTERFACE;
-    }
-
-    IDropTargetImpl_AddRef(iface);
-    return S_OK;
-}
-
-IDropTarget *
-CreateDropTarget(IN HWND hwndTarget,
-                 IN DWORD nSupportedFormats,
-                 IN const FORMATETC *Formats  OPTIONAL,
-                 IN PVOID Context  OPTIONAL,
-                 IN const DROPTARGET_CALLBACKS *Callbacks  OPTIONAL)
-{
-    IDropTargetImpl *This;
-    HRESULT hr;
-
-    This = HeapAlloc(hProcessHeap,
-                     HEAP_ZERO_MEMORY,
-                     FIELD_OFFSET(IDropTargetImpl,
-                                  Formats[nSupportedFormats]));
-    if (This != NULL)
-    {
-        This->lpVtbl = &IDropTargetImpl_Vtbl;
-        This->Ref = 1;
-        This->hwndTarget = hwndTarget;
-        This->FormatsCount = nSupportedFormats;
-        if (nSupportedFormats != 0)
-        {
-            CopyMemory(This->Formats,
-                       Formats,
-                       sizeof(Formats[0]) * nSupportedFormats);
-        }
-
-        This->Context = Context;
-        if (Callbacks != NULL)
-        {
-            CopyMemory(&This->Callbacks,
-                       Callbacks,
-                       sizeof(*Callbacks));
-        }
-
-        hr = CoCreateInstance(&CLSID_DragDropHelper,
-                              NULL,
-                              CLSCTX_INPROC_SERVER,
-                              &IID_IDropTargetHelper,
-                              (PVOID *)&This->DropTargetHelper);
-
-        if (!SUCCEEDED(hr))
-        {
-            HeapFree(hProcessHeap,
-                     0,
-                     This);
-            return NULL;
-        }
-
-        return IDropTarget_from_impl(This);
-    }
-
-    return NULL;
-}
-
-static const FORMATETC *
-IDropTargetImpl_FindSupportedFormat(IN OUT IDropTargetImpl *This,
-                                    IN IDataObject *pDataObject)
-{
-    FORMATETC *Current, *Last;
-    HRESULT hr;
-
-    /* NOTE: we could use IDataObject::EnumFormatEtc(),
-             but this appears to be a lot easier! */
-    Last = This->Formats + This->FormatsCount;
-    for (Current = This->Formats;
-         Current != Last;
-         Current++)
-    {
-        hr = IDataObject_QueryGetData(pDataObject,
-                                      Current);
-        if (SUCCEEDED(hr))
-            return Current;
-    }
-
-    return NULL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDropTargetImpl_DragEnter(IN OUT IDropTarget *iface,
-                          IN IDataObject *pDataObject,
-                          IN DWORD grfKeyState,
-                          IN POINTL pt,
-                          IN OUT DWORD *pdwEffect)
-{
-    IDropTargetImpl *This = impl_from_IDropTarget(iface);
-    const FORMATETC *Format;
-    HRESULT hr;
-
-    if (pDataObject == NULL)
-        return E_INVALIDARG;
-
-    This->CanDrop = FALSE;
-
-    hr = IDropTargetHelper_DragEnter(This->DropTargetHelper,
-                                     This->hwndTarget,
-                                     pDataObject,
-                                     (POINT *)&pt,
-                                     *pdwEffect);
-
-    if (SUCCEEDED(hr))
-    {
-        Format = IDropTargetImpl_FindSupportedFormat(This,
-                                                     pDataObject);
-        if (Format != NULL)
-        {
-            /* We found a format that we support! */
-            if (This->Callbacks.OnDragEnter != NULL)
-            {
-                hr = This->Callbacks.OnDragEnter(iface,
-                                                 This->Context,
-                                                 Format,
-                                                 grfKeyState,
-                                                 pt,
-                                                 pdwEffect);
-                if (SUCCEEDED(hr))
-                {
-                    if (hr == S_OK)
-                        This->CanDrop = TRUE;
-                    else
-                    {
-                        /* Special return value by the callback routine,
-                           doesn't want to allow dragging */
-                        *pdwEffect = DROPEFFECT_NONE;
-                    }
-
-                    hr = S_OK;
-                }
-                else
-                {
-                    *pdwEffect = DROPEFFECT_NONE;
-                    hr = S_OK;
-                }
-            }
-            else
-                *pdwEffect = DROPEFFECT_NONE;
-        }
-        else
-            *pdwEffect = DROPEFFECT_NONE;
-    }
-
-    return hr;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDropTargetImpl_DragOver(IN OUT IDropTarget *iface,
-                         IN DWORD grfKeyState,
-                         IN POINTL pt,
-                         IN OUT DWORD *pdwEffect)
-{
-    IDropTargetImpl *This = impl_from_IDropTarget(iface);
-    HRESULT hr;
-
-    hr = IDropTargetHelper_DragOver(This->DropTargetHelper,
-                                    (POINT *)&pt,
-                                    *pdwEffect);
-
-    if (SUCCEEDED(hr))
-    {
-        if (This->CanDrop)
-        {
-            if (This->Callbacks.OnDragOver != NULL)
-            {
-                hr = This->Callbacks.OnDragOver(iface,
-                                                This->Context,
-                                                grfKeyState,
-                                                pt,
-                                                pdwEffect);
-                if (SUCCEEDED(hr))
-                {
-                    if (hr != S_OK)
-                    {
-                        /* Special return value by the callback routine,
-                           doesn't want to allow dropping here */
-                        *pdwEffect = DROPEFFECT_NONE;
-                    }
-
-                    hr = S_OK;
-                }
-                else
-                {
-                    *pdwEffect = DROPEFFECT_NONE;
-                    hr = S_OK;
-                }
-            }
-            else
-                *pdwEffect = DROPEFFECT_NONE;
-        }
-        else
-            *pdwEffect = DROPEFFECT_NONE;
-    }
-
-    return hr;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDropTargetImpl_DragLeave(IN OUT IDropTarget *iface)
-{
-    IDropTargetImpl *This = impl_from_IDropTarget(iface);
-    HRESULT hr;
-
-    hr = IDropTargetHelper_DragLeave(This->DropTargetHelper);
-    if (SUCCEEDED(hr))
-    {
-        if (This->Callbacks.OnDragLeave != NULL)
-        {
-            hr = This->Callbacks.OnDragLeave(iface,
-                                             This->Context);
-        }
-    }
-
-    return hr;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDropTargetImpl_Drop(IN OUT IDropTarget *iface,
-                     IN IDataObject *pDataObject,
-                     IN DWORD grfKeyState,
-                     IN POINTL pt,
-                     IN OUT DWORD *pdwEffect)
-{
-    IDropTargetImpl *This = impl_from_IDropTarget(iface);
-    const FORMATETC *Format;
-    HRESULT hr;
-
-    if (pDataObject == NULL)
-        return E_INVALIDARG;
-
-    hr = IDropTargetHelper_Drop(This->DropTargetHelper,
-                                pDataObject,
-                                (POINT *)&pt,
-                                *pdwEffect);
-
-    if (SUCCEEDED(hr) && This->CanDrop)
-    {
-        Format = IDropTargetImpl_FindSupportedFormat(This,
-                                                     pDataObject);
-        if (Format != NULL)
-        {
-            /* We found a format that we support! */
-            if (This->Callbacks.OnDrop != NULL)
-            {
-                hr = This->Callbacks.OnDrop(iface,
-                                            This->Context,
-                                            Format,
-                                            grfKeyState,
-                                            pt,
-                                            pdwEffect);
-                if (SUCCEEDED(hr))
-                {
-                    if (hr == S_OK)
-                        This->CanDrop = TRUE;
-                    else
-                    {
-                        /* Special return value by the callback routine,
-                           doesn't want to allow dragging */
-                        *pdwEffect = DROPEFFECT_NONE;
-                    }
-
-                    hr = S_OK;
-                }
-                else
-                {
-                    *pdwEffect = DROPEFFECT_NONE;
-                    hr = S_OK;
-                }
-            }
-            else
-                *pdwEffect = DROPEFFECT_NONE;
-        }
-        else
-            *pdwEffect = DROPEFFECT_NONE;
-    }
-
-    return hr;
-}
-
-static const IDropTargetVtbl IDropTargetImpl_Vtbl =
-{
-    /* IUnknown */
-    IDropTargetImpl_QueryInterface,
-    IDropTargetImpl_AddRef,
-    IDropTargetImpl_Release,
-    /* IDropTarget */
-    IDropTargetImpl_DragEnter,
-    IDropTargetImpl_DragOver,
-    IDropTargetImpl_DragLeave,
-    IDropTargetImpl_Drop
-};
diff --git a/base/shell/explorer-new/dragdrop.cpp b/base/shell/explorer-new/dragdrop.cpp
new file mode 100644 (file)
index 0000000..d9c21e6
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * ReactOS Explorer
+ *
+ * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "precomp.h"
+
+class CDropTarget :
+    public CComCoClass<CDropTarget>,
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IDropTarget
+{
+    HWND hwndTarget;
+    CComPtr<IDropTargetHelper> DropTargetHelper;
+    PVOID Context;
+    BOOL CanDrop;
+    DROPTARGET_CALLBACKS Callbacks;
+    DWORD FormatsCount;
+    FORMATETC* Formats;
+    
+    const FORMATETC *
+        FindSupportedFormat(IN IDataObject *pDataObject)
+    {
+        FORMATETC *Current, *Last;
+        HRESULT hr;
+
+        /* NOTE: we could use IDataObject::EnumFormatEtc(),
+                 but this appears to be a lot easier! */
+        Last = Formats + FormatsCount;
+        for (Current = Formats;
+            Current != Last;
+            Current++)
+        {
+            hr = pDataObject->QueryGetData(Current);
+            if (SUCCEEDED(hr))
+                return Current;
+        }
+
+        return NULL;
+    }
+
+public:
+    CDropTarget() :
+        hwndTarget(NULL),
+        Context(NULL),
+        CanDrop(FALSE),
+        FormatsCount(0),
+        Formats(NULL)
+    {
+        ZeroMemory(&Callbacks, sizeof(Callbacks));
+    }
+
+    virtual ~CDropTarget() { }
+
+    HRESULT Initialize(IN HWND hwndTarget,
+        IN DWORD nSupportedFormats,
+        IN const FORMATETC *formats OPTIONAL,
+        IN PVOID Context  OPTIONAL,
+        IN const DROPTARGET_CALLBACKS *Callbacks OPTIONAL)
+    {
+        this->hwndTarget = hwndTarget;
+        FormatsCount = nSupportedFormats;
+        if (nSupportedFormats != 0)
+        {
+            Formats = new FORMATETC[nSupportedFormats];
+            CopyMemory(Formats,
+                formats,
+                sizeof(formats[0]) * nSupportedFormats);
+        }
+
+        this->Context = Context;
+        if (Callbacks != NULL)
+        {
+            CopyMemory(&this->Callbacks,
+                Callbacks,
+                sizeof(*Callbacks));
+        }
+
+        HRESULT hr = CoCreateInstance(CLSID_DragDropHelper,
+            NULL,
+            CLSCTX_INPROC_SERVER,
+            IID_PPV_ARG(IDropTargetHelper, &DropTargetHelper));
+
+        return hr;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE DragEnter(
+        IN IDataObject *pDataObject,
+        IN DWORD grfKeyState,
+        IN POINTL pt,
+        IN OUT DWORD *pdwEffect)
+    {
+        const FORMATETC *Format;
+        HRESULT hr;
+
+        if (pDataObject == NULL)
+            return E_INVALIDARG;
+
+        CanDrop = FALSE;
+
+        hr = DropTargetHelper->DragEnter(
+            hwndTarget,
+            pDataObject,
+            (POINT *) &pt,
+            *pdwEffect);
+
+        if (SUCCEEDED(hr))
+        {
+            Format = FindSupportedFormat(
+                pDataObject);
+            if (Format != NULL)
+            {
+                /* We found a format that we support! */
+                if (Callbacks.OnDragEnter != NULL)
+                {
+                    hr = Callbacks.OnDragEnter(this,
+                        Context,
+                        Format,
+                        grfKeyState,
+                        pt,
+                        pdwEffect);
+                    if (SUCCEEDED(hr))
+                    {
+                        if (hr == S_OK)
+                            CanDrop = TRUE;
+                        else
+                        {
+                            /* Special return value by the callback routine,
+                               doesn't want to allow dragging */
+                            *pdwEffect = DROPEFFECT_NONE;
+                        }
+
+                        hr = S_OK;
+                    }
+                    else
+                    {
+                        *pdwEffect = DROPEFFECT_NONE;
+                        hr = S_OK;
+                    }
+                }
+                else
+                    *pdwEffect = DROPEFFECT_NONE;
+            }
+            else
+                *pdwEffect = DROPEFFECT_NONE;
+        }
+
+        return hr;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE DragOver(
+        IN DWORD grfKeyState,
+        IN POINTL pt,
+        IN OUT DWORD *pdwEffect)
+    {
+        HRESULT hr;
+
+        hr = DropTargetHelper->DragOver(
+            (POINT *) &pt,
+            *pdwEffect);
+
+        if (SUCCEEDED(hr))
+        {
+            if (CanDrop)
+            {
+                if (Callbacks.OnDragOver != NULL)
+                {
+                    hr = Callbacks.OnDragOver(this,
+                        Context,
+                        grfKeyState,
+                        pt,
+                        pdwEffect);
+                    if (SUCCEEDED(hr))
+                    {
+                        if (hr != S_OK)
+                        {
+                            /* Special return value by the callback routine,
+                               doesn't want to allow dropping here */
+                            *pdwEffect = DROPEFFECT_NONE;
+                        }
+
+                        hr = S_OK;
+                    }
+                    else
+                    {
+                        *pdwEffect = DROPEFFECT_NONE;
+                        hr = S_OK;
+                    }
+                }
+                else
+                    *pdwEffect = DROPEFFECT_NONE;
+            }
+            else
+                *pdwEffect = DROPEFFECT_NONE;
+        }
+
+        return hr;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE DragLeave()
+    {
+        HRESULT hr;
+
+        hr = DropTargetHelper->DragLeave();
+        if (SUCCEEDED(hr))
+        {
+            if (Callbacks.OnDragLeave != NULL)
+            {
+                hr = Callbacks.OnDragLeave(this,
+                    Context);
+            }
+        }
+
+        return hr;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE        Drop(
+        IN IDataObject *pDataObject,
+        IN DWORD grfKeyState,
+        IN POINTL pt,
+        IN OUT DWORD *pdwEffect)
+    {
+        const FORMATETC *Format;
+        HRESULT hr;
+
+        if (pDataObject == NULL)
+            return E_INVALIDARG;
+
+        hr = DropTargetHelper->Drop(
+            pDataObject,
+            (POINT *) &pt,
+            *pdwEffect);
+
+        if (SUCCEEDED(hr) && CanDrop)
+        {
+            Format = FindSupportedFormat(pDataObject);
+            if (Format != NULL)
+            {
+                /* We found a format that we support! */
+                if (Callbacks.OnDrop != NULL)
+                {
+                    hr = Callbacks.OnDrop(this,
+                        Context,
+                        Format,
+                        grfKeyState,
+                        pt,
+                        pdwEffect);
+                    if (SUCCEEDED(hr))
+                    {
+                        if (hr == S_OK)
+                            CanDrop = TRUE;
+                        else
+                        {
+                            /* Special return value by the callback routine,
+                               doesn't want to allow dragging */
+                            *pdwEffect = DROPEFFECT_NONE;
+                        }
+
+                        hr = S_OK;
+                    }
+                    else
+                    {
+                        *pdwEffect = DROPEFFECT_NONE;
+                        hr = S_OK;
+                    }
+                }
+                else
+                    *pdwEffect = DROPEFFECT_NONE;
+            }
+            else
+                *pdwEffect = DROPEFFECT_NONE;
+        }
+
+        return hr;
+    }
+
+    DECLARE_NOT_AGGREGATABLE(CDropTarget)
+
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+    BEGIN_COM_MAP(CDropTarget)
+        COM_INTERFACE_ENTRY_IID(IID_IDropTarget, IDropTarget)
+    END_COM_MAP()
+};
+
+IDropTarget *
+CreateDropTarget(IN HWND hwndTarget,
+                 IN DWORD nSupportedFormats,
+                 IN const FORMATETC *Formats  OPTIONAL,
+                 IN PVOID Context  OPTIONAL,
+                 IN const DROPTARGET_CALLBACKS *Callbacks  OPTIONAL)
+{
+    IDropTarget *dt;
+
+    HRESULT hr = ShellObjectCreatorInit<CDropTarget>(hwndTarget, nSupportedFormats, Formats, Context, Callbacks, IID_IDropTarget, &dt);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return NULL;
+
+    return dt;
+}
diff --git a/base/shell/explorer-new/explorer.c b/base/shell/explorer-new/explorer.c
deleted file mode 100644 (file)
index fe30d62..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * ReactOS Explorer
- *
- * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "precomp.h"
-#include <shlwapi_undoc.h>
-#include <winver.h>
-
-HINSTANCE hExplorerInstance;
-HMODULE hUser32;
-HANDLE hProcessHeap;
-HKEY hkExplorer = NULL;
-DRAWCAPTEMP DrawCapTemp = NULL;
-
-typedef struct _LANGCODEPAGE
-{
-    WORD wLanguage;
-    WORD wCodePage;
-} LANGCODEPAGE, *PLANGCODEPAGE;
-
-LONG
-SetWindowStyle(IN HWND hWnd,
-               IN LONG dwStyleMask,
-               IN LONG dwStyle)
-{
-    LONG PrevStyle, Style;
-
-    ASSERT((~dwStyleMask & dwStyle) == 0);
-
-    PrevStyle = GetWindowLong(hWnd,
-                              GWL_STYLE);
-    if (PrevStyle != 0 &&
-        (PrevStyle & dwStyleMask) != dwStyle)
-    {
-        Style = PrevStyle & ~dwStyleMask;
-        Style |= dwStyle;
-
-        PrevStyle = SetWindowLong(hWnd,
-                                  GWL_STYLE,
-                                  Style);
-    }
-
-    return PrevStyle;
-}
-
-LONG
-SetWindowExStyle(IN HWND hWnd,
-                 IN LONG dwStyleMask,
-                 IN LONG dwStyle)
-{
-    LONG PrevStyle, Style;
-
-    ASSERT((~dwStyleMask & dwStyle) == 0);
-
-    PrevStyle = GetWindowLong(hWnd,
-                              GWL_EXSTYLE);
-    if (PrevStyle != 0 &&
-        (PrevStyle & dwStyleMask) != dwStyle)
-    {
-        Style = PrevStyle & ~dwStyleMask;
-        Style |= dwStyle;
-
-        PrevStyle = SetWindowLong(hWnd,
-                                  GWL_EXSTYLE,
-                                  Style);
-    }
-
-    return PrevStyle;
-}
-
-HMENU
-LoadPopupMenu(IN HINSTANCE hInstance,
-              IN LPCTSTR lpMenuName)
-{
-    HMENU hMenu, hSubMenu = NULL;
-
-    hMenu = LoadMenu(hInstance,
-                     lpMenuName);
-
-    if (hMenu != NULL)
-    {
-        hSubMenu = GetSubMenu(hMenu,
-                              0);
-        if (hSubMenu != NULL &&
-            !RemoveMenu(hMenu,
-                        0,
-                        MF_BYPOSITION))
-        {
-            hSubMenu = NULL;
-        }
-
-        DestroyMenu(hMenu);
-    }
-
-    return hSubMenu;
-}
-
-HMENU
-FindSubMenu(IN HMENU hMenu,
-            IN UINT uItem,
-            IN BOOL fByPosition)
-{
-    MENUITEMINFO mii;
-
-    mii.cbSize = sizeof(mii);
-    mii.fMask = MIIM_SUBMENU;
-
-    if (GetMenuItemInfo(hMenu,
-                        uItem,
-                        fByPosition,
-                        &mii))
-    {
-        return mii.hSubMenu;
-    }
-
-    return NULL;
-}
-
-BOOL
-GetCurrentLoggedOnUserName(OUT LPTSTR szBuffer,
-                           IN DWORD dwBufferSize)
-{
-    DWORD dwType;
-    DWORD dwSize;
-
-    /* Query the user name from the registry */
-    dwSize = (dwBufferSize * sizeof(TCHAR)) - 1;
-    if (RegQueryValueEx(hkExplorer,
-                        TEXT("Logon User Name"),
-                        0,
-                        &dwType,
-                        (LPBYTE)szBuffer,
-                        &dwSize) == ERROR_SUCCESS &&
-        (dwSize / sizeof(TCHAR)) > 1 &&
-        szBuffer[0] != _T('\0'))
-    {
-        szBuffer[dwSize / sizeof(TCHAR)] = _T('\0');
-        return TRUE;
-    }
-
-    /* Fall back to GetUserName() */
-    dwSize = dwBufferSize;
-    if (!GetUserName(szBuffer,
-                     &dwSize))
-    {
-        szBuffer[0] = _T('\0');
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-BOOL
-FormatMenuString(IN HMENU hMenu,
-                 IN UINT uPosition,
-                 IN UINT uFlags,
-                 ...)
-{
-    va_list vl;
-    MENUITEMINFO mii;
-    TCHAR szBuf[128];
-    TCHAR szBufFmt[128];
-
-    /* Find the menu item and read the formatting string */
-    mii.cbSize = sizeof(mii);
-    mii.fMask = MIIM_STRING;
-    mii.dwTypeData = (LPTSTR)szBufFmt;
-    mii.cch = sizeof(szBufFmt) / sizeof(szBufFmt[0]);
-    if (GetMenuItemInfo(hMenu,
-                        uPosition,
-                        uFlags,
-                        &mii))
-    {
-        /* Format the string */
-        va_start(vl, uFlags);
-        _vsntprintf(szBuf,
-                    (sizeof(szBuf) / sizeof(szBuf[0])) - 1,
-                    szBufFmt,
-                    vl);
-        va_end(vl);
-        szBuf[(sizeof(szBuf) / sizeof(szBuf[0])) - 1] = _T('\0');
-
-        /* Update the menu item */
-        mii.dwTypeData = (LPTSTR)szBuf;
-        if (SetMenuItemInfo(hMenu,
-                            uPosition,
-                            uFlags,
-                            &mii))
-        {
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
-BOOL
-GetExplorerRegValueSet(IN HKEY hKey,
-                       IN LPCTSTR lpSubKey,
-                       IN LPCTSTR lpValue)
-{
-    TCHAR szBuffer[MAX_PATH];
-    HKEY hkSubKey;
-    DWORD dwType, dwSize;
-    BOOL Ret = FALSE;
-
-    StringCbCopy(szBuffer, sizeof(szBuffer),
-            TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"));
-    if (FAILED(StringCbCat(szBuffer, sizeof(szBuffer),
-            _T("\\"))))
-        return FALSE;
-    if (FAILED(StringCbCat(szBuffer, sizeof(szBuffer),
-            lpSubKey)))
-    return FALSE;
-
-    dwSize = sizeof(szBuffer);
-    if (RegOpenKeyEx(hKey,
-                     szBuffer,
-                     0,
-                     KEY_QUERY_VALUE,
-                     &hkSubKey) == ERROR_SUCCESS)
-    {
-        ZeroMemory(szBuffer,
-                   sizeof(szBuffer));
-
-        if (RegQueryValueEx(hkSubKey,
-                            lpValue,
-                            0,
-                            &dwType,
-                            (LPBYTE)szBuffer,
-                            &dwSize) == ERROR_SUCCESS)
-        {
-            if (dwType == REG_DWORD && dwSize == sizeof(DWORD))
-                Ret = *((PDWORD)szBuffer) != 0;
-            else if (dwSize > 0)
-                Ret = *((PUCHAR)szBuffer) != 0;
-        }
-
-        RegCloseKey(hkSubKey);
-    }
-    return Ret;
-}
-
-
-static BOOL
-SetShellReadyEvent(IN LPCTSTR lpEventName)
-{
-    HANDLE hEvent;
-
-    hEvent = OpenEvent(EVENT_MODIFY_STATE,
-                       FALSE,
-                       lpEventName);
-    if (hEvent != NULL)
-    {
-        SetEvent(hEvent);
-
-        CloseHandle(hEvent);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-BOOL
-GetVersionInfoString(IN TCHAR *szFileName,
-                     IN TCHAR *szVersionInfo,
-                     OUT TCHAR *szBuffer,
-                     IN UINT cbBufLen)
-{
-    LPVOID lpData = NULL;
-    TCHAR szSubBlock[128];
-    TCHAR *lpszLocalBuf = NULL;
-    LANGID UserLangId;
-    PLANGCODEPAGE lpTranslate = NULL;
-    DWORD dwLen;
-    DWORD dwHandle;
-    UINT cbTranslate;
-    UINT cbLen;
-    BOOL bRet = FALSE;
-    unsigned int i;
-
-    dwLen = GetFileVersionInfoSize(szFileName, &dwHandle);
-
-    if (dwLen > 0)
-    {
-        lpData = HeapAlloc(hProcessHeap, 0, dwLen);
-
-        if (lpData != NULL)
-        {
-            if (GetFileVersionInfo(szFileName,
-                                  0,
-                                  dwLen,
-                                  lpData) != 0)
-            {
-                UserLangId = GetUserDefaultLangID();
-
-                VerQueryValue(lpData,
-                    TEXT("\\VarFileInfo\\Translation"),
-                    (LPVOID *)&lpTranslate,
-                    &cbTranslate);
-
-                for (i = 0; i < cbTranslate / sizeof(LANGCODEPAGE); i++)
-                {
-                    /* If the bottom eight bits of the language id's
-                    match, use this version information (since this
-                    means that the version information and the users
-                    default language are the same). */
-                    if ((lpTranslate[i].wLanguage & 0xFF) ==
-                        (UserLangId & 0xFF))
-                    {
-                        wnsprintf(szSubBlock,
-                            sizeof(szSubBlock) / sizeof(szSubBlock[0]),
-                            TEXT("\\StringFileInfo\\%04X%04X\\%s"),
-                            lpTranslate[i].wLanguage,
-                            lpTranslate[i].wCodePage,
-                            szVersionInfo);
-
-                        if (VerQueryValue(lpData,
-                            szSubBlock,
-                            (LPVOID *)&lpszLocalBuf,
-                            &cbLen) != 0)
-                        {
-                            _tcsncpy(szBuffer, lpszLocalBuf, cbBufLen / sizeof(*szBuffer));
-
-                            bRet = TRUE;
-                            break;
-                        }
-                    }
-                }
-            }
-            HeapFree(hProcessHeap, 0, lpData);
-            lpData = NULL;
-        }
-    }
-
-    return bRet;
-}
-
-static VOID
-HideMinimizedWindows(IN BOOL bHide)
-{
-    MINIMIZEDMETRICS mm;
-
-    mm.cbSize = sizeof(mm);
-    if (!SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0))
-    {
-        ERR("SystemParametersInfo failed with %lu\n", GetLastError());
-        return;
-    }
-    if (bHide)
-        mm.iArrange |= ARW_HIDE;
-    else
-        mm.iArrange &= ~ARW_HIDE;
-    if (!SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0))
-        ERR("SystemParametersInfo failed with %lu\n", GetLastError());
-}
-
-INT WINAPI
-_tWinMain(IN HINSTANCE hInstance,
-          IN HINSTANCE hPrevInstance,
-          IN LPTSTR lpCmdLine,
-          IN INT nCmdShow)
-{
-    ITrayWindow *Tray = NULL;
-    HANDLE hShellDesktop = NULL;
-    BOOL CreateShellDesktop = FALSE;
-
-    DbgPrint("Explorer starting... Commandline: %S\n", lpCmdLine);
-
-    /*
-    * Set our shutdown parameters: we want to shutdown the very last,
-    * but before any TaskMgr instance (which has a shutdown level of 1).
-    */
-    SetProcessShutdownParameters(2, 0);
-
-    if (GetShellWindow() == NULL)
-        CreateShellDesktop = TRUE;
-
-    if (!CreateShellDesktop)
-    {
-        EXPLORER_CMDLINE_PARSE_RESULTS parseResults = { 0 };
-
-        if (SHExplorerParseCmdLine(&parseResults))
-            return SHCreateFromDesktop(&parseResults);
-
-        if (parseResults.strPath)
-            SHFree(parseResults.strPath);
-
-        if (parseResults.pidlPath)
-            ILFree(parseResults.pidlPath);
-
-        if (parseResults.pidlRoot)
-            ILFree(parseResults.pidlRoot);
-
-    }
-
-    if (RegOpenKey(HKEY_CURRENT_USER,
-                   TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"),
-                   &hkExplorer) != ERROR_SUCCESS)
-    {
-        TCHAR Message[256];
-        LoadString(hInstance, IDS_STARTUP_ERROR, Message, 256);
-        MessageBox(NULL, Message, NULL, MB_ICONERROR);
-        return 1;
-    }
-
-    hExplorerInstance = hInstance;
-    hProcessHeap = GetProcessHeap();
-    LoadAdvancedSettings();
-
-    hUser32 = GetModuleHandle(TEXT("USER32.DLL"));
-    if (hUser32 != NULL)
-    {
-        DrawCapTemp = (DRAWCAPTEMP)GetProcAddress(hUser32,
-                                                  PROC_NAME_DRAWCAPTIONTEMP);
-    }
-
-    InitCommonControls();
-    OleInitialize(NULL);
-
-    ProcessStartupItems();
-
-    /* Initialize shell dde support */
-    ShellDDEInit(TRUE);
-
-    /* Initialize shell icons */
-    FileIconInit(TRUE);
-
-    /* Initialize CLSID_ShellWindows class */
-    WinList_Init();
-
-    if (RegisterTrayWindowClass() && RegisterTaskSwitchWndClass())
-    {
-        Tray = CreateTrayWindow();
-        /* This not only hides the minimized window captions in the bottom
-        left screen corner, but is also needed in order to receive
-        HSHELL_* notification messages (which are required for taskbar
-        buttons to work right) */
-        HideMinimizedWindows(TRUE);
-
-        if (Tray != NULL)
-            hShellDesktop = DesktopCreateWindow(Tray);
-    }
-
-    /* WinXP: Notify msgina to hide the welcome screen */
-    if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent")))
-        SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent"));
-
-    if (Tray != NULL)
-    {
-        RegisterHotKey(NULL, IDHK_RUN, MOD_WIN, 'R');
-        TrayMessageLoop(Tray);
-        HideMinimizedWindows(FALSE);
-        ITrayWindow_Release(Tray);
-        UnregisterTrayWindowClass();
-    }
-
-    if (hShellDesktop != NULL)
-        DesktopDestroyShellWindow(hShellDesktop);
-
-    /* FIXME - shutdown SSO Thread */
-
-    OleUninitialize();
-
-    RegCloseKey(hkExplorer);
-    hkExplorer = NULL;
-
-    return 0;
-}
diff --git a/base/shell/explorer-new/explorer.cpp b/base/shell/explorer-new/explorer.cpp
new file mode 100644 (file)
index 0000000..bd40c3d
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * ReactOS Explorer
+ *
+ * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "precomp.h"
+#include <shlwapi_undoc.h>
+
+DWORD WINAPI _WinList_Init(void);
+void WINAPI _ShellDDEInit(BOOL bInit);
+
+HINSTANCE hExplorerInstance;
+HMODULE hUser32;
+HANDLE hProcessHeap;
+HKEY hkExplorer = NULL;
+DRAWCAPTEMP DrawCapTemp = NULL;
+
+class CExplorerModule : public CComModule
+{
+public:
+};
+
+BEGIN_OBJECT_MAP(ObjectMap)
+END_OBJECT_MAP()
+
+CExplorerModule                             gModule;
+CAtlWinModule                               gWinModule;
+
+void *operator new (size_t, void *buf)
+{
+    return buf;
+}
+
+static VOID InitializeAtlModule(HINSTANCE hInstance, BOOL bInitialize)
+{
+    if (bInitialize)
+    {
+        /* HACK - the global constructors don't run, so I placement new them here */
+        new (&gModule) CExplorerModule;
+        new (&gWinModule) CAtlWinModule;
+        new (&_AtlBaseModule) CAtlBaseModule;
+        new (&_AtlComModule) CAtlComModule;
+
+        gModule.Init(ObjectMap, hInstance, NULL);
+    }
+    else
+    {
+        gModule.Term();
+    }
+}
+
+#if !WIN7_COMPAT_MODE
+static BOOL
+SetShellReadyEvent(IN LPCTSTR lpEventName)
+{
+    HANDLE hEvent;
+
+    hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, lpEventName);
+    if (hEvent != NULL)
+    {
+        SetEvent(hEvent);
+
+        CloseHandle(hEvent);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static VOID
+HideMinimizedWindows(IN BOOL bHide)
+{
+    MINIMIZEDMETRICS mm;
+
+    mm.cbSize = sizeof(mm);
+    if (!SystemParametersInfo(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0))
+    {
+        ERR("SystemParametersInfo failed with %lu\n", GetLastError());
+        return;
+    }
+    if (bHide)
+        mm.iArrange |= ARW_HIDE;
+    else
+        mm.iArrange &= ~ARW_HIDE;
+    if (!SystemParametersInfo(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0))
+        ERR("SystemParametersInfo failed with %lu\n", GetLastError());
+}
+
+static INT 
+StartWithCommandLine(IN HINSTANCE hInstance)
+{
+    BOOL b = FALSE;
+    EXPLORER_CMDLINE_PARSE_RESULTS parseResults = { 0 };
+
+    if (SHExplorerParseCmdLine(&parseResults))
+        b = SHCreateFromDesktop(&parseResults);
+
+    if (parseResults.strPath)
+        SHFree(parseResults.strPath);
+
+    if (parseResults.pidlPath)
+        ILFree(parseResults.pidlPath);
+
+    if (parseResults.pidlRoot)
+        ILFree(parseResults.pidlRoot);
+
+    return b;
+}
+#endif
+
+static INT 
+StartWithDesktop(IN HINSTANCE hInstance)
+{
+    InitializeAtlModule(hInstance, TRUE);
+
+    if (RegOpenKey(HKEY_CURRENT_USER,
+        L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
+        &hkExplorer) != ERROR_SUCCESS)
+    {
+        WCHAR Message[256];
+        LoadString(hInstance, IDS_STARTUP_ERROR, Message, 256);
+        MessageBox(NULL, Message, NULL, MB_ICONERROR);
+        return 1;
+    }
+
+    hExplorerInstance = hInstance;
+    hProcessHeap = GetProcessHeap();
+    LoadAdvancedSettings();
+
+    hUser32 = GetModuleHandle(TEXT("USER32.DLL"));
+    if (hUser32 != NULL)
+    {
+        DrawCapTemp = (DRAWCAPTEMP) GetProcAddress(hUser32, PROC_NAME_DRAWCAPTIONTEMP);
+    }
+
+    InitCommonControls();
+    OleInitialize(NULL);
+
+#if !WIN7_COMPAT_MODE
+    ProcessStartupItems();
+
+    /* Initialize shell dde support */
+    _ShellDDEInit(TRUE);
+#endif
+
+    /* Initialize shell icons */
+    FileIconInit(TRUE);
+
+    /* Initialize CLSID_ShellWindows class */
+    _WinList_Init();
+
+    CComPtr<ITrayWindow> Tray;
+    CreateTrayWindow(&Tray);
+
+#if !WIN7_COMPAT_MODE
+    /* This not only hides the minimized window captions in the bottom
+    left screen corner, but is also needed in order to receive
+    HSHELL_* notification messages (which are required for taskbar
+    buttons to work right) */
+    HideMinimizedWindows(TRUE);
+
+    HANDLE hShellDesktop = NULL;
+    if (Tray != NULL)
+        hShellDesktop = DesktopCreateWindow(Tray);
+
+    /* WinXP: Notify msgina to hide the welcome screen */
+    if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent")))
+        SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent"));
+#endif
+
+    if (Tray != NULL)
+    {
+#if !WIN7_COMPAT_MODE
+        RegisterHotKey(NULL, IDHK_RUN, MOD_WIN, 'R');
+#endif
+        TrayMessageLoop(Tray);
+#if !WIN7_COMPAT_MODE
+        HideMinimizedWindows(FALSE);
+#endif
+    }
+
+#if !WIN7_COMPAT_MODE
+    if (hShellDesktop != NULL)
+        DesktopDestroyShellWindow(hShellDesktop);
+#endif
+
+    OleUninitialize();
+
+    RegCloseKey(hkExplorer);
+    hkExplorer = NULL;
+
+    InitializeAtlModule(hInstance, FALSE);
+
+    return 0;
+}
+
+INT WINAPI
+_tWinMain(IN HINSTANCE hInstance,
+          IN HINSTANCE hPrevInstance,
+          IN LPTSTR lpCmdLine,
+          IN INT nCmdShow)
+{
+#if !WIN7_COMPAT_MODE
+    BOOL CreateShellDesktop = FALSE;
+
+    DbgPrint("Explorer starting... Commandline: %S\n", lpCmdLine);
+
+    /*
+    * Set our shutdown parameters: we want to shutdown the very last,
+    * but before any TaskMgr instance (which has a shutdown level of 1).
+    */
+    SetProcessShutdownParameters(2, 0);
+
+    if (GetShellWindow() == NULL)
+        CreateShellDesktop = TRUE;
+
+    if (!CreateShellDesktop)
+    {
+        return StartWithCommandLine(hInstance);
+    }
+#endif
+
+    return StartWithDesktop(hInstance);
+}
index 56571d2..e9e6c26 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _EXPLORER_PRECOMP__H_
 #define _EXPLORER_PRECOMP__H_
 
+#define WIN7_COMPAT_MODE 0
+
 #include <stdio.h>
 #include <tchar.h>
 
@@ -16,6 +18,9 @@
 #include <wingdi.h>
 #include <winnls.h>
 #include <wincon.h>
+#include <atlbase.h>
+#include <atlcom.h>
+#include <atlwin.h>
 #include <shellapi.h>
 #include <shlobj.h>
 #include <shlobj_undoc.h>
@@ -24,6 +29,7 @@
 #include <uxtheme.h>
 #include <strsafe.h>
 #include <undocuser.h>
+#include <undocshell.h>
 
 #include "tmschema.h"
 #include "resource.h"
 WINE_DEFAULT_DEBUG_CHANNEL(explorernew);
 
 /* dynamic imports due to lack of support in msvc linker libs */
-typedef INT (APIENTRY *REGSHELLHOOK)(HWND, DWORD);
+typedef INT(APIENTRY *REGSHELLHOOK)(HWND, DWORD);
 #ifdef UNICODE
 #define PROC_NAME_DRAWCAPTIONTEMP "DrawCaptionTempW"
-typedef BOOL (APIENTRY *DRAWCAPTEMP)(HWND, HDC, const RECT*, HFONT, HICON, LPCWSTR, UINT);
+typedef BOOL(APIENTRY *DRAWCAPTEMP)(HWND, HDC, const RECT*, HFONT, HICON, LPCWSTR, UINT);
 #else
 #define PROC_NAME_DRAWCAPTIONTEMP "DrawCaptionTempA"
 typedef BOOL (APIENTRY *DRAWCAPTEMP)(HWND, HDC, const RECT*, HFONT, HICON, LPCSTR, UINT);
 #endif
-typedef HRESULT (APIENTRY *SHINVDEFCMD)(HWND, IShellFolder*, LPCITEMIDLIST);
+typedef HRESULT(APIENTRY *SHINVDEFCMD)(HWND, IShellFolder*, LPCITEMIDLIST);
 typedef void (APIENTRY *RUNFILEDLG)(HWND, HICON, LPCWSTR, LPCWSTR, LPCWSTR, UINT);
 typedef void (APIENTRY *EXITWINDLG)(HWND);
-typedef HRESULT (APIENTRY *SHWINHELP)(HWND, LPWSTR, UINT, DWORD);
+typedef HRESULT(APIENTRY *SHWINHELP)(HWND, LPWSTR, UINT, DWORD);
 
 /* Constants for RunFileDlg */
 #define RFF_CALCDIRECTORY   0x04    /* Calculates the working directory from the file name. */
 
-static __inline ULONG
-Win32DbgPrint(const char *filename, int line, const char *lpFormat, ...)
-{
-    char szMsg[512];
-    char *szMsgStart;
-    const char *fname;
-    va_list vl;
-    ULONG uRet;
-
-    fname = strrchr(filename, '\\');
-    if (fname == NULL)
-    {
-        fname = strrchr(filename, '/');
-        if (fname != NULL)
-            fname++;
-    }
-    else
-        fname++;
-
-    if (fname == NULL)
-        fname = filename;
-
-    szMsgStart = szMsg + sprintf(szMsg, "%s:%d: ", fname, line);
-
-    va_start(vl, lpFormat);
-    uRet = (ULONG)vsprintf(szMsgStart, lpFormat, vl);
-    va_end(vl);
-
-    OutputDebugStringA(szMsg);
-
-    return uRet;
-}
-
 #define ASSERT(cond) \
     do if (!(cond)) { \
         Win32DbgPrint(__FILE__, __LINE__, "ASSERTION %s FAILED!\n", #cond); \
-    } while (0)
-
-#define DbgPrint(fmt, ...) \
-    Win32DbgPrint(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
+        } while (0)
 
 extern HINSTANCE hExplorerInstance;
 extern HMODULE hUser32;
@@ -103,33 +73,33 @@ extern DRAWCAPTEMP DrawCapTemp;
 
 typedef struct _DROPTARGET_CALLBACKS
 {
-    HRESULT (*OnDragEnter)(IN IDropTarget *pDropTarget,
-                           IN PVOID Context,
-                           IN const FORMATETC *Format,
-                           IN DWORD grfKeyState,
-                           IN POINTL pt,
-                           IN OUT DWORD *pdwEffect);
-    HRESULT (*OnDragOver)(IN IDropTarget *pDropTarget,
+    HRESULT(*OnDragEnter)(IN IDropTarget *pDropTarget,
                           IN PVOID Context,
+                          IN const FORMATETC *Format,
                           IN DWORD grfKeyState,
                           IN POINTL pt,
                           IN OUT DWORD *pdwEffect);
-    HRESULT (*OnDragLeave)(IN IDropTarget *pDropTarget,
-                           IN PVOID Context);
-    HRESULT (*OnDrop)(IN IDropTarget *pDropTarget,
-                      IN PVOID Context,
-                      IN const FORMATETC *Format,
-                      IN DWORD grfKeyState,
-                      IN POINTL pt,
-                      IN OUT DWORD *pdwEffect);
+    HRESULT(*OnDragOver)(IN IDropTarget *pDropTarget,
+                         IN PVOID Context,
+                         IN DWORD grfKeyState,
+                         IN POINTL pt,
+                         IN OUT DWORD *pdwEffect);
+    HRESULT(*OnDragLeave)(IN IDropTarget *pDropTarget,
+                          IN PVOID Context);
+    HRESULT(*OnDrop)(IN IDropTarget *pDropTarget,
+                     IN PVOID Context,
+                     IN const FORMATETC *Format,
+                     IN DWORD grfKeyState,
+                     IN POINTL pt,
+                     IN OUT DWORD *pdwEffect);
 } DROPTARGET_CALLBACKS, *PDROPTARGET_CALLBACKS;
 
 IDropTarget *
 CreateDropTarget(IN HWND hwndTarget,
-                 IN DWORD nSupportedFormats,
-                 IN const FORMATETC *Formats  OPTIONAL,
-                 IN PVOID Context  OPTIONAL,
-                 IN const DROPTARGET_CALLBACKS *Callbacks  OPTIONAL);
+IN DWORD nSupportedFormats,
+IN const FORMATETC *Formats  OPTIONAL,
+IN PVOID Context  OPTIONAL,
+IN const DROPTARGET_CALLBACKS *Callbacks  OPTIONAL);
 
 /*
  * explorer.c
@@ -139,46 +109,44 @@ CreateDropTarget(IN HWND hwndTarget,
 
 LONG
 SetWindowStyle(IN HWND hWnd,
-               IN LONG dwStyleMask,
-               IN LONG dwStyle);
+IN LONG dwStyleMask,
+IN LONG dwStyle);
 
 LONG
 SetWindowExStyle(IN HWND hWnd,
-                 IN LONG dwStyleMask,
-                 IN LONG dwStyle);
+IN LONG dwStyleMask,
+IN LONG dwStyle);
 
 HMENU
 LoadPopupMenu(IN HINSTANCE hInstance,
-              IN LPCTSTR lpMenuName);
+IN LPCTSTR lpMenuName);
 
 HMENU
 FindSubMenu(IN HMENU hMenu,
-            IN UINT uItem,
-            IN BOOL fByPosition);
+IN UINT uItem,
+IN BOOL fByPosition);
 
 BOOL
 GetCurrentLoggedOnUserName(OUT LPTSTR szBuffer,
-                           IN DWORD dwBufferSize);
+IN DWORD dwBufferSize);
 
 BOOL
 FormatMenuString(IN HMENU hMenu,
-                 IN UINT uPosition,
-                 IN UINT uFlags,
-                 ...);
+IN UINT uPosition,
+IN UINT uFlags,
+...);
 
 BOOL
 GetExplorerRegValueSet(IN HKEY hKey,
-                       IN LPCTSTR lpSubKey,
-                       IN LPCTSTR lpValue);
+IN LPCTSTR lpSubKey,
+IN LPCTSTR lpValue);
 
 /*
  *  rshell.c
  */
 
-HRESULT
-CStartMenu_Constructor(
-    REFIID riid,
-    void **ppv);
+HRESULT WINAPI
+_CStartMenu_Constructor(REFIID riid, void **ppv);
 
 /*
  * traywnd.c
@@ -186,13 +154,13 @@ CStartMenu_Constructor(
 
 #define TWM_OPENSTARTMENU (WM_USER + 260)
 
-typedef HMENU (*PCREATECTXMENU)(IN HWND hWndOwner,
-                                IN PVOID *ppcmContext,
-                                IN PVOID Context  OPTIONAL);
-typedef VOID (*PCTXMENUCOMMAND)(IN HWND hWndOwner,
-                                IN UINT uiCmdId,
-                                IN PVOID pcmContext  OPTIONAL,
-                                IN PVOID Context  OPTIONAL);
+typedef HMENU(*PCREATECTXMENU)(IN HWND hWndOwner,
+                               IN PVOID *ppcmContext,
+                               IN PVOID Context  OPTIONAL);
+typedef VOID(*PCTXMENUCOMMAND)(IN HWND hWndOwner,
+                               IN UINT uiCmdId,
+                               IN PVOID pcmContext  OPTIONAL,
+                               IN PVOID Context  OPTIONAL);
 
 typedef struct _TRAYWINDOW_CTXMENU
 {
@@ -203,22 +171,22 @@ typedef struct _TRAYWINDOW_CTXMENU
 extern const GUID IID_IShellDesktopTray;
 
 #define INTERFACE ITrayWindow
-DECLARE_INTERFACE_(ITrayWindow,IUnknown)
+DECLARE_INTERFACE_(ITrayWindow, IUnknown)
 {
     /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef) (THIS) PURE;
-    STDMETHOD_(ULONG,Release) (THIS) PURE;
+    STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
+    STDMETHOD_(ULONG, AddRef) (THIS) PURE;
+    STDMETHOD_(ULONG, Release) (THIS) PURE;
     /*** ITrayWindow methods ***/
-    STDMETHOD_(HRESULT,Open) (THIS) PURE;
-    STDMETHOD_(HRESULT,Close) (THIS) PURE;
-    STDMETHOD_(HWND,GetHWND) (THIS) PURE;
-    STDMETHOD_(BOOL,IsSpecialHWND) (THIS_ HWND hWnd) PURE;
-    STDMETHOD_(BOOL,IsHorizontal) (THIS) PURE;
-    STDMETHOD_(HFONT,GetCaptionFonts) (THIS_ HFONT *phBoldCaption) PURE;
-    STDMETHOD_(HWND,DisplayProperties) (THIS) PURE;
-    STDMETHOD_(BOOL,ExecContextMenuCmd) (THIS_ UINT uiCmd) PURE;
-    STDMETHOD_(BOOL,Lock) (THIS_ BOOL bLock) PURE;
+    STDMETHOD_(HRESULT, Open) (THIS) PURE;
+    STDMETHOD_(HRESULT, Close) (THIS) PURE;
+    STDMETHOD_(HWND, GetHWND) (THIS) PURE;
+    STDMETHOD_(BOOL, IsSpecialHWND) (THIS_ HWND hWnd) PURE;
+    STDMETHOD_(BOOL, IsHorizontal) (THIS) PURE;
+    STDMETHOD_(HFONT, GetCaptionFonts) (THIS_ HFONT *phBoldCaption) PURE;
+    STDMETHOD_(HWND, DisplayProperties) (THIS) PURE;
+    STDMETHOD_(BOOL, ExecContextMenuCmd) (THIS_ UINT uiCmd) PURE;
+    STDMETHOD_(BOOL, Lock) (THIS_ BOOL bLock) PURE;
 };
 #undef INTERFACE
 
@@ -245,8 +213,7 @@ RegisterTrayWindowClass(VOID);
 VOID
 UnregisterTrayWindowClass(VOID);
 
-ITrayWindow *
-CreateTrayWindow(VOID);
+HRESULT CreateTrayWindow(ITrayWindow ** ppTray);
 
 VOID
 TrayProcessMessages(IN OUT ITrayWindow *Tray);
@@ -259,20 +226,21 @@ TrayMessageLoop(IN OUT ITrayWindow *Tray);
  */
 
 /* Structure to hold non-default options*/
-typedef struct _ADVANCED_SETTINGS {
+typedef struct _ADVANCED_SETTINGS
+{
     BOOL bShowSeconds;
 } ADVANCED_SETTINGS, *PADVANCED_SETTINGS;
 
 extern ADVANCED_SETTINGS AdvancedSettings;
-extern const TCHAR szAdvancedSettingsKey[];
+extern const TCHAR szAdvancedSettingsKey [];
 
 VOID
 LoadAdvancedSettings(VOID);
 
 BOOL
 SaveSettingDword(IN PCTSTR pszKeyName,
-                 IN PCTSTR pszValueName,
-                 IN DWORD dwValue);
+IN PCTSTR pszValueName,
+IN DWORD dwValue);
 
 /*
  * startup.c
@@ -305,14 +273,14 @@ DesktopDestroyShellWindow(IN HANDLE hDesktop);
 extern const GUID CLSID_ITaskBand;
 
 #define INTERFACE ITaskBand
-DECLARE_INTERFACE_(ITaskBand,IUnknown)
+DECLARE_INTERFACE_(ITaskBand, IUnknown)
 {
     /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef) (THIS) PURE;
-    STDMETHOD_(ULONG,Release) (THIS) PURE;
+    STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
+    STDMETHOD_(ULONG, AddRef) (THIS) PURE;
+    STDMETHOD_(ULONG, Release) (THIS) PURE;
     /*** ITaskBand methods ***/
-    STDMETHOD_(HRESULT,GetRebarBandID)(THIS_ DWORD *pdwBandID) PURE;
+    STDMETHOD_(HRESULT, GetRebarBandID)(THIS_ DWORD *pdwBandID) PURE;
 };
 #undef INTERFACE
 
@@ -333,20 +301,20 @@ CreateTaskBand(IN OUT ITrayWindow *Tray);
  */
 
 #define INTERFACE ITrayBandSite
-DECLARE_INTERFACE_(ITrayBandSite,IUnknown)
+DECLARE_INTERFACE_(ITrayBandSite, IUnknown)
 {
     /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef) (THIS) PURE;
-    STDMETHOD_(ULONG,Release) (THIS) PURE;
+    STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
+    STDMETHOD_(ULONG, AddRef) (THIS) PURE;
+    STDMETHOD_(ULONG, Release) (THIS) PURE;
     /*** IBandSiteStreamCallback ***/
-    STDMETHOD_(HRESULT,OnLoad)(THIS_ IStream *pStm, REFIID riid, PVOID *pvObj) PURE;
-    STDMETHOD_(HRESULT,OnSave)(THIS_ IUnknown *pUnk, IStream *pStm) PURE;
+    STDMETHOD_(HRESULT, OnLoad)(THIS_ IStream *pStm, REFIID riid, PVOID *pvObj) PURE;
+    STDMETHOD_(HRESULT, OnSave)(THIS_ IUnknown *pUnk, IStream *pStm) PURE;
     /*** ITrayBandSite methods ***/
-    STDMETHOD_(HRESULT,IsTaskBand) (THIS_ IUnknown *punk) PURE;
-    STDMETHOD_(HRESULT,ProcessMessage) (THIS_ HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) PURE;
-    STDMETHOD_(HRESULT,AddContextMenus) (THIS_ HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags, IContextMenu **ppcm) PURE;
-    STDMETHOD_(HRESULT,Lock) (THIS_ BOOL bLock) PURE;
+    STDMETHOD_(HRESULT, IsTaskBand) (THIS_ IUnknown *punk) PURE;
+    STDMETHOD_(HRESULT, ProcessMessage) (THIS_ HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plResult) PURE;
+    STDMETHOD_(HRESULT, AddContextMenus) (THIS_ HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags, IContextMenu **ppcm) PURE;
+    STDMETHOD_(HRESULT, Lock) (THIS_ BOOL bLock) PURE;
 };
 #undef INTERFACE
 
@@ -367,8 +335,8 @@ DECLARE_INTERFACE_(ITrayBandSite,IUnknown)
 
 ITrayBandSite *
 CreateTrayBandSite(IN OUT ITrayWindow *Tray,
-                   OUT HWND *phWndRebar,
-                   OUT HWND *phWndTaskSwitch);
+OUT HWND *phWndRebar,
+OUT HWND *phWndTaskSwitch);
 
 /*
  * startmnu.c
@@ -377,12 +345,12 @@ CreateTrayBandSite(IN OUT ITrayWindow *Tray,
 extern const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu;
 
 #define INTERFACE IStartMenuSite
-DECLARE_INTERFACE_(IStartMenuSite,IUnknown)
+DECLARE_INTERFACE_(IStartMenuSite, IUnknown)
 {
     /*** IUnknown methods ***/
-    STDMETHOD_(HRESULT,QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
-    STDMETHOD_(ULONG,AddRef) (THIS) PURE;
-    STDMETHOD_(ULONG,Release) (THIS) PURE;
+    STDMETHOD_(HRESULT, QueryInterface) (THIS_ REFIID riid, void** ppvObject) PURE;
+    STDMETHOD_(ULONG, AddRef) (THIS) PURE;
+    STDMETHOD_(ULONG, Release) (THIS) PURE;
     /*** IStartMenuSite ***/
 };
 #undef INTERFACE
@@ -397,14 +365,14 @@ DECLARE_INTERFACE_(IStartMenuSite,IUnknown)
 
 IMenuPopup*
 CreateStartMenu(IN ITrayWindow *Tray,
-                OUT IMenuBand **ppMenuBand,
-                IN HBITMAP hbmBanner  OPTIONAL,
-                IN BOOL bSmallIcons);
+OUT IMenuBand **ppMenuBand,
+IN HBITMAP hbmBanner  OPTIONAL,
+IN BOOL bSmallIcons);
 
 HRESULT
 UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
-                IN HBITMAP hbmBanner  OPTIONAL,
-                IN BOOL bSmallIcons);
+IN HBITMAP hbmBanner  OPTIONAL,
+IN BOOL bSmallIcons);
 
 /*
  * trayntfy.c
@@ -431,16 +399,14 @@ UnregisterTrayNotifyWndClass(VOID);
 
 HWND
 CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow,
-                    IN BOOL bHideClock);
+IN BOOL bHideClock);
 
 VOID
-TrayNotify_NotifyMsg(IN HWND hwnd,
-                     IN WPARAM wParam,
-                     IN LPARAM lParam);
+TrayNotify_NotifyMsg(IN WPARAM wParam,
+IN LPARAM lParam);
 
 BOOL
-TrayNotify_GetClockRect(IN HWND hwnd,
-                        OUT PRECT rcClock);
+TrayNotify_GetClockRect(OUT PRECT rcClock);
 
 /*
  * taskswnd.c
@@ -457,9 +423,12 @@ UnregisterTaskSwitchWndClass(VOID);
 
 HWND
 CreateTaskSwitchWnd(IN HWND hWndParent,
-                    IN OUT ITrayWindow *Tray);
+IN OUT ITrayWindow *Tray);
 
 HRESULT
 Tray_OnStartMenuDismissed();
 
+HRESULT
+IsSameObject(IN IUnknown *punk1, IN IUnknown *punk2);
+
 #endif /* _EXPLORER_PRECOMP__H_ */
similarity index 93%
rename from base/shell/explorer-new/rshell.c
rename to base/shell/explorer-new/rshell.cpp
index 1ea863a..49e2352 100644 (file)
@@ -24,7 +24,7 @@ static HINSTANCE hRShell = NULL;
 
 typedef HRESULT(WINAPI * PSTARTMENU_CONSTRUCTOR)(REFIID riid, void **ppv);
 
-HRESULT CStartMenu_Constructor(REFIID riid, void **ppv)
+HRESULT WINAPI _CStartMenu_Constructor(REFIID riid, void **ppv)
 {
     if (!hRShell)
     {
@@ -40,7 +40,7 @@ HRESULT CStartMenu_Constructor(REFIID riid, void **ppv)
         }
     }
 
-    return CoCreateInstance(&CLSID_StartMenu,
+    return CoCreateInstance(CLSID_StartMenu,
                             NULL,
                             CLSCTX_INPROC_SERVER,
                             riid,
@@ -49,7 +49,7 @@ HRESULT CStartMenu_Constructor(REFIID riid, void **ppv)
 
 typedef HANDLE(WINAPI * PSHCREATEDESKTOP)(IShellDesktopTray *ShellDesk);
 
-HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
+HANDLE WINAPI _SHCreateDesktop(IShellDesktopTray *ShellDesk)
 {
     HINSTANCE hFallback;
 
@@ -83,7 +83,7 @@ HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
 
 typedef BOOL(WINAPI *PSHDESKTOPMESSAGELOOP)(HANDLE hDesktop);
 
-BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
+BOOL WINAPI _SHDesktopMessageLoop(HANDLE hDesktop)
 {
     HINSTANCE hFallback;
 
@@ -117,7 +117,7 @@ BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
 
 typedef DWORD(WINAPI* PWINLIST_INIT)(void);
 
-DWORD WINAPI WinList_Init(void)
+DWORD WINAPI _WinList_Init(void)
 {
     HINSTANCE hFallback;
 
@@ -151,7 +151,7 @@ DWORD WINAPI WinList_Init(void)
 
 typedef void (WINAPI *PSHELLDDEINIT)(BOOL bInit);
 
-void WINAPI ShellDDEInit(BOOL bInit)
+void WINAPI _ShellDDEInit(BOOL bInit)
 {
     HINSTANCE hFallback;
 
similarity index 96%
rename from base/shell/explorer-new/settings.c
rename to base/shell/explorer-new/settings.cpp
index b982c9a..1496457 100644 (file)
@@ -21,8 +21,7 @@
 #include "precomp.h"
 
 ADVANCED_SETTINGS AdvancedSettings;
-const TCHAR szAdvancedSettingsKey[] = TEXT("Software\\ReactOS\\Features\\Explorer");
-
+const WCHAR szAdvancedSettingsKey[] = TEXT("Software\\ReactOS\\Features\\Explorer");
 
 VOID
 LoadAdvancedSettings(VOID)
similarity index 82%
rename from base/shell/explorer-new/shellservice.c
rename to base/shell/explorer-new/shellservice.cpp
index 02d3600..39a83cb 100644 (file)
@@ -25,26 +25,26 @@ extern HRESULT ShutdownShellServices(HDPA hdpa);
 
 static int CALLBACK InitializeAllCallback(void* pItem, void* pData)
 {
-    IOleCommandTarget * pOct = pItem;
-    HRESULT * phr = pData;
+    IOleCommandTarget * pOct = reinterpret_cast<IOleCommandTarget *>(pItem);
+    HRESULT * phr = reinterpret_cast<HRESULT *>(pData);
     TRACE("Initializing SSO %p\n", pOct);
-    *phr = IOleCommandTarget_Exec(pOct, &CGID_ShellServiceObject, OLECMDID_NEW, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
+    *phr = pOct->Exec(&CGID_ShellServiceObject, OLECMDID_NEW, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
     return SUCCEEDED(*phr);
 }
 
 static int CALLBACK ShutdownAllCallback(void* pItem, void* pData)
 {
-    IOleCommandTarget * pOct = pItem;
+    IOleCommandTarget * pOct = reinterpret_cast<IOleCommandTarget *>(pItem);
     TRACE("Shutting down SSO %p\n", pOct);
-    IOleCommandTarget_Exec(pOct, &CGID_ShellServiceObject, OLECMDID_SAVE, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
+    pOct->Exec(&CGID_ShellServiceObject, OLECMDID_SAVE, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
     return TRUE;
 }
 
 static int CALLBACK DeleteAllEnumCallback(void* pItem, void* pData)
 {
-    IOleCommandTarget * pOct = pItem;
+    IOleCommandTarget * pOct = reinterpret_cast<IOleCommandTarget *>(pItem);
     TRACE("Releasing SSO %p\n", pOct);
-    IUnknown_Release(pOct);
+    pOct->Release();
     return TRUE;
 }
 
@@ -92,14 +92,14 @@ HRESULT InitShellServices(HDPA * phdpa)
         }
 
         hr = CLSIDFromString(value, &clsid);
-        if (FAILED(hr))
+        if (FAILED_UNEXPECTEDLY(hr))
         {
             ERR("CLSIDFromString failed %08x.\n", hr);
             goto cleanup;
         }
 
-        hr = CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER, &IID_IOleCommandTarget, (VOID**) &pOct);
-        if (FAILED(hr))
+        hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IOleCommandTarget, &pOct));
+        if (FAILED_UNEXPECTEDLY(hr))
         {
             ERR("CoCreateInstance failed %08x.\n", hr);
             goto cleanup;
@@ -122,7 +122,7 @@ HRESULT InitShellServices(HDPA * phdpa)
 
     /* Initialize */
     DPA_EnumCallback(hdpa, InitializeAllCallback, &hr);
-    if (FAILED(hr))
+    if (FAILED_UNEXPECTEDLY(hr))
         goto cleanup;
 
     *phdpa = hdpa;
diff --git a/base/shell/explorer-new/startmnu.c b/base/shell/explorer-new/startmnu.c
deleted file mode 100644 (file)
index 36ffaef..0000000
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- * ReactOS Explorer
- *
- * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "precomp.h"
-
-/*
- * Start menu button context menu
- */
-
-typedef struct _STARTMNU_CTMENU_CTX
-{
-    IContextMenu *pcm;
-    LPITEMIDLIST pidl;
-} STARTMNU_CTMENU_CTX, *PSTARTMNU_CTMENU_CTX;
-
-static HMENU
-CreateStartContextMenu(IN HWND hWndOwner,
-                       IN PVOID *ppcmContext,
-                       IN PVOID Context  OPTIONAL);
-
-static VOID
-OnStartContextMenuCommand(IN HWND hWndOwner,
-                          IN UINT uiCmdId,
-                          IN PVOID pcmContext  OPTIONAL,
-                          IN PVOID Context  OPTIONAL);
-
-const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu = {
-    CreateStartContextMenu,
-    OnStartContextMenuCommand
-};
-
-static HMENU
-CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner,
-                                     IN OUT IShellFolder *psf,
-                                     IN OUT LPITEMIDLIST pidl,
-                                     OUT IContextMenu **ppcm)
-{
-    IContextMenu *pcm;
-    HRESULT hRet;
-    HMENU hPopup;
-
-    hRet = IShellFolder_GetUIObjectOf(psf,
-                                      hWndOwner,
-                                      1,
-                                      (LPCITEMIDLIST *)&pidl,
-                                      &IID_IContextMenu,
-                                      NULL,
-                                      (PVOID *)&pcm);
-    if (SUCCEEDED(hRet))
-    {
-        hPopup = CreatePopupMenu();
-
-        if (hPopup != NULL)
-        {
-            hRet = IContextMenu_QueryContextMenu(pcm,
-                                                 hPopup,
-                                                 0,
-                                                 ID_SHELL_CMD_FIRST,
-                                                 ID_SHELL_CMD_LAST,
-                                                 CMF_VERBSONLY);
-
-            if (SUCCEEDED(hRet))
-            {
-                *ppcm = pcm;
-                return hPopup;
-            }
-
-            DestroyMenu(hPopup);
-        }
-
-        IContextMenu_Release(pcm);
-    }
-
-    return NULL;
-}
-
-static VOID
-OnStartContextMenuCommand(IN HWND hWndOwner,
-                          IN UINT uiCmdId,
-                          IN PVOID pcmContext  OPTIONAL,
-                          IN PVOID Context  OPTIONAL)
-{
-    PSTARTMNU_CTMENU_CTX psmcmc = pcmContext;
-
-    if (uiCmdId != 0)
-    {
-        if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST))
-        {
-            CMINVOKECOMMANDINFO cmici = {0};
-            CHAR szDir[MAX_PATH];
-
-            /* Setup and invoke the shell command */
-            cmici.cbSize = sizeof(cmici);
-            cmici.hwnd = hWndOwner;
-            cmici.lpVerb = (LPCSTR)MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST);
-            cmici.nShow = SW_NORMAL;
-
-            /* FIXME: Support Unicode!!! */
-            if (SHGetPathFromIDListA(psmcmc->pidl,
-                                     szDir))
-            {
-                cmici.lpDirectory = szDir;
-            }
-
-            IContextMenu_InvokeCommand(psmcmc->pcm,
-                                       &cmici);
-        }
-        else
-        {
-            ITrayWindow_ExecContextMenuCmd((ITrayWindow *)Context,
-                                           uiCmdId);
-        }
-    }
-
-    IContextMenu_Release(psmcmc->pcm);
-
-    HeapFree(hProcessHeap,
-             0,
-             psmcmc);
-}
-
-static VOID
-AddStartContextMenuItems(IN HWND hWndOwner,
-                         IN HMENU hPopup)
-{
-    TCHAR szBuf[MAX_PATH];
-    HRESULT hRet;
-
-    /* Add the "Open All Users" menu item */
-    if (LoadString(hExplorerInstance,
-                   IDS_PROPERTIES,
-                   szBuf,
-                   sizeof(szBuf) / sizeof(szBuf[0])))
-    {
-        AppendMenu(hPopup,
-                   MF_STRING,
-                   ID_SHELL_CMD_PROPERTIES,
-                   szBuf);
-    }
-
-    if (!SHRestricted(REST_NOCOMMONGROUPS))
-    {
-        /* Check if we should add menu items for the common start menu */
-        hRet = SHGetFolderPath(hWndOwner,
-                               CSIDL_COMMON_STARTMENU,
-                               NULL,
-                               SHGFP_TYPE_CURRENT,
-                               szBuf);
-        if (SUCCEEDED(hRet) && hRet != S_FALSE)
-        {
-            /* The directory exists, but only show the items if the
-               user can actually make any changes to the common start
-               menu. This is most likely only the case if the user
-               has administrative rights! */
-            if (IsUserAnAdmin())
-            {
-                AppendMenu(hPopup,
-                           MF_SEPARATOR,
-                           0,
-                           NULL);
-
-                /* Add the "Open All Users" menu item */
-                if (LoadString(hExplorerInstance,
-                               IDS_OPEN_ALL_USERS,
-                               szBuf,
-                               sizeof(szBuf) / sizeof(szBuf[0])))
-                {
-                    AppendMenu(hPopup,
-                               MF_STRING,
-                               ID_SHELL_CMD_OPEN_ALL_USERS,
-                               szBuf);
-                }
-
-                /* Add the "Explore All Users" menu item */
-                if (LoadString(hExplorerInstance,
-                               IDS_EXPLORE_ALL_USERS,
-                               szBuf,
-                               sizeof(szBuf) / sizeof(szBuf[0])))
-                {
-                    AppendMenu(hPopup,
-                               MF_STRING,
-                               ID_SHELL_CMD_EXPLORE_ALL_USERS,
-                               szBuf);
-                }
-            }
-        }
-    }
-}
-
-static HMENU
-CreateStartContextMenu(IN HWND hWndOwner,
-                       IN PVOID *ppcmContext,
-                       IN PVOID Context  OPTIONAL)
-{
-    LPITEMIDLIST pidlStart, pidlLast;
-    IShellFolder *psfStart, *psfDesktop;
-    IContextMenu *pcm;
-    HRESULT hRet;
-    HMENU hPopup;
-
-    pidlStart = SHCloneSpecialIDList(hWndOwner,
-                                     CSIDL_STARTMENU,
-                                     TRUE);
-
-    if (pidlStart != NULL)
-    {
-        pidlLast = ILClone(ILFindLastID(pidlStart));
-        ILRemoveLastID(pidlStart);
-
-        if (pidlLast != NULL)
-        {
-            hRet = SHGetDesktopFolder(&psfDesktop);
-            if (SUCCEEDED(hRet))
-            {
-                hRet = IShellFolder_BindToObject(psfDesktop,
-                                                 pidlStart,
-                                                 NULL,
-                                                 &IID_IShellFolder,
-                                                 (PVOID*)&psfStart);
-                if (SUCCEEDED(hRet))
-                {
-                    hPopup = CreateContextMenuFromShellFolderPidl(hWndOwner,
-                                                                  psfStart,
-                                                                  pidlLast,
-                                                                  &pcm);
-
-                    if (hPopup != NULL)
-                    {
-                        PSTARTMNU_CTMENU_CTX psmcmc;
-
-                        psmcmc = HeapAlloc(hProcessHeap,
-                                           0,
-                                           sizeof(*psmcmc));
-                        if (psmcmc != NULL)
-                        {
-                            psmcmc->pcm = pcm;
-                            psmcmc->pidl = pidlLast;
-
-                            AddStartContextMenuItems(hWndOwner,
-                                                     hPopup);
-
-                            *ppcmContext = psmcmc;
-                            return hPopup;
-                        }
-                        else
-                        {
-                            IContextMenu_Release(pcm);
-
-                            DestroyMenu(hPopup);
-                            hPopup = NULL;
-                        }
-                    }
-
-                    IShellFolder_Release(psfStart);
-                }
-
-                IShellFolder_Release(psfDesktop);
-            }
-
-            ILFree(pidlLast);
-        }
-
-        ILFree(pidlStart);
-    }
-
-    return NULL;
-}
-
-/*****************************************************************************
- ** IStartMenuSite ***********************************************************
- *****************************************************************************/
-
-static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl;
-static const IServiceProviderVtbl IServiceProviderImpl_Vtbl;
-static const ITrayPrivVtbl ITrayPrivImpl_Vtbl;
-static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl;
-static const IMenuPopupVtbl IMenuPopupImpl_Vtbl;
-
-typedef struct
-{
-    const IStartMenuSiteVtbl *lpVtbl;
-    const IServiceProviderVtbl *lpServiceProviderVtbl;
-    const ITrayPrivVtbl *lpStartMenuCallbackVtbl;
-    const IOleCommandTargetVtbl *lpOleCommandTargetVtbl;
-    const IMenuPopupVtbl *lpMenuPopupVtbl;
-    LONG Ref;
-
-    ITrayWindow *Tray;
-
-    IMenuPopup * StartMenuPopup;
-} IStartMenuSiteImpl;
-
-static IUnknown *
-IUnknown_from_IStartMenuSiteImpl(IStartMenuSiteImpl *This)
-{
-    return (IUnknown *)&This->lpVtbl;
-}
-
-IMPL_CASTS(IStartMenuSite, IStartMenuSite, lpVtbl)
-IMPL_CASTS(IServiceProvider, IStartMenuSite, lpServiceProviderVtbl)
-IMPL_CASTS(ITrayPriv, IStartMenuSite, lpStartMenuCallbackVtbl)
-IMPL_CASTS(IOleCommandTarget, IStartMenuSite, lpOleCommandTargetVtbl)
-IMPL_CASTS(IDeskBar, IStartMenuSite, lpMenuPopupVtbl)
-IMPL_CASTS(IMenuPopup, IStartMenuSite, lpMenuPopupVtbl)
-
-/*******************************************************************/
-
-static ULONG STDMETHODCALLTYPE
-IStartMenuSiteImpl_AddRef(IN OUT IStartMenuSite *iface)
-{
-    IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
-
-    return InterlockedIncrement(&This->Ref);
-}
-
-static VOID
-IStartMenuSiteImpl_Free(IN OUT IStartMenuSiteImpl *This)
-{
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-static ULONG STDMETHODCALLTYPE
-IStartMenuSiteImpl_Release(IN OUT IStartMenuSite *iface)
-{
-    IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
-    ULONG Ret;
-
-    Ret = InterlockedDecrement(&This->Ref);
-
-    if (Ret == 0)
-        IStartMenuSiteImpl_Free(This);
-
-    return Ret;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_QueryInterface(IN OUT IStartMenuSite *iface,
-                                  IN REFIID riid,
-                                  OUT LPVOID *ppvObj)
-{
-    IStartMenuSiteImpl *This;
-
-    if (ppvObj == NULL)
-        return E_POINTER;
-
-    This = IStartMenuSiteImpl_from_IStartMenuSite(iface);
-
-    if (IsEqualIID(riid,
-                   &IID_IUnknown))
-    {
-        *ppvObj = IUnknown_from_IStartMenuSiteImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IServiceProvider))
-    {
-        *ppvObj = IServiceProvider_from_IStartMenuSiteImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_ITrayPriv) ||
-             IsEqualIID(riid,
-                        &IID_IOleWindow))
-    {
-        *ppvObj = ITrayPriv_from_IStartMenuSiteImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IOleCommandTarget))
-    {
-        *ppvObj = IOleCommandTarget_from_IStartMenuSiteImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IDeskBar))
-    {
-        *ppvObj = IDeskBar_from_IStartMenuSiteImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IMenuPopup))
-    {
-        *ppvObj = IMenuPopup_from_IStartMenuSiteImpl(This);
-    }
-    else
-    {
-        TRACE("IStartMenuSite::QueryInterface queried unsupported interface: "
-                 "{0x%8x,0x%4x,0x%4x,{0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x,0x%2x}}\n",
-                 riid->Data1, riid->Data2, riid->Data3, riid->Data4[0], riid->Data4[1],
-                 riid->Data4[2], riid->Data4[3], riid->Data4[4], riid->Data4[5],
-                 riid->Data4[6], riid->Data4[7]);
-        *ppvObj = NULL;
-        return E_NOINTERFACE;
-    }
-
-    IStartMenuSiteImpl_AddRef(iface);
-    return S_OK;
-}
-
-static const IStartMenuSiteVtbl IStartMenuSiteImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    IStartMenuSiteImpl_QueryInterface,
-    IStartMenuSiteImpl_AddRef,
-    IStartMenuSiteImpl_Release,
-    /*** IStartMenuSite methods ***/
-};
-
-/*******************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IServiceProvider, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IServiceProvider, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IServiceProvider, IStartMenuSite)
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_QueryService(IN OUT IServiceProvider *iface,
-                                IN REFGUID guidService,
-                                IN REFIID riid,
-                                OUT PVOID *ppvObject)
-{
-    IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_IServiceProvider(iface);
-
-    if (IsEqualGUID(guidService,
-                    &SID_SMenuPopup))
-    {
-        return IStartMenuSiteImpl_QueryInterface(IStartMenuSite_from_IStartMenuSiteImpl(This),
-                                                 riid,
-                                                 ppvObject);
-    }
-
-    return E_NOINTERFACE;
-}
-
-static const IServiceProviderVtbl IServiceProviderImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IServiceProvider, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IServiceProvider, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IServiceProvider, IStartMenuSite),
-    /*** IServiceProvider methods ***/
-    IStartMenuSiteImpl_QueryService
-};
-
-/*******************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(ITrayPriv, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_RELEASE(ITrayPriv, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(ITrayPriv, IStartMenuSite)
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_GetWindow(IN OUT ITrayPriv *iface,
-                             OUT HWND *phwnd)
-{
-    IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
-    TRACE("ITrayPriv::GetWindow\n");
-
-    *phwnd = ITrayWindow_GetHWND(This->Tray);
-    if (*phwnd != NULL)
-        return S_OK;
-
-    return E_FAIL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_ContextSensitiveHelp(IN OUT ITrayPriv *iface,
-                                        IN BOOL fEnterMode)
-{
-    TRACE("ITrayPriv::ContextSensitiveHelp\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_Execute(IN OUT ITrayPriv *iface,
-                           IN IShellFolder *pShellFolder,
-                           IN LPCITEMIDLIST pidl)
-{
-    HMODULE hShlwapi;
-    HRESULT ret = S_FALSE;
-
-    IStartMenuSiteImpl *This = IStartMenuSiteImpl_from_ITrayPriv(iface);
-
-    TRACE("ITrayPriv::Execute\n");
-
-    hShlwapi = GetModuleHandle(TEXT("SHLWAPI.DLL"));
-    if (hShlwapi != NULL)
-    {
-        SHINVDEFCMD SHInvokeDefCmd;
-
-        /* SHInvokeDefaultCommand */
-        SHInvokeDefCmd = (SHINVDEFCMD)GetProcAddress(hShlwapi,
-                                                     (LPCSTR)((LONG)279));
-        if (SHInvokeDefCmd != NULL)
-        {
-            ret = SHInvokeDefCmd(ITrayWindow_GetHWND(This->Tray),
-                                 pShellFolder,
-                                 pidl);
-        }
-    }
-
-    return ret;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_Unknown(IN OUT ITrayPriv *iface,
-                           IN PVOID Unknown1,
-                           IN PVOID Unknown2,
-                           IN PVOID Unknown3,
-                           IN PVOID Unknown4)
-{
-    TRACE("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4);
-    return E_NOTIMPL;
-}
-
-static BOOL
-ShowUndockMenuItem(VOID)
-{
-    TRACE("ShowUndockMenuItem() not implemented!\n");
-    /* FIXME: How do we detect this?! */
-    return FALSE;
-}
-
-static BOOL
-ShowSynchronizeMenuItem(VOID)
-{
-    TRACE("ShowSynchronizeMenuItem() not implemented!\n");
-    /* FIXME: How do we detect this?! */
-    return FALSE;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_AppendMenu(IN OUT ITrayPriv *iface,
-                              OUT HMENU* phMenu)
-{
-    HMENU hMenu, hSettingsMenu;
-    DWORD dwLogoff;
-    BOOL bWantLogoff;
-    UINT uLastItemsCount = 5; /* 5 menu items below the last separator */
-    TCHAR szUser[128];
-
-    TRACE("ITrayPriv::AppendMenu\n");
-
-    hMenu = LoadPopupMenu(hExplorerInstance,
-                          MAKEINTRESOURCE(IDM_STARTMENU));
-    *phMenu = hMenu;
-    if (hMenu == NULL)
-        return E_FAIL;
-
-    /* Remove menu items that don't apply */
-
-    dwLogoff = SHRestricted(REST_STARTMENULOGOFF);
-    bWantLogoff = (dwLogoff == 2 ||
-                   SHRestricted(REST_FORCESTARTMENULOGOFF) ||
-                   GetExplorerRegValueSet(HKEY_CURRENT_USER,
-                                          TEXT("Advanced"),
-                                          TEXT("StartMenuLogoff")));
-
-    /* Favorites */
-    if (!GetExplorerRegValueSet(HKEY_CURRENT_USER,
-                                TEXT("Advanced"),
-                                TEXT("StartMenuFavorites")))
-    {
-        DeleteMenu(hMenu,
-                   IDM_FAVORITES,
-                   MF_BYCOMMAND);
-    }
-
-    /* Documents */
-    if (SHRestricted(REST_NORECENTDOCSMENU))
-    {
-        DeleteMenu(hMenu,
-                   IDM_DOCUMENTS,
-                   MF_BYCOMMAND);
-    }
-
-    /* Settings */
-    hSettingsMenu = FindSubMenu(hMenu,
-                                IDM_SETTINGS,
-                                FALSE);
-    if (hSettingsMenu != NULL)
-    {
-        if (SHRestricted(REST_NOSETFOLDERS))
-        {
-            /* Control Panel */
-            if (SHRestricted(REST_NOCONTROLPANEL))
-            {
-                DeleteMenu(hSettingsMenu,
-                           IDM_CONTROLPANEL,
-                           MF_BYCOMMAND);
-
-                /* Delete the separator below it */
-                DeleteMenu(hSettingsMenu,
-                           0,
-                           MF_BYPOSITION);
-            }
-
-            /* Network Connections */
-            if (SHRestricted(REST_NONETWORKCONNECTIONS))
-            {
-                DeleteMenu(hSettingsMenu,
-                           IDM_NETWORKCONNECTIONS,
-                           MF_BYCOMMAND);
-            }
-
-            /* Printers and Faxes */
-            DeleteMenu(hSettingsMenu,
-                       IDM_PRINTERSANDFAXES,
-                       MF_BYCOMMAND);
-        }
-
-        /* Security */
-        if (GetSystemMetrics(SM_REMOTECONTROL) == 0 ||
-            SHRestricted(REST_NOSECURITY))
-        {
-            DeleteMenu(hSettingsMenu,
-                       IDM_SECURITY,
-                       MF_BYCOMMAND);
-        }
-
-        if (GetMenuItemCount(hSettingsMenu) == 0)
-        {
-            DeleteMenu(hMenu,
-                       IDM_SETTINGS,
-                       MF_BYCOMMAND);
-        }
-    }
-
-    /* Search */
-    /* FIXME: Enable after implementing */
-    /* if (SHRestricted(REST_NOFIND)) */
-    {
-        DeleteMenu(hMenu,
-                   IDM_SEARCH,
-                   MF_BYCOMMAND);
-    }
-
-    /* FIXME: Help */
-
-    /* Run */
-    if (SHRestricted(REST_NORUN))
-    {
-        DeleteMenu(hMenu,
-                   IDM_RUN,
-                   MF_BYCOMMAND);
-    }
-
-    /* Synchronize */
-    if (!ShowSynchronizeMenuItem())
-    {
-        DeleteMenu(hMenu,
-                   IDM_SYNCHRONIZE,
-                   MF_BYCOMMAND);
-        uLastItemsCount--;
-    }
-
-    /* Log off */
-    if (dwLogoff != 1 && bWantLogoff)
-    {
-        /* FIXME: We need a more sophisticated way to determine whether to show
-                  or hide it, it might be hidden in too many cases!!! */
-
-        /* Update Log Off menu item */
-        if (!GetCurrentLoggedOnUserName(szUser,
-                                        sizeof(szUser) / sizeof(szUser[0])))
-        {
-            szUser[0] = _T('\0');
-        }
-
-        if (!FormatMenuString(hMenu,
-                              IDM_LOGOFF,
-                              MF_BYCOMMAND,
-                              szUser))
-        {
-            /* We couldn't update the menu item, delete it... */
-            DeleteMenu(hMenu,
-                       IDM_LOGOFF,
-                       MF_BYCOMMAND);
-        }
-    }
-    else
-    {
-        DeleteMenu(hMenu,
-                   IDM_LOGOFF,
-                   MF_BYCOMMAND);
-        uLastItemsCount--;
-    }
-
-
-    /* Disconnect */
-    if (GetSystemMetrics(SM_REMOTECONTROL) == 0)
-    {
-        DeleteMenu(hMenu,
-                   IDM_DISCONNECT,
-                   MF_BYCOMMAND);
-        uLastItemsCount--;
-    }
-
-    /* Undock computer */
-    if (!ShowUndockMenuItem())
-    {
-        DeleteMenu(hMenu,
-                   IDM_UNDOCKCOMPUTER,
-                   MF_BYCOMMAND);
-        uLastItemsCount--;
-    }
-
-    /* Shut down */
-    if (SHRestricted(REST_NOCLOSE))
-    {
-        DeleteMenu(hMenu,
-                   IDM_SHUTDOWN,
-                   MF_BYCOMMAND);
-        uLastItemsCount--;
-    }
-
-    if (uLastItemsCount == 0)
-    {
-        /* Remove the separator at the end of the menu */
-        DeleteMenu(hMenu,
-                   IDM_LASTSTARTMENU_SEPARATOR,
-                   MF_BYCOMMAND);
-    }
-
-    return S_OK;
-}
-
-static const ITrayPrivVtbl ITrayPrivImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(ITrayPriv, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(ITrayPriv, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(ITrayPriv, IStartMenuSite),
-    /*** IOleWindow methods ***/
-    IStartMenuSiteImpl_GetWindow,
-    IStartMenuSiteImpl_ContextSensitiveHelp,
-    /*** ITrayPriv methods ***/
-    IStartMenuSiteImpl_Execute,
-    IStartMenuSiteImpl_Unknown,
-    IStartMenuSiteImpl_AppendMenu
-};
-
-/*******************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IOleCommandTarget, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IOleCommandTarget, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IOleCommandTarget, IStartMenuSite)
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_QueryStatus(IN OUT IOleCommandTarget *iface,
-                               IN const GUID *pguidCmdGroup  OPTIONAL,
-                               IN ULONG cCmds,
-                               IN OUT OLECMD *prgCmds,
-                               IN OUT OLECMDTEXT *pCmdText  OPTIONAL)
-{
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_Exec(IN OUT IOleCommandTarget *iface,
-                        IN const GUID *pguidCmdGroup  OPTIONAL,
-                        IN DWORD nCmdID,
-                        IN DWORD nCmdExecOpt,
-                        IN VARIANTARG *pvaIn  OPTIONAL,
-                        IN VARIANTARG *pvaOut  OPTIONAL)
-{
-    return E_NOTIMPL;
-}
-
-static const IOleCommandTargetVtbl IOleCommandTargetImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IOleCommandTarget, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IOleCommandTarget, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IOleCommandTarget, IStartMenuSite),
-    /*** IOleCommandTarget ***/
-    IStartMenuSiteImpl_QueryStatus,
-    IStartMenuSiteImpl_Exec
-};
-
-/*******************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IMenuPopup, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IMenuPopup, IStartMenuSite)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IMenuPopup, IStartMenuSite)
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_IMenuPopup_GetWindow(IN OUT IMenuPopup *iface, OUT HWND *phwnd)
-{
-    IStartMenuSiteImpl * This = IStartMenuSiteImpl_from_IMenuPopup(iface);
-    ITrayPriv * tp = ITrayPriv_from_IStartMenuSiteImpl(This);
-    return IStartMenuSiteImpl_GetWindow(tp, phwnd);
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_IMenuPopup_ContextSensitiveHelp(IN OUT IMenuPopup *iface, IN BOOL fEnterMode)
-{
-    IStartMenuSiteImpl * This = IStartMenuSiteImpl_from_IMenuPopup(iface);
-    ITrayPriv * tp = ITrayPriv_from_IStartMenuSiteImpl(This);
-    return IStartMenuSiteImpl_ContextSensitiveHelp(tp, fEnterMode);
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_SetClient(IN OUT IMenuPopup *iface, IUnknown *punkClient)
-{
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_GetClient(IN OUT IMenuPopup *iface, IUnknown ** ppunkClient)
-{
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_OnPosRectChangeDB(IN OUT IMenuPopup *iface, RECT *prc)
-{
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_Popup(IN OUT IMenuPopup *iface, POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
-{
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_OnSelect(IN OUT IMenuPopup *iface, DWORD dwSelectType)
-{
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IStartMenuSiteImpl_SetSubMenu(IN OUT IMenuPopup *iface, IMenuPopup *pmp, BOOL fSet)
-{
-    if (!fSet)
-    {
-        return Tray_OnStartMenuDismissed();
-    }
-
-    return S_OK;
-}
-
-static const IMenuPopupVtbl IMenuPopupImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IMenuPopup, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IMenuPopup, IStartMenuSite),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IMenuPopup, IStartMenuSite),
-    /*** IOleWindow methods ***/
-    IStartMenuSiteImpl_IMenuPopup_GetWindow,
-    IStartMenuSiteImpl_IMenuPopup_ContextSensitiveHelp,
-    /*** IDeskBar methods ***/
-    IStartMenuSiteImpl_SetClient,
-    IStartMenuSiteImpl_GetClient,
-    IStartMenuSiteImpl_OnPosRectChangeDB,
-    /*** IMenuPopup ***/
-    IStartMenuSiteImpl_Popup,
-    IStartMenuSiteImpl_OnSelect,
-    IStartMenuSiteImpl_SetSubMenu
-};
-
-
-/*******************************************************************/
-
-static IStartMenuSiteImpl*
-IStartMenuSiteImpl_Construct(IN ITrayWindow *Tray)
-{
-    IStartMenuSiteImpl *This;
-
-    This = HeapAlloc(hProcessHeap,
-                     HEAP_ZERO_MEMORY,
-                     sizeof(*This));
-    if (This == NULL)
-        return NULL;
-
-    This->lpVtbl = &IStartMenuSiteImpl_Vtbl;
-    This->lpServiceProviderVtbl = &IServiceProviderImpl_Vtbl;
-    This->lpStartMenuCallbackVtbl = &ITrayPrivImpl_Vtbl;
-    This->lpOleCommandTargetVtbl = &IOleCommandTargetImpl_Vtbl;
-    This->lpMenuPopupVtbl = &IMenuPopupImpl_Vtbl;
-    This->Ref = 1;
-
-    This->Tray = Tray;
-
-    return This;
-}
-
-static IStartMenuSite*
-CreateStartMenuSite(IN ITrayWindow *Tray)
-{
-    IStartMenuSiteImpl *This;
-
-    This = IStartMenuSiteImpl_Construct(Tray);
-    if (This != NULL)
-    {
-        return IStartMenuSite_from_IStartMenuSiteImpl(This);
-    }
-
-    return NULL;
-}
-
-HRESULT
-UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
-                IN HBITMAP hbmBanner  OPTIONAL,
-                IN BOOL bSmallIcons)
-{
-    IBanneredBar *pbb;
-    HRESULT hRet;
-
-    hRet = IMenuPopup_QueryInterface(pMenuPopup,
-                                     &IID_IBanneredBar,
-                                     (PVOID *)&pbb);
-    if (SUCCEEDED(hRet))
-    {
-        hRet = IBanneredBar_SetBitmap(pbb, hbmBanner);
-
-        /* Update the icon size */
-        hRet = IBanneredBar_SetIconSize(pbb,
-                                        bSmallIcons ? BMICON_SMALL : BMICON_LARGE);
-
-        IBanneredBar_Release(pbb);
-    }
-
-    return hRet;
-}
-
-IMenuPopup *
-CreateStartMenu(IN ITrayWindow *Tray,
-                OUT IMenuBand **ppMenuBand,
-                IN HBITMAP hbmBanner  OPTIONAL,
-                IN BOOL bSmallIcons)
-{
-    HRESULT hr;
-    IObjectWithSite *pOws = NULL;
-    IMenuPopup *pMp = NULL;
-    IStartMenuSite *pSms = NULL;
-    IMenuBand *pMb = NULL;
-    IInitializeObject *pIo;
-    IUnknown *pUnk = NULL;
-    IBandSite *pBs = NULL;
-    DWORD dwBandId = 0;
-
-    pSms = CreateStartMenuSite(Tray);
-    if (pSms == NULL)
-        return NULL;
-
-#if 0
-    hr = CoCreateInstance(&CLSID_StartMenu,
-                          NULL,
-                          CLSCTX_INPROC_SERVER,
-                          &IID_IMenuPopup,
-                          (PVOID *)&pMp);
-#else
-    hr = CStartMenu_Constructor(&IID_IMenuPopup,(PVOID *)&pMp);
-#endif
-    if (FAILED(hr))
-    {
-        TRACE("CoCreateInstance failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    hr = IMenuPopup_QueryInterface(pMp,
-                                   &IID_IObjectWithSite,
-                                   (PVOID *)&pOws);
-    if (FAILED(hr))
-    {
-        TRACE("IMenuPopup_QueryInterface failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    /* Set the menu site so we can handle messages */
-    hr = IObjectWithSite_SetSite(pOws, (IUnknown *)pSms);
-    if (FAILED(hr))
-    {
-        TRACE("IObjectWithSite_SetSite failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    /* Initialize the menu object */
-    hr = IMenuPopup_QueryInterface(pMp, &IID_IInitializeObject, (PVOID*)&pIo);
-    if (SUCCEEDED(hr))
-    {
-        hr = IInitializeObject_Initialize(pIo);
-        IInitializeObject_Release(pIo);
-    }
-    else
-        hr = S_OK;
-
-    /* Everything is initialized now. Let's get the IMenuBand interface. */
-    if (FAILED(hr))
-    {
-        TRACE("IMenuPopup_QueryInterface failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    hr = IMenuPopup_GetClient(pMp, &pUnk);
-    if (FAILED(hr))
-    {
-        TRACE("IMenuPopup_GetClient failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    hr = IUnknown_QueryInterface(pUnk, &IID_IBandSite, (PVOID *)&pBs);
-    if (FAILED(hr))
-    {
-        TRACE("IUnknown_QueryInterface pBs failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    /* Finally we have the IBandSite interface, there's only one
-       band in it that apparently provides the IMenuBand interface */
-    hr = IBandSite_EnumBands(pBs, 0, &dwBandId);
-    if (FAILED(hr))
-    {
-        TRACE("IBandSite_EnumBands failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    hr = IBandSite_GetBandObject(pBs, dwBandId, &IID_IMenuBand, (PVOID *)&pMb);
-    if (FAILED(hr))
-    {
-        TRACE("IBandSite_GetBandObject failed: %x\n", hr);
-        goto cleanup;
-    }
-
-    UpdateStartMenu(pMp,
-                    hbmBanner,
-                    bSmallIcons);
-
-cleanup:
-    if (SUCCEEDED(hr))
-        *ppMenuBand = pMb;
-    else if (pMb != NULL)
-        IMenuBand_Release(pMb);
-
-    if (pBs != NULL)
-        IBandSite_Release(pBs);
-    if (pUnk != NULL)
-        IUnknown_Release(pUnk);
-    if (pOws != NULL)
-        IObjectWithSite_Release(pOws);
-    if (pMp != NULL)
-        IMenuPopup_Release(pMp);
-    if (pSms != NULL)
-        IStartMenuSite_Release(pSms);
-
-    if (FAILED(hr))
-        return NULL;
-    return pMp;
-}
diff --git a/base/shell/explorer-new/startmnu.cpp b/base/shell/explorer-new/startmnu.cpp
new file mode 100644 (file)
index 0000000..950a330
--- /dev/null
@@ -0,0 +1,796 @@
+/*
+ * ReactOS Explorer
+ *
+ * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "precomp.h"
+
+/*
+ * Start menu button context menu
+ */
+
+typedef struct _STARTMNU_CTMENU_CTX
+{
+    IContextMenu *pcm;
+    LPITEMIDLIST pidl;
+} STARTMNU_CTMENU_CTX, *PSTARTMNU_CTMENU_CTX;
+
+static HMENU
+CreateStartContextMenu(IN HWND hWndOwner,
+                       IN PVOID *ppcmContext,
+                       IN PVOID Context  OPTIONAL);
+
+static VOID
+OnStartContextMenuCommand(IN HWND hWndOwner,
+                          IN UINT uiCmdId,
+                          IN PVOID pcmContext  OPTIONAL,
+                          IN PVOID Context  OPTIONAL);
+
+const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu = {
+    CreateStartContextMenu,
+    OnStartContextMenuCommand
+};
+
+static HMENU
+CreateContextMenuFromShellFolderPidl(IN HWND hWndOwner,
+                                     IN OUT IShellFolder *psf,
+                                     IN OUT LPITEMIDLIST pidl,
+                                     OUT IContextMenu **ppcm)
+{
+    CComPtr<IContextMenu> pcm;
+    HRESULT hRet;
+    HMENU hPopup;
+
+    hRet = psf->GetUIObjectOf(hWndOwner, 1, (LPCITEMIDLIST *)&pidl, IID_NULL_PPV_ARG(IContextMenu, &pcm));
+    if (SUCCEEDED(hRet))
+    {
+        hPopup = CreatePopupMenu();
+
+        if (hPopup != NULL)
+        {
+            hRet = pcm->QueryContextMenu(
+                                                 hPopup,
+                                                 0,
+                                                 ID_SHELL_CMD_FIRST,
+                                                 ID_SHELL_CMD_LAST,
+                                                 CMF_VERBSONLY);
+
+            if (SUCCEEDED(hRet))
+            {
+                *ppcm = pcm;
+                return hPopup;
+            }
+
+            DestroyMenu(hPopup);
+        }
+    }
+
+    return NULL;
+}
+
+static VOID
+OnStartContextMenuCommand(IN HWND hWndOwner,
+                          IN UINT uiCmdId,
+                          IN PVOID pcmContext  OPTIONAL,
+                          IN PVOID Context  OPTIONAL)
+{
+    PSTARTMNU_CTMENU_CTX psmcmc = (PSTARTMNU_CTMENU_CTX) pcmContext;
+
+    if (uiCmdId != 0)
+    {
+        if ((uiCmdId >= ID_SHELL_CMD_FIRST) && (uiCmdId <= ID_SHELL_CMD_LAST))
+        {
+            CMINVOKECOMMANDINFO cmici = {0};
+            CHAR szDir[MAX_PATH];
+
+            /* Setup and invoke the shell command */
+            cmici.cbSize = sizeof(cmici);
+            cmici.hwnd = hWndOwner;
+            cmici.lpVerb = (LPCSTR)MAKEINTRESOURCE(uiCmdId - ID_SHELL_CMD_FIRST);
+            cmici.nShow = SW_NORMAL;
+
+            /* FIXME: Support Unicode!!! */
+            if (SHGetPathFromIDListA(psmcmc->pidl,
+                                     szDir))
+            {
+                cmici.lpDirectory = szDir;
+            }
+
+            psmcmc->pcm->InvokeCommand(&cmici);
+        }
+        else
+        {
+            ITrayWindow * TrayWnd = (ITrayWindow *) Context;
+            TrayWnd->ExecContextMenuCmd(uiCmdId);
+        }
+    }
+
+    psmcmc->pcm->Release();
+
+    HeapFree(hProcessHeap, 0, psmcmc);
+}
+
+static VOID
+AddStartContextMenuItems(IN HWND hWndOwner,
+                         IN HMENU hPopup)
+{
+    WCHAR szBuf[MAX_PATH];
+    HRESULT hRet;
+
+    /* Add the "Open All Users" menu item */
+    if (LoadString(hExplorerInstance,
+                   IDS_PROPERTIES,
+                   szBuf,
+                   sizeof(szBuf) / sizeof(szBuf[0])))
+    {
+        AppendMenu(hPopup,
+                   MF_STRING,
+                   ID_SHELL_CMD_PROPERTIES,
+                   szBuf);
+    }
+
+    if (!SHRestricted(REST_NOCOMMONGROUPS))
+    {
+        /* Check if we should add menu items for the common start menu */
+        hRet = SHGetFolderPath(hWndOwner,
+                               CSIDL_COMMON_STARTMENU,
+                               NULL,
+                               SHGFP_TYPE_CURRENT,
+                               szBuf);
+        if (SUCCEEDED(hRet) && hRet != S_FALSE)
+        {
+            /* The directory exists, but only show the items if the
+               user can actually make any changes to the common start
+               menu. This is most likely only the case if the user
+               has administrative rights! */
+            if (IsUserAnAdmin())
+            {
+                AppendMenu(hPopup,
+                           MF_SEPARATOR,
+                           0,
+                           NULL);
+
+                /* Add the "Open All Users" menu item */
+                if (LoadString(hExplorerInstance,
+                               IDS_OPEN_ALL_USERS,
+                               szBuf,
+                               sizeof(szBuf) / sizeof(szBuf[0])))
+                {
+                    AppendMenu(hPopup,
+                               MF_STRING,
+                               ID_SHELL_CMD_OPEN_ALL_USERS,
+                               szBuf);
+                }
+
+                /* Add the "Explore All Users" menu item */
+                if (LoadString(hExplorerInstance,
+                               IDS_EXPLORE_ALL_USERS,
+                               szBuf,
+                               sizeof(szBuf) / sizeof(szBuf[0])))
+                {
+                    AppendMenu(hPopup,
+                               MF_STRING,
+                               ID_SHELL_CMD_EXPLORE_ALL_USERS,
+                               szBuf);
+                }
+            }
+        }
+    }
+}
+
+static HMENU
+CreateStartContextMenu(IN HWND hWndOwner,
+                       IN PVOID *ppcmContext,
+                       IN PVOID Context  OPTIONAL)
+{
+    LPITEMIDLIST pidlStart, pidlLast;
+    CComPtr<IShellFolder> psfStart;
+    CComPtr<IShellFolder> psfDesktop;
+    CComPtr<IContextMenu> pcm;
+    HRESULT hRet;
+    HMENU hPopup;
+
+    pidlStart = SHCloneSpecialIDList(hWndOwner,
+                                     CSIDL_STARTMENU,
+                                     TRUE);
+
+    if (pidlStart != NULL)
+    {
+        pidlLast = ILClone(ILFindLastID(pidlStart));
+        ILRemoveLastID(pidlStart);
+
+        if (pidlLast != NULL)
+        {
+            hRet = SHGetDesktopFolder(&psfDesktop);
+            if (SUCCEEDED(hRet))
+            {
+                hRet = psfDesktop->BindToObject(pidlStart, NULL, IID_PPV_ARG(IShellFolder, &psfStart));
+                if (SUCCEEDED(hRet))
+                {
+                    hPopup = CreateContextMenuFromShellFolderPidl(hWndOwner,
+                                                                  psfStart,
+                                                                  pidlLast,
+                                                                  &pcm);
+
+                    if (hPopup != NULL)
+                    {
+                        PSTARTMNU_CTMENU_CTX psmcmc;
+
+                        psmcmc = (PSTARTMNU_CTMENU_CTX) HeapAlloc(hProcessHeap, 0, sizeof(*psmcmc));
+                        if (psmcmc != NULL)
+                        {
+                            psmcmc->pcm = pcm;
+                            psmcmc->pidl = pidlLast;
+
+                            AddStartContextMenuItems(hWndOwner,
+                                                     hPopup);
+
+                            *ppcmContext = psmcmc;
+                            return hPopup;
+                        }
+                        else
+                        {
+                            DestroyMenu(hPopup);
+                            hPopup = NULL;
+                        }
+                    }
+                }
+            }
+
+            ILFree(pidlLast);
+        }
+
+        ILFree(pidlStart);
+    }
+
+    return NULL;
+}
+
+/*****************************************************************************
+ ** IStartMenuSite ***********************************************************
+ *****************************************************************************/
+
+class IStartMenuSiteImpl :
+    public CComCoClass<IStartMenuSiteImpl>,
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IStartMenuSite,
+    public IServiceProvider,
+    public ITrayPriv,
+    public IOleCommandTarget,
+    public IMenuPopup
+{
+    CComPtr<ITrayWindow> Tray;
+    CComPtr<IMenuPopup> StartMenuPopup;
+
+public:
+    IStartMenuSiteImpl()
+    {
+    }
+
+    virtual ~IStartMenuSiteImpl() { }
+
+    /*******************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE QueryService(
+        IN REFGUID guidService,
+        IN REFIID riid,
+        OUT PVOID *ppvObject)
+    {
+        if (IsEqualGUID(guidService, SID_SMenuPopup))
+        {
+            return QueryInterface(riid, ppvObject);
+        }
+
+        return E_NOINTERFACE;
+    }
+
+    /*******************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE GetWindow(
+        OUT HWND *phwnd)
+    {
+        TRACE("ITrayPriv::GetWindow\n");
+
+        *phwnd = Tray->GetHWND();
+        if (*phwnd != NULL)
+            return S_OK;
+
+        return E_FAIL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
+        IN BOOL fEnterMode)
+    {
+        TRACE("ITrayPriv::ContextSensitiveHelp\n");
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Execute(
+        IN IShellFolder *pShellFolder,
+        IN LPCITEMIDLIST pidl)
+    {
+        HMODULE hShlwapi;
+        HRESULT ret = S_FALSE;
+
+        TRACE("ITrayPriv::Execute\n");
+
+        hShlwapi = GetModuleHandle(TEXT("SHLWAPI.DLL"));
+        if (hShlwapi != NULL)
+        {
+            SHINVDEFCMD SHInvokeDefCmd;
+
+            /* SHInvokeDefaultCommand */
+            SHInvokeDefCmd = (SHINVDEFCMD) GetProcAddress(hShlwapi,
+                (LPCSTR) ((LONG) 279));
+            if (SHInvokeDefCmd != NULL)
+            {
+                ret = SHInvokeDefCmd(Tray->GetHWND(),
+                    pShellFolder,
+                    pidl);
+            }
+        }
+
+        return ret;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Unknown(
+        IN PVOID Unknown1,
+        IN PVOID Unknown2,
+        IN PVOID Unknown3,
+        IN PVOID Unknown4)
+    {
+        TRACE("ITrayPriv::Unknown(0x%p,0x%p,0x%p,0x%p)\n", Unknown1, Unknown2, Unknown3, Unknown4);
+        return E_NOTIMPL;
+    }
+
+    virtual BOOL
+        ShowUndockMenuItem(VOID)
+    {
+        TRACE("ShowUndockMenuItem() not implemented!\n");
+        /* FIXME: How do we detect this?! */
+        return FALSE;
+    }
+
+    virtual BOOL
+        ShowSynchronizeMenuItem(VOID)
+    {
+        TRACE("ShowSynchronizeMenuItem() not implemented!\n");
+        /* FIXME: How do we detect this?! */
+        return FALSE;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE AppendMenu(
+        OUT HMENU* phMenu)
+    {
+        HMENU hMenu, hSettingsMenu;
+        DWORD dwLogoff;
+        BOOL bWantLogoff;
+        UINT uLastItemsCount = 5; /* 5 menu items below the last separator */
+        WCHAR szUser[128];
+
+        TRACE("ITrayPriv::AppendMenu\n");
+
+        hMenu = LoadPopupMenu(hExplorerInstance,
+            MAKEINTRESOURCE(IDM_STARTMENU));
+        *phMenu = hMenu;
+        if (hMenu == NULL)
+            return E_FAIL;
+
+        /* Remove menu items that don't apply */
+
+        dwLogoff = SHRestricted(REST_STARTMENULOGOFF);
+        bWantLogoff = (dwLogoff == 2 ||
+            SHRestricted(REST_FORCESTARTMENULOGOFF) ||
+            GetExplorerRegValueSet(HKEY_CURRENT_USER,
+            TEXT("Advanced"),
+            TEXT("StartMenuLogoff")));
+
+        /* Favorites */
+        if (!GetExplorerRegValueSet(HKEY_CURRENT_USER,
+            TEXT("Advanced"),
+            TEXT("StartMenuFavorites")))
+        {
+            DeleteMenu(hMenu,
+                IDM_FAVORITES,
+                MF_BYCOMMAND);
+        }
+
+        /* Documents */
+        if (SHRestricted(REST_NORECENTDOCSMENU))
+        {
+            DeleteMenu(hMenu,
+                IDM_DOCUMENTS,
+                MF_BYCOMMAND);
+        }
+
+        /* Settings */
+        hSettingsMenu = FindSubMenu(hMenu,
+            IDM_SETTINGS,
+            FALSE);
+        if (hSettingsMenu != NULL)
+        {
+            if (SHRestricted(REST_NOSETFOLDERS))
+            {
+                /* Control Panel */
+                if (SHRestricted(REST_NOCONTROLPANEL))
+                {
+                    DeleteMenu(hSettingsMenu,
+                        IDM_CONTROLPANEL,
+                        MF_BYCOMMAND);
+
+                    /* Delete the separator below it */
+                    DeleteMenu(hSettingsMenu,
+                        0,
+                        MF_BYPOSITION);
+                }
+
+                /* Network Connections */
+                if (SHRestricted(REST_NONETWORKCONNECTIONS))
+                {
+                    DeleteMenu(hSettingsMenu,
+                        IDM_NETWORKCONNECTIONS,
+                        MF_BYCOMMAND);
+                }
+
+                /* Printers and Faxes */
+                DeleteMenu(hSettingsMenu,
+                    IDM_PRINTERSANDFAXES,
+                    MF_BYCOMMAND);
+            }
+
+            /* Security */
+            if (GetSystemMetrics(SM_REMOTECONTROL) == 0 ||
+                SHRestricted(REST_NOSECURITY))
+            {
+                DeleteMenu(hSettingsMenu,
+                    IDM_SECURITY,
+                    MF_BYCOMMAND);
+            }
+
+            if (GetMenuItemCount(hSettingsMenu) == 0)
+            {
+                DeleteMenu(hMenu,
+                    IDM_SETTINGS,
+                    MF_BYCOMMAND);
+            }
+        }
+
+        /* Search */
+        /* FIXME: Enable after implementing */
+        /* if (SHRestricted(REST_NOFIND)) */
+    {
+        DeleteMenu(hMenu,
+            IDM_SEARCH,
+            MF_BYCOMMAND);
+    }
+
+        /* FIXME: Help */
+
+        /* Run */
+        if (SHRestricted(REST_NORUN))
+        {
+            DeleteMenu(hMenu,
+                IDM_RUN,
+                MF_BYCOMMAND);
+        }
+
+        /* Synchronize */
+        if (!ShowSynchronizeMenuItem())
+        {
+            DeleteMenu(hMenu,
+                IDM_SYNCHRONIZE,
+                MF_BYCOMMAND);
+            uLastItemsCount--;
+        }
+
+        /* Log off */
+        if (dwLogoff != 1 && bWantLogoff)
+        {
+            /* FIXME: We need a more sophisticated way to determine whether to show
+                      or hide it, it might be hidden in too many cases!!! */
+
+            /* Update Log Off menu item */
+            if (!GetCurrentLoggedOnUserName(szUser,
+                sizeof(szUser) / sizeof(szUser[0])))
+            {
+                szUser[0] = _T('\0');
+            }
+
+            if (!FormatMenuString(hMenu,
+                IDM_LOGOFF,
+                MF_BYCOMMAND,
+                szUser))
+            {
+                /* We couldn't update the menu item, delete it... */
+                DeleteMenu(hMenu,
+                    IDM_LOGOFF,
+                    MF_BYCOMMAND);
+            }
+        }
+        else
+        {
+            DeleteMenu(hMenu,
+                IDM_LOGOFF,
+                MF_BYCOMMAND);
+            uLastItemsCount--;
+        }
+
+
+        /* Disconnect */
+        if (GetSystemMetrics(SM_REMOTECONTROL) == 0)
+        {
+            DeleteMenu(hMenu,
+                IDM_DISCONNECT,
+                MF_BYCOMMAND);
+            uLastItemsCount--;
+        }
+
+        /* Undock computer */
+        if (!ShowUndockMenuItem())
+        {
+            DeleteMenu(hMenu,
+                IDM_UNDOCKCOMPUTER,
+                MF_BYCOMMAND);
+            uLastItemsCount--;
+        }
+
+        /* Shut down */
+        if (SHRestricted(REST_NOCLOSE))
+        {
+            DeleteMenu(hMenu,
+                IDM_SHUTDOWN,
+                MF_BYCOMMAND);
+            uLastItemsCount--;
+        }
+
+        if (uLastItemsCount == 0)
+        {
+            /* Remove the separator at the end of the menu */
+            DeleteMenu(hMenu,
+                IDM_LASTSTARTMENU_SEPARATOR,
+                MF_BYCOMMAND);
+        }
+
+        return S_OK;
+    }
+
+    /*******************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE QueryStatus(
+        IN const GUID *pguidCmdGroup  OPTIONAL,
+        IN ULONG cCmds,
+        IN OUT OLECMD *prgCmds,
+        IN OUT OLECMDTEXT *pCmdText  OPTIONAL)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Exec(
+        IN const GUID *pguidCmdGroup  OPTIONAL,
+        IN DWORD nCmdID,
+        IN DWORD nCmdExecOpt,
+        IN VARIANTARG *pvaIn  OPTIONAL,
+        IN VARIANTARG *pvaOut  OPTIONAL)
+    {
+        return E_NOTIMPL;
+    }
+
+    /*******************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE SetClient(IUnknown *punkClient)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetClient(IUnknown ** ppunkClient)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(RECT *prc)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Popup(POINTL *ppt, RECTL *prcExclude, MP_POPUPFLAGS dwFlags)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE OnSelect(DWORD dwSelectType)
+    {
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE SetSubMenu(IMenuPopup *pmp, BOOL fSet)
+    {
+        if (!fSet)
+        {
+            return Tray_OnStartMenuDismissed();
+        }
+
+        return S_OK;
+    }
+
+    /*******************************************************************/
+
+    HRESULT Initialize(IN ITrayWindow *tray)
+    {
+        Tray = tray;
+        return S_OK;
+    }
+
+    DECLARE_NOT_AGGREGATABLE(IStartMenuSiteImpl)
+
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+    BEGIN_COM_MAP(IStartMenuSiteImpl)
+        COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
+        COM_INTERFACE_ENTRY_IID(IID_ITrayPriv, ITrayPriv)
+        COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
+        COM_INTERFACE_ENTRY_IID(IID_IMenuPopup, IMenuPopup)
+        COM_INTERFACE_ENTRY_IID(IID_IOleWindow, IOleWindow)
+    END_COM_MAP()
+};
+
+HRESULT CreateStartMenuSite(IN OUT ITrayWindow *Tray, const IID & riid, PVOID * ppv)
+{
+    return ShellObjectCreatorInit<IStartMenuSiteImpl>(Tray, riid, ppv);
+}
+
+HRESULT
+UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
+                IN HBITMAP hbmBanner  OPTIONAL,
+                IN BOOL bSmallIcons)
+{
+    CComPtr<IBanneredBar> pbb;
+    HRESULT hRet;
+
+    hRet = pMenuPopup->QueryInterface(IID_PPV_ARG(IBanneredBar, &pbb));
+    if (SUCCEEDED(hRet))
+    {
+        hRet = pbb->SetBitmap( hbmBanner);
+
+        /* Update the icon size */
+        hRet = pbb->SetIconSize(bSmallIcons ? BMICON_SMALL : BMICON_LARGE);
+    }
+
+    return hRet;
+}
+
+IMenuPopup *
+CreateStartMenu(IN ITrayWindow *Tray,
+                OUT IMenuBand **ppMenuBand,
+                IN HBITMAP hbmBanner  OPTIONAL,
+                IN BOOL bSmallIcons)
+{
+    HRESULT hr;
+    IObjectWithSite *pOws = NULL;
+    IMenuPopup *pMp = NULL;
+    IUnknown *pSms = NULL;
+    IMenuBand *pMb = NULL;
+    IInitializeObject *pIo;
+    IUnknown *pUnk = NULL;
+    IBandSite *pBs = NULL;
+    DWORD dwBandId = 0;
+
+    hr = CreateStartMenuSite(Tray, IID_PPV_ARG(IUnknown, &pSms));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return NULL;
+
+#if 0
+    hr = CoCreateInstance(&CLSID_StartMenu,
+                          NULL,
+                          CLSCTX_INPROC_SERVER,
+                          &IID_IMenuPopup,
+                          (PVOID *)&pMp);
+#else
+    hr = _CStartMenu_Constructor(IID_PPV_ARG(IMenuPopup, &pMp));
+#endif
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("CoCreateInstance failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    hr = pMp->QueryInterface(IID_PPV_ARG(IObjectWithSite, &pOws));
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("IMenuPopup_QueryInterface failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    /* Set the menu site so we can handle messages */
+    hr = pOws->SetSite(pSms);
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("IObjectWithSite_SetSite failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    /* Initialize the menu object */
+    hr = pMp->QueryInterface(IID_PPV_ARG(IInitializeObject, &pIo));
+    if (SUCCEEDED(hr))
+    {
+        hr = pIo->Initialize();
+        pIo->Release();
+    }
+    else
+        hr = S_OK;
+
+    /* Everything is initialized now. Let's get the IMenuBand interface. */
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("IMenuPopup_QueryInterface failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    hr = pMp->GetClient( &pUnk);
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("IMenuPopup_GetClient failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    hr = pUnk->QueryInterface(IID_PPV_ARG(IBandSite, &pBs));
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("IUnknown_QueryInterface pBs failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    /* Finally we have the IBandSite interface, there's only one
+       band in it that apparently provides the IMenuBand interface */
+    hr = pBs->EnumBands( 0, &dwBandId);
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("IBandSite_EnumBands failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    hr = pBs->GetBandObject( dwBandId, IID_PPV_ARG(IMenuBand, &pMb));
+    if (FAILED_UNEXPECTEDLY(hr))
+    {
+        TRACE("IBandSite_GetBandObject failed: %x\n", hr);
+        goto cleanup;
+    }
+
+    UpdateStartMenu(pMp,
+                    hbmBanner,
+                    bSmallIcons);
+
+cleanup:
+    if (SUCCEEDED(hr))
+        *ppMenuBand = pMb;
+    else if (pMb != NULL)
+        pMb->Release();
+
+    if (pBs != NULL)
+        pBs->Release();
+    if (pUnk != NULL)
+        pUnk->Release();
+    if (pOws != NULL)
+        pOws->Release();
+    if (pMp != NULL)
+        pMp->Release();
+    if (pSms != NULL)
+        pSms->Release();
+
+    if (FAILED_UNEXPECTEDLY(hr))
+        return NULL;
+    return pMp;
+}
similarity index 99%
rename from base/shell/explorer-new/startup.c
rename to base/shell/explorer-new/startup.cpp
index 4de2ef3..d1ae7ee 100644 (file)
@@ -176,7 +176,7 @@ static BOOL ProcessRunKeys(HKEY hkRoot, LPCWSTR szKeyName, BOOL bDelete,
         goto end;
     }
 
-    szCmdLine = HeapAlloc(hProcessHeap,
+    szCmdLine = (WCHAR*)HeapAlloc(hProcessHeap,
                           0,
                           cbMaxCmdLine);
     if (szCmdLine == NULL)
@@ -188,7 +188,7 @@ static BOOL ProcessRunKeys(HKEY hkRoot, LPCWSTR szKeyName, BOOL bDelete,
     }
 
     ++cchMaxValue;
-    szValue = HeapAlloc(hProcessHeap,
+    szValue = (WCHAR*)HeapAlloc(hProcessHeap,
                         0,
                         cchMaxValue * sizeof(*szValue));
     if (szValue == NULL)
diff --git a/base/shell/explorer-new/taskband.c b/base/shell/explorer-new/taskband.c
deleted file mode 100644 (file)
index 299a7fa..0000000
+++ /dev/null
@@ -1,660 +0,0 @@
-/*
- * ReactOS Explorer
- *
- * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "precomp.h"
-
-/*****************************************************************************
- ** ITaskBand ****************************************************************
- *****************************************************************************/
-
-const GUID CLSID_ITaskBand = {0x68284FAA,0x6A48,0x11D0,{0x8C,0x78,0x00,0xC0,0x4F,0xD9,0x18,0xB4}};
-
-static const ITaskBandVtbl ITaskBandImpl_Vtbl;
-static const IDeskBandVtbl IDeskBandImpl_Vtbl;
-static const IObjectWithSiteVtbl IObjectWithSiteImpl_Vtbl;
-static const IDeskBarVtbl IDeskBarImpl_Vtbl;
-static const IPersistStreamVtbl IPersistStreamImpl_Vtbl;
-static const IWinEventHandlerVtbl IWinEventHandlerImpl_Vtbl;
-
-typedef struct
-{
-    const ITaskBandVtbl *lpVtbl;
-    const IDeskBandVtbl *lpDeskBandVtbl;
-    const IObjectWithSiteVtbl *lpObjectWithSiteVtbl;
-    const IDeskBarVtbl *lpDeskBarVtbl;
-    const IPersistStreamVtbl *lpPersistStreamVtbl;
-    const IWinEventHandlerVtbl *lpWindowEventHandlerVtbl;
-    /* FIXME: Implement IOleCommandTarget */
-    LONG Ref;
-
-    ITrayWindow *Tray;
-    IUnknown *punkSite;
-
-    HWND hWnd;
-    DWORD dwBandID;
-} ITaskBandImpl;
-
-static IUnknown *
-IUnknown_from_ITaskBandImpl(ITaskBandImpl *This)
-{
-    return (IUnknown *)&This->lpVtbl;
-}
-
-IMPL_CASTS(ITaskBand, ITaskBand, lpVtbl)
-IMPL_CASTS(IDeskBand, ITaskBand, lpDeskBandVtbl)
-IMPL_CASTS(IObjectWithSite, ITaskBand, lpObjectWithSiteVtbl)
-IMPL_CASTS(IDeskBar, ITaskBand, lpDeskBarVtbl)
-IMPL_CASTS(IPersistStream, ITaskBand, lpPersistStreamVtbl)
-IMPL_CASTS(IWinEventHandler, ITaskBand, lpWindowEventHandlerVtbl)
-
-static ULONG STDMETHODCALLTYPE
-ITaskBandImpl_AddRef(IN OUT ITaskBand *iface)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_ITaskBand(iface);
-
-    return InterlockedIncrement(&This->Ref);
-}
-
-static VOID
-ITaskBandImpl_Free(IN OUT ITaskBandImpl *This)
-{
-    if (This->punkSite != NULL)
-    {
-        IUnknown_Release(This->punkSite);
-        This->punkSite = NULL;
-    }
-
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-static ULONG STDMETHODCALLTYPE
-ITaskBandImpl_Release(IN OUT ITaskBand *iface)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_ITaskBand(iface);
-    ULONG Ret;
-
-    Ret = InterlockedDecrement(&This->Ref);
-
-    if (Ret == 0)
-        ITaskBandImpl_Free(This);
-
-    return Ret;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_QueryInterface(IN OUT ITaskBand *iface,
-                             IN REFIID riid,
-                             OUT LPVOID *ppvObj)
-{
-    ITaskBandImpl *This;
-
-    if (ppvObj == NULL)
-        return E_POINTER;
-
-    This = ITaskBandImpl_from_ITaskBand(iface);
-
-    if (IsEqualIID(riid,
-                   &IID_IUnknown))
-    {
-        *ppvObj = IUnknown_from_ITaskBandImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IDeskBand) ||
-             IsEqualIID(riid,
-                        &IID_IOleWindow) ||
-             IsEqualIID(riid,
-                        &IID_IDockingWindow))
-    {
-        *ppvObj = IDeskBand_from_ITaskBandImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IObjectWithSite))
-    {
-        *ppvObj = IObjectWithSite_from_ITaskBandImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IDeskBar))
-    {
-        *ppvObj = IDeskBar_from_ITaskBandImpl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IWinEventHandler))
-    {
-        /* When run on Windows the system queries this interface, which is completely
-           undocumented :( It's queried during initialization of the tray band site.
-           The system apparently uses this interface to forward messages to be handled
-           by the band child window. This interface appears to be implemented by a number
-           of classes provided by the shell, including the IBandSite interface. In that
-           we (the host application) forward messages to the default message handler (in
-           our case the IBandSite default message handler for the Rebar control)! This
-           interface in the ITaskBand implementation is only actually used if we use
-           the same interface to forward messages to the IBandSite implementation of
-           the shell! */
-        *ppvObj = IWinEventHandler_from_ITaskBandImpl(This);
-    }
-#if 0
-    else if (IsEqualIID(riid,
-                        &IID_IPersistStream) ||
-             IsEqualIID(riid,
-                        &IID_IPersist))
-    {
-        *ppvObj = IPersistStream_from_ITaskBandImpl(This);
-    }
-#endif
-    else
-    {
-        *ppvObj = NULL;
-        return E_NOINTERFACE;
-    }
-
-    ITaskBandImpl_AddRef(iface);
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_GetRebarBandID(IN OUT ITaskBand *iface,
-                             OUT DWORD *pdwBandID)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_ITaskBand(iface);
-
-    if (This->dwBandID != (DWORD)-1)
-    {
-        if (pdwBandID != NULL)
-            *pdwBandID = This->dwBandID;
-
-        return S_OK;
-    }
-
-    return E_FAIL;
-}
-
-static const ITaskBandVtbl ITaskBandImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    ITaskBandImpl_QueryInterface,
-    ITaskBandImpl_AddRef,
-    ITaskBandImpl_Release,
-    /*** ITaskBand methods ***/
-    ITaskBandImpl_GetRebarBandID
-};
-
-/*****************************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IDeskBand, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IDeskBand, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IDeskBand, ITaskBand)
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_GetWindow(IN OUT IDeskBand *iface,
-                        OUT HWND *phwnd)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_IDeskBand(iface);
-
-    /* NOTE: We have to return the tray window here so that ITaskBarClient
-             knows the parent window of the Rebar control it creates when
-             calling ITaskBarClient::SetDeskBarSite()! However, once we
-             created a window we return the task switch window! */
-    if (This->hWnd != NULL)
-        *phwnd = This->hWnd;
-    else
-        *phwnd = ITrayWindow_GetHWND(This->Tray);
-
-    TRACE("ITaskBand::GetWindow(0x%p->0x%p)\n", phwnd, *phwnd);
-
-    if (*phwnd != NULL)
-        return S_OK;
-
-    return E_FAIL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_ContextSensitiveHelp(IN OUT IDeskBand *iface,
-                                   IN BOOL fEnterMode)
-{
-    /* FIXME: Implement */
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_ShowDW(IN OUT IDeskBand *iface,
-                     IN BOOL bShow)
-{
-    /* We don't do anything... */
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_CloseDW(IN OUT IDeskBand *iface,
-                      IN DWORD dwReserved)
-{
-    /* We don't do anything... */
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_ResizeBoderDW(IN OUT IDeskBand *iface,
-                            IN LPCRECT prcBorder,
-                            IN IUnknown *punkToolbarSite,
-                            IN BOOL fReserved)
-{
-    /* No need to implement this method */
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_GetBandInfo(IN OUT IDeskBand *iface,
-                          IN DWORD dwBandID,
-                          IN DWORD dwViewMode,
-                          IN OUT DESKBANDINFO *pdbi)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_IDeskBand(iface);
-    TRACE("ITaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, This->hWnd);
-
-    /* NOTE: We could save dwBandID in the instance in case we need it later... */
-
-    if (This->hWnd != NULL)
-    {
-        /* The task band never has a title */
-        pdbi->dwMask &= ~DBIM_TITLE;
-
-        /* NOTE: We don't return DBIMF_UNDELETEABLE here, the band site will
-                 handle us differently and add this flag for us. The reason for
-                 this is future changes that might allow it to be deletable.
-                 We want the band site to be in charge of this decision rather
-                 the band itself! */
-        /* FIXME: What about DBIMF_NOGRIPPER and DBIMF_ALWAYSGRIPPER */
-        pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT;
-
-        if (dwViewMode & DBIF_VIEWMODE_VERTICAL)
-        {
-            pdbi->ptIntegral.y = 1;
-            pdbi->ptMinSize.y = 1;
-            /* FIXME: Get the button metrics from the task bar object!!! */
-            pdbi->ptMinSize.x = (3 * GetSystemMetrics(SM_CXEDGE) / 2) + /* FIXME: Might be wrong if only one column! */
-                                GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); /* FIXME: Min button size, query!!! */
-        }
-        else
-        {
-            pdbi->ptMinSize.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); /* FIXME: Query */
-            pdbi->ptIntegral.y = pdbi->ptMinSize.y + (3 * GetSystemMetrics(SM_CYEDGE) / 2); /* FIXME: Query metrics */
-            /* We're not going to allow task bands where not even the minimum button size fits into the band */
-            pdbi->ptMinSize.x = pdbi->ptIntegral.y;
-        }
-
-        /* Ignored: pdbi->ptMaxSize.x */
-        pdbi->ptMaxSize.y = -1;
-
-        /* FIXME: We should query the height from the task bar object!!! */
-        pdbi->ptActual.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
-
-        /* Save the band ID for future use in case we need to check whether a given band
-           is the task band */
-        This->dwBandID = dwBandID;
-
-        TRACE("H: %d, Min: %d,%d, Integral.y: %d Actual: %d,%d\n", (dwViewMode & DBIF_VIEWMODE_VERTICAL) == 0,
-                                                        pdbi->ptMinSize.x, pdbi->ptMinSize.y, pdbi->ptIntegral.y,
-                                                        pdbi->ptActual.x,pdbi->ptActual.y);
-
-        return S_OK;
-    }
-
-    return E_FAIL;
-}
-
-static const IDeskBandVtbl IDeskBandImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IDeskBand, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IDeskBand, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IDeskBand, ITaskBand),
-    /*** IOleWindow methods ***/
-    ITaskBandImpl_GetWindow,
-    ITaskBandImpl_ContextSensitiveHelp,
-    /*** IDockingWindow methods ***/
-    ITaskBandImpl_ShowDW,
-    ITaskBandImpl_CloseDW,
-    ITaskBandImpl_ResizeBoderDW,
-    /*** IDeskBand methods ***/
-    ITaskBandImpl_GetBandInfo
-};
-
-/*****************************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IDeskBar, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IDeskBar, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IDeskBar, ITaskBand)
-
-static HRESULT STDMETHODCALLTYPE
-IDeskBarImpl_GetWindow(IN OUT IDeskBar *iface,
-                       OUT HWND *phwnd)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_IDeskBar(iface);
-    IDeskBand *DeskBand = IDeskBand_from_ITaskBandImpl(This);
-
-    /* Proxy to IDeskBand interface */
-    return IDeskBand_GetWindow(DeskBand,
-                               phwnd);
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDeskBarImpl_ContextSensitiveHelp(IN OUT IDeskBar *iface,
-                                  IN BOOL fEnterMode)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_IDeskBar(iface);
-    IDeskBand *DeskBand = IDeskBand_from_ITaskBandImpl(This);
-
-    /* Proxy to IDeskBand interface */
-    return IDeskBand_ContextSensitiveHelp(DeskBand,
-                                          fEnterMode);
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDeskBarImpl_SetClient(IN OUT IDeskBar *iface,
-                       IN IUnknown *punkClient)
-{
-    TRACE("IDeskBar::SetClient(0x%p)\n", punkClient);
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDeskBarImpl_GetClient(IN OUT IDeskBar *iface,
-                       OUT IUnknown **ppunkClient)
-{
-    TRACE("IDeskBar::GetClient(0x%p)\n", ppunkClient);
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IDeskBarImpl_OnPosRectChangeDB(IN OUT IDeskBar *iface,
-                               IN RECT *prc)
-{
-    TRACE("IDeskBar::OnPosRectChangeDB(0x%p=(%d,%d,%d,%d))\n", prc, prc->left, prc->top, prc->right, prc->bottom);
-    if (prc->bottom - prc->top == 0)
-        return S_OK;
-
-    return S_FALSE;
-}
-
-static const IDeskBarVtbl IDeskBarImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IDeskBar, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IDeskBar, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IDeskBar, ITaskBand),
-    /*** IOleWindow methods ***/
-    IDeskBarImpl_GetWindow,
-    IDeskBarImpl_ContextSensitiveHelp,
-    /*** IDeskBar methods ***/
-    IDeskBarImpl_SetClient,
-    IDeskBarImpl_GetClient,
-    IDeskBarImpl_OnPosRectChangeDB
-};
-
-/*****************************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IPersistStream, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IPersistStream, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IPersistStream, ITaskBand)
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_GetClassID(IN OUT IPersistStream *iface,
-                         OUT CLSID *pClassID)
-{
-    TRACE("ITaskBand::GetClassID(0x%p)\n", pClassID);
-    /* We're going to return the (internal!) CLSID of the task band interface */
-    *pClassID = CLSID_ITaskBand;
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_IsDirty(IN OUT IPersistStream *iface)
-{
-    /* The object hasn't changed since the last save! */
-    return S_FALSE;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_Load(IN OUT IPersistStream *iface,
-                   IN IStream *pStm)
-{
-    TRACE("ITaskBand::Load called\n");
-    /* Nothing to do */
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_Save(IN OUT IPersistStream *iface,
-                   IN IStream *pStm,
-                   IN BOOL fClearDirty)
-{
-    /* Nothing to do */
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_GetSizeMax(IN OUT IPersistStream *iface,
-                         OUT ULARGE_INTEGER *pcbSize)
-{
-    TRACE("ITaskBand::GetSizeMax called\n");
-    /* We don't need any space for the task band */
-    pcbSize->QuadPart = 0;
-    return S_OK;
-}
-
-static const IPersistStreamVtbl IPersistStreamImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IPersistStream, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IPersistStream, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IPersistStream, ITaskBand),
-    /*** IPersist methods ***/
-    ITaskBandImpl_GetClassID,
-    /*** IPersistStream methods ***/
-    ITaskBandImpl_IsDirty,
-    ITaskBandImpl_Load,
-    ITaskBandImpl_Save,
-    ITaskBandImpl_GetSizeMax
-};
-
-/*****************************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IObjectWithSite, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IObjectWithSite, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IObjectWithSite, ITaskBand)
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_SetSite(IN OUT IObjectWithSite *iface,
-                      IN IUnknown* pUnkSite)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_IObjectWithSite(iface);
-    HRESULT hRet = E_FAIL;
-
-    TRACE("ITaskBand::SetSite(0x%p)\n", pUnkSite);
-
-    /* Release the current site */
-    if (This->punkSite != NULL)
-    {
-        IUnknown_Release(This->punkSite);
-    }
-
-    This->punkSite = NULL;
-    This->hWnd = NULL;
-
-    if (pUnkSite != NULL)
-    {
-        IOleWindow *OleWindow;
-
-        /* Check if the site supports IOleWindow */
-        hRet = IUnknown_QueryInterface(pUnkSite,
-                                       &IID_IOleWindow,
-                                       (PVOID *)&OleWindow);
-        if (SUCCEEDED(hRet))
-        {
-            HWND hWndParent = NULL;
-
-            hRet = IOleWindow_GetWindow(OleWindow,
-                                        &hWndParent);
-            if (SUCCEEDED(hRet))
-            {
-                /* Attempt to create the task switch window */
-
-                TRACE("CreateTaskSwitchWnd(Parent: 0x%p)\n", hWndParent);
-                This->hWnd = CreateTaskSwitchWnd(hWndParent,
-                                                 This->Tray);
-                if (This->hWnd != NULL)
-                {
-                    This->punkSite = pUnkSite;
-                    hRet = S_OK;
-                }
-                else
-                {
-                    TRACE("CreateTaskSwitchWnd() failed!\n");
-                    IUnknown_Release(OleWindow);
-                    hRet = E_FAIL;
-                }
-            }
-            else
-                IUnknown_Release(OleWindow);
-        }
-        else
-            TRACE("Querying IOleWindow failed: 0x%x\n", hRet);
-    }
-
-    return hRet;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITaskBandImpl_GetSite(IN OUT IObjectWithSite *iface,
-                      IN REFIID riid,
-                      OUT VOID **ppvSite)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_IObjectWithSite(iface);
-    TRACE("ITaskBand::GetSite(0x%p,0x%p)\n", riid, ppvSite);
-
-    if (This->punkSite != NULL)
-    {
-        return IUnknown_QueryInterface(This->punkSite,
-                                       riid,
-                                       ppvSite);
-    }
-
-    *ppvSite = NULL;
-    return E_FAIL;
-}
-
-static const IObjectWithSiteVtbl IObjectWithSiteImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IObjectWithSite, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IObjectWithSite, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IObjectWithSite, ITaskBand),
-    /*** IObjectWithSite methods ***/
-    ITaskBandImpl_SetSite,
-    ITaskBandImpl_GetSite
-};
-
-
-/*****************************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IWinEventHandler, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IWinEventHandler, ITaskBand)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IWinEventHandler, ITaskBand)
-
-static HRESULT STDMETHODCALLTYPE
-IWinEventHandlerImpl_ProcessMessage(IN OUT IWinEventHandler *iface,
-                                       IN HWND hWnd,
-                                       IN UINT uMsg,
-                                       IN WPARAM wParam,
-                                       IN LPARAM lParam,
-                                       OUT LRESULT *plrResult)
-{
-    TRACE("ITaskBand: IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p)\n", hWnd, uMsg, wParam, lParam, plrResult);
-    return E_NOTIMPL;
-}
-
-static HRESULT STDMETHODCALLTYPE
-IWinEventHandlerImpl_ContainsWindow(IN OUT IWinEventHandler *iface,
-                                       IN HWND hWnd)
-{
-    ITaskBandImpl *This = ITaskBandImpl_from_IWinEventHandler(iface);
-
-    if (This->hWnd == hWnd ||
-        IsChild(This->hWnd, hWnd))
-    {
-        TRACE("ITaskBand::ContainsWindow(0x%p) returns S_OK\n", hWnd);
-        return S_OK;
-    }
-
-    return S_FALSE;
-}
-
-static const IWinEventHandlerVtbl IWinEventHandlerImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IWinEventHandler, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IWinEventHandler, ITaskBand),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IWinEventHandler, ITaskBand),
-    /*** IWinEventHandler methods ***/
-    IWinEventHandlerImpl_ProcessMessage,
-    IWinEventHandlerImpl_ContainsWindow
-};
-
-/*****************************************************************************/
-
-static ITaskBandImpl *
-ITaskBandImpl_Construct(IN OUT ITrayWindow *Tray)
-{
-    ITaskBandImpl *This;
-
-    This = HeapAlloc(hProcessHeap,
-                     HEAP_ZERO_MEMORY,
-                     sizeof(*This));
-    if (This == NULL)
-        return NULL;
-
-    This->lpVtbl = &ITaskBandImpl_Vtbl;
-    This->lpDeskBandVtbl = &IDeskBandImpl_Vtbl;
-    This->lpObjectWithSiteVtbl = &IObjectWithSiteImpl_Vtbl;
-    This->lpDeskBarVtbl = &IDeskBarImpl_Vtbl;
-    This->lpPersistStreamVtbl = &IPersistStreamImpl_Vtbl;
-    This->lpWindowEventHandlerVtbl = &IWinEventHandlerImpl_Vtbl;
-    This->Ref = 1;
-
-    This->Tray = Tray;
-    This->dwBandID = (DWORD)-1;
-
-    return This;
-}
-
-ITaskBand *
-CreateTaskBand(IN OUT ITrayWindow *Tray)
-{
-    ITaskBandImpl *This;
-
-    This = ITaskBandImpl_Construct(Tray);
-    if (This != NULL)
-    {
-        return ITaskBand_from_ITaskBandImpl(This);
-    }
-
-    return NULL;
-}
diff --git a/base/shell/explorer-new/taskband.cpp b/base/shell/explorer-new/taskband.cpp
new file mode 100644 (file)
index 0000000..3c0df86
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * ReactOS Explorer
+ *
+ * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "precomp.h"
+
+/*****************************************************************************
+ ** ITaskBand ****************************************************************
+ *****************************************************************************/
+
+const GUID CLSID_ITaskBand = { 0x68284FAA, 0x6A48, 0x11D0, { 0x8C, 0x78, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0xB4 } };
+
+class ITaskBandImpl :
+    public CComCoClass<ITaskBandImpl>,
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public IObjectWithSite,
+    public ITaskBand,
+    public IDeskBand,
+    public IDeskBar,
+    public IPersistStream,
+    public IWinEventHandler,
+    public IOleCommandTarget
+{
+    CComPtr<ITrayWindow> Tray;
+    CComPtr<IUnknown> punkSite;
+
+    HWND hWnd;
+    DWORD dwBandID;
+
+public:
+    ITaskBandImpl() :
+        hWnd(NULL),
+        dwBandID(0)
+    {
+
+    }
+
+    virtual ~ITaskBandImpl() { }
+
+    virtual HRESULT STDMETHODCALLTYPE GetRebarBandID(
+        OUT DWORD *pdwBandID)
+    {
+        if (dwBandID != (DWORD) -1)
+        {
+            if (pdwBandID != NULL)
+                *pdwBandID = dwBandID;
+
+            return S_OK;
+        }
+
+        return E_FAIL;
+    }
+
+    /*****************************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE GetWindow(
+        OUT HWND *phwnd)
+    {
+
+        /* NOTE: We have to return the tray window here so that ITaskBarClient
+                 knows the parent window of the Rebar control it creates when
+                 calling ITaskBarClient::SetDeskBarSite()! However, once we
+                 created a window we return the task switch window! */
+        if (hWnd != NULL)
+            *phwnd = hWnd;
+        else
+            *phwnd = Tray->GetHWND();
+
+        TRACE("ITaskBand::GetWindow(0x%p->0x%p)\n", phwnd, *phwnd);
+
+        if (*phwnd != NULL)
+            return S_OK;
+
+        return E_FAIL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(
+        IN BOOL fEnterMode)
+    {
+        /* FIXME: Implement */
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ShowDW(
+        IN BOOL bShow)
+    {
+        /* We don't do anything... */
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE CloseDW(
+        IN DWORD dwReserved)
+    {
+        /* We don't do anything... */
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ResizeBorderDW(
+        LPCRECT prcBorder,
+        IUnknown *punkToolbarSite,
+        BOOL fReserved) 
+    {
+        /* No need to implement this method */
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetBandInfo(
+        IN DWORD dwBandID,
+        IN DWORD dwViewMode,
+        IN OUT DESKBANDINFO *pdbi)
+    {
+        TRACE("ITaskBand::GetBandInfo(0x%x,0x%x,0x%p) hWnd=0x%p\n", dwBandID, dwViewMode, pdbi, hWnd);
+
+        if (hWnd != NULL)
+        {
+            /* The task band never has a title */
+            pdbi->dwMask &= ~DBIM_TITLE;
+
+            /* NOTE: We don't return DBIMF_UNDELETEABLE here, the band site will
+                     handle us differently and add this flag for us. The reason for
+                     this is future changes that might allow it to be deletable.
+                     We want the band site to be in charge of this decision rather
+                     the band itself! */
+            /* FIXME: What about DBIMF_NOGRIPPER and DBIMF_ALWAYSGRIPPER */
+            pdbi->dwModeFlags = DBIMF_VARIABLEHEIGHT;
+
+            if (dwViewMode & DBIF_VIEWMODE_VERTICAL)
+            {
+                pdbi->ptIntegral.y = 1;
+                pdbi->ptMinSize.y = 1;
+                /* FIXME: Get the button metrics from the task bar object!!! */
+                pdbi->ptMinSize.x = (3 * GetSystemMetrics(SM_CXEDGE) / 2) + /* FIXME: Might be wrong if only one column! */
+                    GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE)); /* FIXME: Min button size, query!!! */
+            }
+            else
+            {
+                pdbi->ptMinSize.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE)); /* FIXME: Query */
+                pdbi->ptIntegral.y = pdbi->ptMinSize.y + (3 * GetSystemMetrics(SM_CYEDGE) / 2); /* FIXME: Query metrics */
+                /* We're not going to allow task bands where not even the minimum button size fits into the band */
+                pdbi->ptMinSize.x = pdbi->ptIntegral.y;
+            }
+
+            /* Ignored: pdbi->ptMaxSize.x */
+            pdbi->ptMaxSize.y = -1;
+
+            /* FIXME: We should query the height from the task bar object!!! */
+            pdbi->ptActual.y = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
+
+            /* Save the band ID for future use in case we need to check whether a given band
+               is the task band */
+            this->dwBandID = dwBandID;
+
+            TRACE("H: %d, Min: %d,%d, Integral.y: %d Actual: %d,%d\n", (dwViewMode & DBIF_VIEWMODE_VERTICAL) == 0,
+                pdbi->ptMinSize.x, pdbi->ptMinSize.y, pdbi->ptIntegral.y,
+                pdbi->ptActual.x, pdbi->ptActual.y);
+
+            return S_OK;
+        }
+
+        return E_FAIL;
+    }
+
+    /*****************************************************************************/
+    // *** IOleCommandTarget methods ***
+    virtual HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds [], OLECMDTEXT *pCmdText)
+    {
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
+    {
+        if (IsEqualIID(*pguidCmdGroup, IID_IBandSite))
+        {
+            return S_OK;
+        }
+
+        if (IsEqualIID(*pguidCmdGroup, IID_IDeskBand))
+        {
+            return S_OK;
+        }
+
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    /*****************************************************************************/
+    
+    virtual HRESULT STDMETHODCALLTYPE SetClient(
+        IN IUnknown *punkClient)
+    {
+        TRACE("IDeskBar::SetClient(0x%p)\n", punkClient);
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetClient(
+        OUT IUnknown **ppunkClient)
+    {
+        TRACE("IDeskBar::GetClient(0x%p)\n", ppunkClient);
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE OnPosRectChangeDB(
+        IN RECT *prc)
+    {
+        TRACE("IDeskBar::OnPosRectChangeDB(0x%p=(%d,%d,%d,%d))\n", prc, prc->left, prc->top, prc->right, prc->bottom);
+        if (prc->bottom - prc->top == 0)
+            return S_OK;
+
+        return S_FALSE;
+    }
+
+    /*****************************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE GetClassID(
+        OUT CLSID *pClassID)
+    {
+        TRACE("ITaskBand::GetClassID(0x%p)\n", pClassID);
+        /* We're going to return the (internal!) CLSID of the task band interface */
+        *pClassID = CLSID_ITaskBand;
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE IsDirty()
+    {
+        /* The object hasn't changed since the last save! */
+        return S_FALSE;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Load(
+        IN IStream *pStm)
+    {
+        TRACE("ITaskBand::Load called\n");
+        /* Nothing to do */
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Save(
+        IN IStream *pStm,
+        IN BOOL fClearDirty)
+    {
+        /* Nothing to do */
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetSizeMax(
+        OUT ULARGE_INTEGER *pcbSize)
+    {
+        TRACE("ITaskBand::GetSizeMax called\n");
+        /* We don't need any space for the task band */
+        pcbSize->QuadPart = 0;
+        return S_OK;
+    }
+
+    /*****************************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE SetSite(IUnknown *pUnkSite)
+    {
+        HRESULT hRet = E_FAIL;
+
+        TRACE("ITaskBand::SetSite(0x%p)\n", pUnkSite);
+
+        /* Release the current site */
+        if (punkSite != NULL)
+        {
+            punkSite->Release();
+        }
+
+        punkSite = NULL;
+        hWnd = NULL;
+
+        if (pUnkSite != NULL)
+        {
+            IOleWindow *OleWindow;
+
+            /* Check if the site supports IOleWindow */
+            hRet = pUnkSite->QueryInterface(IID_PPV_ARG(IOleWindow, &OleWindow));
+            if (SUCCEEDED(hRet))
+            {
+                HWND hWndParent = NULL;
+
+                hRet = OleWindow->GetWindow(
+                    &hWndParent);
+                if (SUCCEEDED(hRet))
+                {
+                    /* Attempt to create the task switch window */
+
+                    TRACE("CreateTaskSwitchWnd(Parent: 0x%p)\n", hWndParent);
+                    hWnd = CreateTaskSwitchWnd(hWndParent, Tray);
+                    if (hWnd != NULL)
+                    {
+                        punkSite = pUnkSite;
+                        hRet = S_OK;
+                    }
+                    else
+                    {
+                        TRACE("CreateTaskSwitchWnd() failed!\n");
+                        OleWindow->Release();
+                        hRet = E_FAIL;
+                    }
+                }
+                else
+                    OleWindow->Release();
+            }
+            else
+                TRACE("Querying IOleWindow failed: 0x%x\n", hRet);
+        }
+
+        return hRet;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetSite(
+        IN REFIID riid,
+        OUT VOID **ppvSite)
+    {
+        TRACE("ITaskBand::GetSite(0x%p,0x%p)\n", riid, ppvSite);
+
+        if (punkSite != NULL)
+        {
+            return punkSite->QueryInterface(riid, ppvSite);
+        }
+
+        *ppvSite = NULL;
+        return E_FAIL;
+    }
+
+    /*****************************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
+        IN HWND hWnd,
+        IN UINT uMsg,
+        IN WPARAM wParam,
+        IN LPARAM lParam,
+        OUT LRESULT *plrResult)
+    {
+        TRACE("ITaskBand: IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p)\n", hWnd, uMsg, wParam, lParam, plrResult);
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ContainsWindow(
+        IN HWND hWnd)
+    {
+        if (hWnd == hWnd ||
+            IsChild(hWnd, hWnd))
+        {
+            TRACE("ITaskBand::ContainsWindow(0x%p) returns S_OK\n", hWnd);
+            return S_OK;
+        }
+
+        return S_FALSE;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE OnWinEvent(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *theResult)
+    {
+        UNIMPLEMENTED;
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE IsWindowOwner(HWND hWnd)
+    {
+        return (hWnd == this->hWnd) ? S_OK : S_FALSE;
+    }
+
+    /*****************************************************************************/
+
+    HRESULT STDMETHODCALLTYPE _Init(IN OUT ITrayWindow *tray)
+    {
+        Tray = tray;
+        dwBandID = (DWORD) -1;
+        return S_OK;
+    }
+
+    DECLARE_NOT_AGGREGATABLE(ITaskBandImpl)
+
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+    BEGIN_COM_MAP(ITaskBandImpl)
+        COM_INTERFACE_ENTRY2_IID(IID_IOleWindow, IOleWindow, IDeskBand)
+        COM_INTERFACE_ENTRY_IID(IID_IDeskBand, IDeskBand)
+        COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
+        COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist)
+        COM_INTERFACE_ENTRY_IID(IID_IPersistStream, IPersistStream)
+        COM_INTERFACE_ENTRY_IID(IID_IWinEventHandler, IWinEventHandler)
+        COM_INTERFACE_ENTRY_IID(IID_IOleCommandTarget, IOleCommandTarget)
+    END_COM_MAP()
+};
+
+ITaskBand * CreateTaskBand(IN OUT ITrayWindow *Tray)
+{
+    HRESULT hr;
+
+    ITaskBandImpl * tb = new CComObject<ITaskBandImpl>();
+
+    if (!tb)
+        return NULL;
+
+    hr = tb->AddRef();
+
+    hr = tb->_Init(Tray);
+
+    if (FAILED_UNEXPECTEDLY(hr))
+        tb->Release();
+
+    return tb;
+}
diff --git a/base/shell/explorer-new/taskswnd.c b/base/shell/explorer-new/taskswnd.c
deleted file mode 100644 (file)
index fe3f896..0000000
+++ /dev/null
@@ -1,2196 +0,0 @@
-/*
- * ReactOS Explorer
- *
- * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include "precomp.h"
-
-/* Set DUMP_TASKS to 1 to enable a dump of the tasks and task groups every
-   5 seconds */
-#define DUMP_TASKS  0
-
-static const TCHAR szTaskSwitchWndClass[] = TEXT("MSTaskSwWClass");
-static const TCHAR szRunningApps[] = TEXT("Running Applications");
-
-typedef struct _TASK_GROUP
-{
-    /* We have to use a linked list instead of an array so we don't have to
-       update all pointers to groups in the task item array when removing
-       groups. */
-    struct _TASK_GROUP *Next;
-
-    DWORD dwTaskCount;
-    DWORD dwProcessId;
-    INT Index;
-    union
-    {
-        DWORD dwFlags;
-        struct
-        {
-
-            DWORD IsCollapsed : 1;
-        };
-    };
-} TASK_GROUP, *PTASK_GROUP;
-
-typedef struct _TASK_ITEM
-{
-    HWND hWnd;
-    PTASK_GROUP Group;
-    INT Index;
-    INT IconIndex;
-
-
-
-    union
-    {
-        DWORD dwFlags;
-        struct
-        {
-
-            /* IsFlashing is TRUE when the task bar item should be flashing. */
-            DWORD IsFlashing : 1;
-
-            /* RenderFlashed is only TRUE if the task bar item should be
-               drawn with a flash. */
-            DWORD RenderFlashed : 1;
-        };
-    };
-} TASK_ITEM, *PTASK_ITEM;
-
-#define TASK_ITEM_ARRAY_ALLOC   64
-
-typedef struct _TASK_SWITCH_WND
-{
-    HWND hWnd;
-    HWND hWndNotify;
-
-    UINT ShellHookMsg;
-    ITrayWindow *Tray;
-
-    PTASK_GROUP TaskGroups;
-
-    WORD TaskItemCount;
-    WORD AllocatedTaskItems;
-    PTASK_ITEM TaskItems;
-    PTASK_ITEM ActiveTaskItem;
-
-    HTHEME TaskBandTheme;
-    HWND hWndToolbar;
-    UINT TbButtonsPerLine;
-    WORD ToolbarBtnCount;
-    HIMAGELIST TaskIcons;
-
-    union
-    {
-        DWORD dwFlags;
-        struct
-        {
-            DWORD IsGroupingEnabled : 1;
-            DWORD IsDestroying : 1;
-            DWORD IsToolbarSubclassed : 1;
-        };
-    };
-
-    SIZE ButtonSize;
-    TCHAR szBuf[255];
-} TASK_SWITCH_WND, *PTASK_SWITCH_WND;
-
-#define TSW_TOOLBAR_SUBCLASS_ID 1
-
-#define MAX_TASKS_COUNT (0x7FFF)
-
-static VOID TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This,
-                                            IN BOOL bRedrawDisabled);
-
-static LPTSTR
-TaskSwitchWnd_GetWndTextFromTaskItem(IN OUT PTASK_SWITCH_WND This,
-                                     IN PTASK_ITEM TaskItem)
-{
-    /* Get the window text without sending a message so we don't hang if an
-       application isn't responding! */
-    if (InternalGetWindowText(TaskItem->hWnd,
-                              This->szBuf,
-                              sizeof(This->szBuf) / sizeof(This->szBuf[0])) > 0)
-    {
-        return This->szBuf;
-    }
-
-    return NULL;
-}
-
-
-#if DUMP_TASKS != 0
-static VOID
-TaskSwitchWnd_DumpTasks(IN OUT PTASK_SWITCH_WND This)
-{
-    PTASK_GROUP CurrentGroup;
-    PTASK_ITEM CurrentTaskItem, LastTaskItem;
-
-    TRACE("Tasks dump:\n");
-    if (This->IsGroupingEnabled)
-    {
-        CurrentGroup = This->TaskGroups;
-        while (CurrentGroup != NULL)
-        {
-            TRACE("- Group PID: 0x%p Tasks: %d Index: %d\n", CurrentGroup->dwProcessId, CurrentGroup->dwTaskCount, CurrentGroup->Index);
-
-            CurrentTaskItem = This->TaskItems;
-            LastTaskItem = CurrentTaskItem + This->TaskItemCount;
-            while (CurrentTaskItem != LastTaskItem)
-            {
-                if (CurrentTaskItem->Group == CurrentGroup)
-                {
-                    TRACE("  + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
-                }
-                CurrentTaskItem++;
-            }
-
-            CurrentGroup = CurrentGroup->Next;
-        }
-
-        CurrentTaskItem = This->TaskItems;
-        LastTaskItem = CurrentTaskItem + This->TaskItemCount;
-        while (CurrentTaskItem != LastTaskItem)
-        {
-            if (CurrentTaskItem->Group == NULL)
-            {
-                TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
-            }
-            CurrentTaskItem++;
-        }
-    }
-    else
-    {
-        CurrentTaskItem = This->TaskItems;
-        LastTaskItem = CurrentTaskItem + This->TaskItemCount;
-        while (CurrentTaskItem != LastTaskItem)
-        {
-            TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
-            CurrentTaskItem++;
-        }
-    }
-}
-#endif
-
-static VOID
-TaskSwitchWnd_BeginUpdate(IN OUT PTASK_SWITCH_WND This)
-{
-    SendMessage(This->hWndToolbar,
-                WM_SETREDRAW,
-                FALSE,
-                0);
-}
-
-static VOID
-TaskSwitchWnd_EndUpdate(IN OUT PTASK_SWITCH_WND This)
-{
-    SendMessage(This->hWndToolbar,
-                WM_SETREDRAW,
-                TRUE,
-                0);
-    InvalidateRect(This->hWndToolbar,
-                   NULL,
-                   TRUE);
-}
-
-static BOOL
-TaskSwitchWnd_SetToolbarButtonCommandId(IN OUT PTASK_SWITCH_WND This,
-                                        IN INT iButtonIndex,
-                                        IN INT iCommandId)
-{
-    TBBUTTONINFO tbbi;
-
-    tbbi.cbSize = sizeof(tbbi);
-    tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
-    tbbi.idCommand = iCommandId;
-
-    return SendMessage(This->hWndToolbar,
-                       TB_SETBUTTONINFO,
-                       (WPARAM)iButtonIndex,
-                       (LPARAM)&tbbi) != 0;
-}
-
-static VOID
-TaskSwitchWnd_UpdateIndexesAfterButtonInserted(IN OUT PTASK_SWITCH_WND This,
-                                               IN INT iIndex)
-{
-    PTASK_GROUP CurrentGroup;
-    PTASK_ITEM CurrentTaskItem, LastTaskItem;
-    INT NewIndex;
-
-    if (This->IsGroupingEnabled)
-    {
-        /* Update all affected groups */
-        CurrentGroup = This->TaskGroups;
-        while (CurrentGroup != NULL)
-        {
-            if (CurrentGroup->IsCollapsed &&
-                CurrentGroup->Index >= iIndex)
-            {
-                /* Update the toolbar buttons */
-                NewIndex = CurrentGroup->Index + 1;
-                if (TaskSwitchWnd_SetToolbarButtonCommandId(This,
-                                                            CurrentGroup->Index + 1,
-                                                            NewIndex))
-                {
-                    CurrentGroup->Index = NewIndex;
-                }
-                else
-                    CurrentGroup->Index = -1;
-            }
-
-            CurrentGroup = CurrentGroup->Next;
-        }
-    }
-
-    /* Update all affected task items */
-    CurrentTaskItem = This->TaskItems;
-    LastTaskItem = CurrentTaskItem + This->TaskItemCount;
-    while (CurrentTaskItem != LastTaskItem)
-    {
-        CurrentGroup = CurrentTaskItem->Group;
-        if (CurrentGroup != NULL)
-        {
-            if (!CurrentGroup->IsCollapsed &&
-                CurrentTaskItem->Index >= iIndex)
-            {
-                goto UpdateTaskItemBtn;
-            }
-        }
-        else if (CurrentTaskItem->Index >= iIndex)
-        {
-UpdateTaskItemBtn:
-            /* Update the toolbar buttons */
-            NewIndex = CurrentTaskItem->Index + 1;
-            if (TaskSwitchWnd_SetToolbarButtonCommandId(This,
-                                                        CurrentTaskItem->Index + 1,
-                                                        NewIndex))
-            {
-                CurrentTaskItem->Index = NewIndex;
-            }
-            else
-                CurrentTaskItem->Index = -1;
-        }
-
-        CurrentTaskItem++;
-    }
-}
-
-static VOID
-TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(IN OUT PTASK_SWITCH_WND This,
-                                              IN INT iIndex)
-{
-    PTASK_GROUP CurrentGroup;
-    PTASK_ITEM CurrentTaskItem, LastTaskItem;
-    INT NewIndex;
-
-    if (This->IsGroupingEnabled)
-    {
-        /* Update all affected groups */
-        CurrentGroup = This->TaskGroups;
-        while (CurrentGroup != NULL)
-        {
-            if (CurrentGroup->IsCollapsed &&
-                CurrentGroup->Index > iIndex)
-            {
-                /* Update the toolbar buttons */
-                NewIndex = CurrentGroup->Index - 1;
-                if (TaskSwitchWnd_SetToolbarButtonCommandId(This,
-                                                            CurrentGroup->Index - 1,
-                                                            NewIndex))
-                {
-                    CurrentGroup->Index = NewIndex;
-                }
-                else
-                    CurrentGroup->Index = -1;
-            }
-
-            CurrentGroup = CurrentGroup->Next;
-        }
-    }
-
-    /* Update all affected task items */
-    CurrentTaskItem = This->TaskItems;
-    LastTaskItem = CurrentTaskItem + This->TaskItemCount;
-    while (CurrentTaskItem != LastTaskItem)
-    {
-        CurrentGroup = CurrentTaskItem->Group;
-        if (CurrentGroup != NULL)
-        {
-            if (!CurrentGroup->IsCollapsed &&
-                CurrentTaskItem->Index > iIndex)
-            {
-                goto UpdateTaskItemBtn;
-            }
-        }
-        else if (CurrentTaskItem->Index > iIndex)
-        {
-UpdateTaskItemBtn:
-            /* Update the toolbar buttons */
-            NewIndex = CurrentTaskItem->Index - 1;
-            if (TaskSwitchWnd_SetToolbarButtonCommandId(This,
-                                                        CurrentTaskItem->Index - 1,
-                                                        NewIndex))
-            {
-                CurrentTaskItem->Index = NewIndex;
-            }
-            else
-                CurrentTaskItem->Index = -1;
-        }
-
-        CurrentTaskItem++;
-    }
-}
-
-static INT
-TaskSwitchWnd_UpdateTaskGroupButton(IN OUT PTASK_SWITCH_WND This,
-                                    IN PTASK_GROUP TaskGroup)
-{
-    ASSERT(TaskGroup->Index >= 0);
-
-    /* FIXME: Implement */
-
-    return TaskGroup->Index;
-}
-
-static VOID
-TaskSwitchWnd_ExpandTaskGroup(IN OUT PTASK_SWITCH_WND This,
-                              IN PTASK_GROUP TaskGroup)
-{
-    ASSERT(TaskGroup->dwTaskCount > 0);
-    ASSERT(TaskGroup->IsCollapsed);
-    ASSERT(TaskGroup->Index >= 0);
-
-    /* FIXME: Implement */
-}
-
-static HICON
-TaskSwitchWnd_GetWndIcon(HWND hwnd)
-{
-    HICON hIcon = 0;
-
-    SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
-
-    if (!hIcon)
-       SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
-
-    if (!hIcon)
-       SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
-
-    if (!hIcon)
-       hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM);
-
-    if (!hIcon)
-       hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON);
-
-    return hIcon;
-}
-static INT
-TaskSwitchWnd_UpdateTaskItemButton(IN OUT PTASK_SWITCH_WND This,
-                                   IN PTASK_ITEM TaskItem)
-{
-    TBBUTTONINFO tbbi;
-    HICON icon;
-
-    ASSERT(TaskItem->Index >= 0);
-
-    tbbi.cbSize = sizeof(tbbi);
-    tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE | TBIF_TEXT | TBIF_IMAGE;
-    tbbi.fsState = TBSTATE_ENABLED;
-    if (This->ActiveTaskItem == TaskItem)
-        tbbi.fsState |= TBSTATE_CHECKED;
-
-    if (TaskItem->RenderFlashed)
-        tbbi.fsState |= TBSTATE_MARKED;
-
-    /* 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 (This->TbButtonsPerLine != 0 &&
-        (TaskItem->Index + 1) % This->TbButtonsPerLine == 0)
-    {
-        tbbi.fsState |= TBSTATE_WRAP;
-    }
-
-    tbbi.pszText = TaskSwitchWnd_GetWndTextFromTaskItem(This,
-                                                        TaskItem);
-
-    icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd);
-    TaskItem->IconIndex = ImageList_ReplaceIcon(This->TaskIcons,
-                                                TaskItem->IconIndex,
-                                                icon);
-    tbbi.iImage = TaskItem->IconIndex;
-
-    if (!SendMessage(This->hWndToolbar,
-                     TB_SETBUTTONINFO,
-                     (WPARAM)TaskItem->Index,
-                     (LPARAM)&tbbi))
-    {
-        TaskItem->Index = -1;
-        return -1;
-    }
-
-    TRACE("Updated button %d for hwnd 0x%p\n", TaskItem->Index, TaskItem->hWnd);
-    return TaskItem->Index;
-}
-
-static VOID
-TaskSwitchWnd_RemoveIcon(IN OUT PTASK_SWITCH_WND This,
-                         IN PTASK_ITEM TaskItem)
-{
-    TBBUTTONINFO tbbi;
-    PTASK_ITEM currentTaskItem, LastItem;
-
-    if (TaskItem->IconIndex == -1)
-        return;
-
-    tbbi.cbSize = sizeof(tbbi);
-    tbbi.dwMask = TBIF_IMAGE;
-
-    currentTaskItem = This->TaskItems;
-    LastItem = currentTaskItem + This->TaskItemCount;
-    while (currentTaskItem != LastItem)
-    {
-        if (currentTaskItem->IconIndex > TaskItem->IconIndex)
-        {
-            currentTaskItem->IconIndex--;
-            tbbi.iImage = currentTaskItem->IconIndex;
-
-            SendMessage(This->hWndToolbar,
-                        TB_SETBUTTONINFO,
-                        currentTaskItem->Index,
-                        (LPARAM)&tbbi);
-        }
-        currentTaskItem++;
-    }
-
-    ImageList_Remove(This->TaskIcons, TaskItem->IconIndex);
-}
-
-static PTASK_ITEM
-TaskSwitchWnd_FindLastTaskItemOfGroup(IN OUT PTASK_SWITCH_WND This,
-                                      IN PTASK_GROUP TaskGroup  OPTIONAL,
-                                      IN PTASK_ITEM NewTaskItem  OPTIONAL)
-{
-    PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL;
-    DWORD dwTaskCount;
-
-    ASSERT(This->IsGroupingEnabled);
-
-    TaskItem = This->TaskItems;
-    LastTaskItem = TaskItem + This->TaskItemCount;
-
-    dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT);
-
-    ASSERT(dwTaskCount > 0);
-
-    while (TaskItem != LastTaskItem)
-    {
-        if (TaskItem->Group == TaskGroup)
-        {
-            if ((NewTaskItem != NULL && TaskItem != NewTaskItem) || NewTaskItem == NULL)
-            {
-                FoundTaskItem = TaskItem;
-            }
-
-            if (--dwTaskCount == 0)
-            {
-                /* We found the last task item in the group! */
-                break;
-            }
-        }
-
-        TaskItem++;
-    }
-
-    return FoundTaskItem;
-}
-
-static INT
-TaskSwitchWnd_CalculateTaskItemNewButtonIndex(IN OUT PTASK_SWITCH_WND This,
-                                              IN PTASK_ITEM TaskItem)
-{
-    PTASK_GROUP TaskGroup;
-    PTASK_ITEM LastTaskItem;
-
-    /* NOTE: This routine assumes that the group is *not* collapsed! */
-
-    TaskGroup = TaskItem->Group;
-    if (This->IsGroupingEnabled)
-    {
-        if (TaskGroup != NULL)
-        {
-            ASSERT(TaskGroup->Index < 0);
-            ASSERT(!TaskGroup->IsCollapsed);
-
-            if (TaskGroup->dwTaskCount > 1)
-            {
-                LastTaskItem = TaskSwitchWnd_FindLastTaskItemOfGroup(This,
-                                                                     TaskGroup,
-                                                                     TaskItem);
-                if (LastTaskItem != NULL)
-                {
-                    /* Since the group is expanded the task items must have an index */
-                    ASSERT(LastTaskItem->Index >= 0);
-
-                    return LastTaskItem->Index + 1;
-                }
-            }
-        }
-        else
-        {
-            /* Find the last NULL group button. NULL groups are added at the end of the
-               task item list when grouping is enabled */
-            LastTaskItem = TaskSwitchWnd_FindLastTaskItemOfGroup(This,
-                                                                 NULL,
-                                                                 TaskItem);
-            if (LastTaskItem != NULL)
-            {
-                ASSERT(LastTaskItem->Index >= 0);
-
-                return LastTaskItem->Index + 1;
-            }
-        }
-    }
-
-    return This->ToolbarBtnCount;
-}
-
-static INT
-TaskSwitchWnd_AddTaskItemButton(IN OUT PTASK_SWITCH_WND This,
-                                IN OUT PTASK_ITEM TaskItem)
-{
-    TBBUTTON tbBtn;
-    INT iIndex;
-    HICON icon;
-
-    if (TaskItem->Index >= 0)
-    {
-        return TaskSwitchWnd_UpdateTaskItemButton(This,
-                                                  TaskItem);
-    }
-
-    if (TaskItem->Group != NULL &&
-        TaskItem->Group->IsCollapsed)
-    {
-        /* The task group is collapsed, we only need to update the group button */
-        return TaskSwitchWnd_UpdateTaskGroupButton(This,
-                                                   TaskItem->Group);
-    }
-
-    icon = TaskSwitchWnd_GetWndIcon(TaskItem->hWnd);
-    TaskItem->IconIndex = ImageList_AddIcon(This->TaskIcons, 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)TaskSwitchWnd_GetWndTextFromTaskItem(This,
-                                                                    TaskItem);
-
-    /* Find out where to insert the new button */
-    iIndex = TaskSwitchWnd_CalculateTaskItemNewButtonIndex(This,
-                                                           TaskItem);
-    ASSERT(iIndex >= 0);
-    tbBtn.idCommand = iIndex;
-
-    TaskSwitchWnd_BeginUpdate(This);
-
-    if (SendMessage(This->hWndToolbar,
-                    TB_INSERTBUTTON,
-                    (WPARAM)iIndex,
-                    (LPARAM)&tbBtn))
-    {
-        TaskSwitchWnd_UpdateIndexesAfterButtonInserted(This,
-                                                       iIndex);
-
-        TRACE("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd);
-
-        TaskItem->Index = iIndex;
-        This->ToolbarBtnCount++;
-
-        /* Update button sizes and fix the button wrapping */
-        TaskSwitchWnd_UpdateButtonsSize(This,
-                                        TRUE);
-        return iIndex;
-    }
-
-    TaskSwitchWnd_EndUpdate(This);
-
-    return -1;
-}
-
-static BOOL
-TaskSwitchWnd_DeleteTaskItemButton(IN OUT PTASK_SWITCH_WND This,
-                                   IN OUT PTASK_ITEM TaskItem)
-{
-    PTASK_GROUP TaskGroup;
-    INT iIndex;
-
-    TaskGroup = TaskItem->Group;
-
-    if (TaskItem->Index >= 0)
-    {
-        if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) ||
-            TaskGroup == NULL)
-        {
-            TaskSwitchWnd_BeginUpdate(This);
-
-            TaskSwitchWnd_RemoveIcon(This, TaskItem);
-            iIndex = TaskItem->Index;
-            if (SendMessage(This->hWndToolbar,
-                            TB_DELETEBUTTON,
-                            (WPARAM)iIndex,
-                            0))
-            {
-                TaskItem->Index = -1;
-                This->ToolbarBtnCount--;
-
-                TaskSwitchWnd_UpdateIndexesAfterButtonDeleted(This,
-                                                              iIndex);
-
-                /* Update button sizes and fix the button wrapping */
-                TaskSwitchWnd_UpdateButtonsSize(This,
-                                                TRUE);
-                return TRUE;
-            }
-
-            TaskSwitchWnd_EndUpdate(This);
-        }
-    }
-
-    return FALSE;
-}
-
-static PTASK_GROUP
-TaskSwitchWnd_AddToTaskGroup(IN OUT PTASK_SWITCH_WND This,
-                             IN HWND hWnd)
-{
-    DWORD dwProcessId;
-    PTASK_GROUP TaskGroup, *PrevLink;
-
-    if (!GetWindowThreadProcessId(hWnd,
-                                  &dwProcessId))
-    {
-        TRACE("Cannot get process id of hwnd 0x%p\n", hWnd);
-        return NULL;
-    }
-
-    /* Try to find an existing task group */
-    TaskGroup = This->TaskGroups;
-    PrevLink = &This->TaskGroups;
-    while (TaskGroup != NULL)
-    {
-        if (TaskGroup->dwProcessId == dwProcessId)
-        {
-            TaskGroup->dwTaskCount++;
-            return TaskGroup;
-        }
-
-        PrevLink = &TaskGroup->Next;
-        TaskGroup = TaskGroup->Next;
-    }
-
-    /* Allocate a new task group */
-    TaskGroup = HeapAlloc(hProcessHeap,
-                          HEAP_ZERO_MEMORY,
-                          sizeof(*TaskGroup));
-    if (TaskGroup != NULL)
-    {
-        TaskGroup->dwTaskCount = 1;
-        TaskGroup->dwProcessId = dwProcessId;
-        TaskGroup->Index = -1;
-
-        /* Add the task group to the list */
-        *PrevLink = TaskGroup;
-    }
-
-    return TaskGroup;
-}
-
-static VOID
-TaskSwitchWnd_RemoveTaskFromTaskGroup(IN OUT PTASK_SWITCH_WND This,
-                                      IN OUT PTASK_ITEM TaskItem)
-{
-    PTASK_GROUP TaskGroup, CurrentGroup, *PrevLink;
-
-    TaskGroup = TaskItem->Group;
-    if (TaskGroup != NULL)
-    {
-        DWORD dwNewTaskCount = --TaskGroup->dwTaskCount;
-        if (dwNewTaskCount == 0)
-        {
-            /* Find the previous pointer in the chain */
-            CurrentGroup = This->TaskGroups;
-            PrevLink = &This->TaskGroups;
-            while (CurrentGroup != TaskGroup)
-            {
-                PrevLink = &CurrentGroup->Next;
-                CurrentGroup = CurrentGroup->Next;
-            }
-
-            /* Remove the group from the list */
-            ASSERT(TaskGroup == CurrentGroup);
-            *PrevLink = TaskGroup->Next;
-
-            /* Free the task group */
-            HeapFree(hProcessHeap,
-                     0,
-                     TaskGroup);
-        }
-        else if (TaskGroup->IsCollapsed &&
-                 TaskGroup->Index >= 0)
-        {
-            if (dwNewTaskCount > 1)
-            {
-                /* FIXME: Check if we should expand the group */
-                /* Update the task group button */
-                TaskSwitchWnd_UpdateTaskGroupButton(This,
-                                                    TaskGroup);
-            }
-            else
-            {
-                /* Expand the group of one task button to a task button */
-                TaskSwitchWnd_ExpandTaskGroup(This,
-                                              TaskGroup);
-            }
-        }
-    }
-}
-
-static PTASK_ITEM
-TaskSwitchWnd_FindTaskItem(IN OUT PTASK_SWITCH_WND This,
-                           IN HWND hWnd)
-{
-    PTASK_ITEM TaskItem, LastItem;
-
-    TaskItem = This->TaskItems;
-    LastItem = TaskItem + This->TaskItemCount;
-    while (TaskItem != LastItem)
-    {
-        if (TaskItem->hWnd == hWnd)
-            return TaskItem;
-
-        TaskItem++;
-    }
-
-    return NULL;
-}
-
-static PTASK_ITEM
-TaskSwitchWnd_FindOtherTaskItem(IN OUT PTASK_SWITCH_WND This,
-                                IN HWND hWnd)
-{
-    PTASK_ITEM LastItem, TaskItem;
-    PTASK_GROUP TaskGroup;
-    DWORD dwProcessId;
-
-    if (!GetWindowThreadProcessId(hWnd,
-                                  &dwProcessId))
-    {
-        return NULL;
-    }
-
-    /* Try to find another task that belongs to the same
-       process as the given window */
-    TaskItem = This->TaskItems;
-    LastItem = TaskItem + This->TaskItemCount;
-    while (TaskItem != LastItem)
-    {
-        TaskGroup = TaskItem->Group;
-        if (TaskGroup != NULL)
-        {
-            if (TaskGroup->dwProcessId == dwProcessId)
-                return TaskItem;
-        }
-        else
-        {
-            DWORD dwProcessIdTask;
-
-            if (GetWindowThreadProcessId(TaskItem->hWnd,
-                                         &dwProcessIdTask) &&
-                dwProcessIdTask == dwProcessId)
-            {
-                return TaskItem;
-            }
-        }
-
-        TaskItem++;
-    }
-
-    return NULL;
-}
-
-static PTASK_ITEM
-TaskSwitchWnd_AllocTaskItem(IN OUT PTASK_SWITCH_WND This)
-{
-    if (This->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(This->AllocatedTaskItems >= This->TaskItemCount);
-
-    if (This->TaskItemCount == 0)
-    {
-        This->TaskItems = HeapAlloc(hProcessHeap,
-                                    0,
-                                    TASK_ITEM_ARRAY_ALLOC * sizeof(*This->TaskItems));
-        if (This->TaskItems != NULL)
-        {
-            This->AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC;
-        }
-        else
-            return NULL;
-    }
-    else if (This->TaskItemCount >= This->AllocatedTaskItems)
-    {
-        PTASK_ITEM NewArray;
-        SIZE_T NewArrayLength, ActiveTaskItemIndex;
-
-        NewArrayLength = This->AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC;
-
-        NewArray = HeapReAlloc(hProcessHeap,
-                               0,
-                               This->TaskItems,
-                               NewArrayLength * sizeof(*This->TaskItems));
-        if (NewArray != NULL)
-        {
-            if (This->ActiveTaskItem != NULL)
-            {
-                /* Fixup the ActiveTaskItem pointer */
-                ActiveTaskItemIndex = This->ActiveTaskItem - This->TaskItems;
-                This->ActiveTaskItem = NewArray + ActiveTaskItemIndex;
-            }
-            This->AllocatedTaskItems = (WORD)NewArrayLength;
-            This->TaskItems = NewArray;
-        }
-        else
-            return NULL;
-    }
-
-    return This->TaskItems + This->TaskItemCount++;
-}
-
-static VOID
-TaskSwitchWnd_FreeTaskItem(IN OUT PTASK_SWITCH_WND This,
-                           IN OUT PTASK_ITEM TaskItem)
-{
-    WORD wIndex;
-
-    if (TaskItem == This->ActiveTaskItem)
-        This->ActiveTaskItem = NULL;
-
-    wIndex = (WORD)(TaskItem - This->TaskItems);
-    if (wIndex + 1 < This->TaskItemCount)
-    {
-        MoveMemory(TaskItem,
-                   TaskItem + 1,
-                   (This->TaskItemCount - wIndex - 1) * sizeof(*TaskItem));
-    }
-
-    This->TaskItemCount--;
-}
-
-static VOID
-TaskSwitchWnd_DeleteTaskItem(IN OUT PTASK_SWITCH_WND This,
-                             IN OUT PTASK_ITEM TaskItem)
-{
-    if (!This->IsDestroying)
-    {
-        /* Delete the task button from the toolbar */
-        TaskSwitchWnd_DeleteTaskItemButton(This,
-                                           TaskItem);
-    }
-
-    /* Remove the task from it's group */
-    TaskSwitchWnd_RemoveTaskFromTaskGroup(This,
-                                          TaskItem);
-
-    /* Free the task item */
-    TaskSwitchWnd_FreeTaskItem(This,
-                               TaskItem);
-}
-
-static VOID
-TaskSwitchWnd_CheckActivateTaskItem(IN OUT PTASK_SWITCH_WND This,
-                                    IN OUT PTASK_ITEM TaskItem)
-{
-    PTASK_ITEM CurrentTaskItem;
-    PTASK_GROUP TaskGroup = NULL;
-
-    CurrentTaskItem = This->ActiveTaskItem;
-
-    if (TaskItem != NULL)
-        TaskGroup = TaskItem->Group;
-
-    if (This->IsGroupingEnabled &&
-        TaskGroup != NULL &&
-        TaskGroup->IsCollapsed)
-    {
-        /* FIXME */
-        return;
-    }
-
-    if (CurrentTaskItem != NULL)
-    {
-        PTASK_GROUP CurrentTaskGroup;
-
-        if (CurrentTaskItem == TaskItem)
-            return;
-
-        CurrentTaskGroup = CurrentTaskItem->Group;
-
-        if (This->IsGroupingEnabled &&
-            CurrentTaskGroup != NULL &&
-            CurrentTaskGroup->IsCollapsed)
-        {
-            if (CurrentTaskGroup == TaskGroup)
-                return;
-
-            /* FIXME */
-        }
-        else
-        {
-            This->ActiveTaskItem = NULL;
-            if (CurrentTaskItem->Index >= 0)
-            {
-                TaskSwitchWnd_UpdateTaskItemButton(This, CurrentTaskItem);
-            }
-        }
-    }
-
-    This->ActiveTaskItem = TaskItem;
-
-    if (TaskItem != NULL && TaskItem->Index >= 0)
-    {
-        TaskSwitchWnd_UpdateTaskItemButton(This, TaskItem);
-    }
-    else if (TaskItem == NULL)
-    {
-        TRACE("Active TaskItem now NULL\n");
-    }
-}
-
-static PTASK_ITEM
-FindTaskItemByIndex(IN OUT PTASK_SWITCH_WND This,
-                    IN INT Index)
-{
-    PTASK_ITEM TaskItem, LastItem;
-
-    TaskItem = This->TaskItems;
-    LastItem = TaskItem + This->TaskItemCount;
-    while (TaskItem != LastItem)
-    {
-        if (TaskItem->Index == Index)
-            return TaskItem;
-
-        TaskItem++;
-    }
-
-    return NULL;
-}
-
-static PTASK_GROUP
-FindTaskGroupByIndex(IN OUT PTASK_SWITCH_WND This,
-                     IN INT Index)
-{
-    PTASK_GROUP CurrentGroup;
-
-    CurrentGroup = This->TaskGroups;
-    while (CurrentGroup != NULL)
-    {
-        if (CurrentGroup->Index == Index)
-            break;
-
-        CurrentGroup = CurrentGroup->Next;
-    }
-
-    return CurrentGroup;
-}
-
-static BOOL
-TaskSwitchWnd_AddTask(IN OUT PTASK_SWITCH_WND This,
-                      IN HWND hWnd)
-{
-    PTASK_ITEM TaskItem;
-
-    if (!IsWindow(hWnd) || ITrayWindow_IsSpecialHWND(This->Tray, hWnd))
-        return FALSE;
-
-    TaskItem = TaskSwitchWnd_FindTaskItem(This,
-                                          hWnd);
-    if (TaskItem == NULL)
-    {
-        TRACE("Add window 0x%p\n", hWnd);
-        TaskItem = TaskSwitchWnd_AllocTaskItem(This);
-        if (TaskItem != NULL)
-        {
-            ZeroMemory(TaskItem,
-                       sizeof(*TaskItem));
-            TaskItem->hWnd = hWnd;
-            TaskItem->Index = -1;
-            TaskItem->Group = TaskSwitchWnd_AddToTaskGroup(This,
-                                                           hWnd);
-
-            if (!This->IsDestroying)
-            {
-                TaskSwitchWnd_AddTaskItemButton(This,
-                                                TaskItem);
-            }
-        }
-    }
-
-    return TaskItem != NULL;
-}
-
-static BOOL
-TaskSwitchWnd_ActivateTaskItem(IN OUT PTASK_SWITCH_WND This,
-                               IN OUT PTASK_ITEM TaskItem  OPTIONAL)
-{
-    if (TaskItem != NULL)
-    {
-        TRACE("Activate window 0x%p on button %d\n", TaskItem->hWnd, TaskItem->Index);
-    }
-
-    TaskSwitchWnd_CheckActivateTaskItem(This, TaskItem);
-
-    return FALSE;
-}
-
-static BOOL
-TaskSwitchWnd_ActivateTask(IN OUT PTASK_SWITCH_WND This,
-                           IN HWND hWnd)
-{
-    PTASK_ITEM TaskItem;
-
-    if (!hWnd)
-    {
-        return TaskSwitchWnd_ActivateTaskItem(This, NULL);
-    }
-
-    TaskItem = TaskSwitchWnd_FindTaskItem(This,
-                                          hWnd);
-    if (TaskItem == NULL)
-    {
-        TaskItem = TaskSwitchWnd_FindOtherTaskItem(This,
-                                                   hWnd);
-    }
-
-    if (TaskItem == NULL)
-    {
-        TRACE("Activate window 0x%p, could not find task\n", hWnd);
-    }
-
-    return TaskSwitchWnd_ActivateTaskItem(This, TaskItem);
-}
-
-static BOOL
-TaskSwitchWnd_DeleteTask(IN OUT PTASK_SWITCH_WND This,
-                         IN HWND hWnd)
-{
-    PTASK_ITEM TaskItem;
-
-    TaskItem = TaskSwitchWnd_FindTaskItem(This,
-                                          hWnd);
-    if (TaskItem != NULL)
-    {
-        TRACE("Delete window 0x%p on button %d\n", hWnd, TaskItem->Index);
-        TaskSwitchWnd_DeleteTaskItem(This,
-                                     TaskItem);
-        return TRUE;
-    }
-    //else
-        //TRACE("Failed to delete window 0x%p\n", hWnd);
-
-    return FALSE;
-}
-
-static VOID
-TaskSwitchWnd_DeleteAllTasks(IN OUT PTASK_SWITCH_WND This)
-{
-    PTASK_ITEM CurrentTask;
-
-    if (This->TaskItemCount > 0)
-    {
-        CurrentTask = This->TaskItems + This->TaskItemCount;
-        do
-        {
-            TaskSwitchWnd_DeleteTaskItem(This,
-                                         --CurrentTask);
-        } while (CurrentTask != This->TaskItems);
-    }
-}
-
-static VOID
-TaskSwitchWnd_FlashTaskItem(IN OUT PTASK_SWITCH_WND This,
-                            IN OUT PTASK_ITEM TaskItem)
-{
-    TaskItem->RenderFlashed = 1;
-    TaskSwitchWnd_UpdateTaskItemButton(This,
-                                       TaskItem);
-}
-
-static BOOL
-TaskSwitchWnd_FlashTask(IN OUT PTASK_SWITCH_WND This,
-                        IN HWND hWnd)
-{
-    PTASK_ITEM TaskItem;
-
-    TaskItem = TaskSwitchWnd_FindTaskItem(This,
-                                          hWnd);
-    if (TaskItem != NULL)
-    {
-        TRACE("Flashing window 0x%p on button %d\n", hWnd, TaskItem->Index);
-        TaskSwitchWnd_FlashTaskItem(This,
-                                    TaskItem);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-static VOID
-TaskSwitchWnd_RedrawTaskItem(IN OUT PTASK_SWITCH_WND This,
-                             IN OUT PTASK_ITEM TaskItem)
-{
-    PTASK_GROUP TaskGroup;
-
-    TaskGroup = TaskItem->Group;
-    if (This->IsGroupingEnabled && TaskGroup != NULL)
-    {
-        if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0)
-        {
-            TaskSwitchWnd_UpdateTaskGroupButton(This,
-                                                TaskGroup);
-        }
-        else if (TaskItem->Index >= 0)
-        {
-            goto UpdateTaskItem;
-        }
-    }
-    else if (TaskItem->Index >= 0)
-    {
-UpdateTaskItem:
-        TaskItem->RenderFlashed = 0;
-        TaskSwitchWnd_UpdateTaskItemButton(This,
-                                           TaskItem);
-    }
-}
-
-
-static BOOL
-TaskSwitchWnd_RedrawTask(IN OUT PTASK_SWITCH_WND This,
-                         IN HWND hWnd)
-{
-    PTASK_ITEM TaskItem;
-
-    TaskItem = TaskSwitchWnd_FindTaskItem(This,
-                                          hWnd);
-    if (TaskItem != NULL)
-    {
-        TaskSwitchWnd_RedrawTaskItem(This,
-                                     TaskItem);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-static INT
-TaskSwitchWnd_UpdateTbButtonSpacing(IN OUT PTASK_SWITCH_WND This,
-                                    IN BOOL bHorizontal,
-                                    IN UINT uiRows,
-                                    IN UINT uiBtnsPerLine)
-{
-    TBMETRICS tbm;
-
-    tbm.cbSize = sizeof(tbm);
-    tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
-
-    tbm.cxBarPad = tbm.cyBarPad = 0;
-
-    if (bHorizontal || uiBtnsPerLine > 1)
-        tbm.cxButtonSpacing = (3 * GetSystemMetrics(SM_CXEDGE) / 2);
-    else
-        tbm.cxButtonSpacing = 0;
-
-    if (!bHorizontal || uiRows > 1)
-        tbm.cyButtonSpacing = (3 * GetSystemMetrics(SM_CYEDGE) / 2);
-    else
-        tbm.cyButtonSpacing = 0;
-
-    SendMessage(This->hWndToolbar,
-                TB_SETMETRICS,
-                0,
-                (LPARAM)&tbm);
-
-    return tbm.cxButtonSpacing;
-}
-
-
-static VOID
-TaskSwitchWnd_UpdateButtonsSize(IN OUT PTASK_SWITCH_WND This,
-                                IN BOOL bRedrawDisabled)
-{
-    RECT rcClient;
-    UINT uiRows, uiMax, uiMin, uiBtnsPerLine, ui;
-    LONG NewBtnSize;
-    BOOL Horizontal;
-    TBBUTTONINFO tbbi;
-    TBMETRICS tbm;
-
-    if (GetClientRect(This->hWnd,
-                      &rcClient) &&
-        !IsRectEmpty(&rcClient))
-    {
-        if (This->ToolbarBtnCount > 0)
-        {
-            ZeroMemory (&tbm, sizeof (tbm));
-            tbm.cbSize = sizeof(tbm);
-            tbm.dwMask = TBMF_BUTTONSPACING;
-            SendMessage(This->hWndToolbar,
-                        TB_GETMETRICS,
-                        0,
-                        (LPARAM)&tbm);
-
-            uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (This->ButtonSize.cy + tbm.cyButtonSpacing);
-            if (uiRows == 0)
-                uiRows = 1;
-
-            uiBtnsPerLine = (This->ToolbarBtnCount + uiRows - 1) / uiRows;
-
-            Horizontal = ITrayWindow_IsHorizontal(This->Tray);
-
-            if (!bRedrawDisabled)
-                TaskSwitchWnd_BeginUpdate(This);
-
-            /* We might need to update the button spacing */
-            tbm.cxButtonSpacing = TaskSwitchWnd_UpdateTbButtonSpacing(This,
-                                                                      Horizontal,
-                                                                      uiRows,
-                                                                      uiBtnsPerLine);
-
-            /* Calculate the ideal width and make sure it's within the allowed range */
-            NewBtnSize = (rcClient.right - (uiBtnsPerLine * tbm.cxButtonSpacing)) / uiBtnsPerLine;
-
-            /* Determine the minimum and maximum width of a button */
-            if (Horizontal)
-                uiMax = GetSystemMetrics(SM_CXMINIMIZED);
-            else
-                uiMax = rcClient.right;
-
-            uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE));
-
-            if (NewBtnSize < (LONG)uiMin)
-                NewBtnSize = uiMin;
-            if (NewBtnSize > (LONG)uiMax)
-                NewBtnSize = uiMax;
-
-            This->ButtonSize.cx = NewBtnSize;
-
-            /* Recalculate how many buttons actually fit into one line */
-            uiBtnsPerLine = rcClient.right / (NewBtnSize + tbm.cxButtonSpacing);
-            if (uiBtnsPerLine == 0)
-                uiBtnsPerLine++;
-            This->TbButtonsPerLine = uiBtnsPerLine;
-
-            tbbi.cbSize = sizeof(tbbi);
-            tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE;
-            tbbi.cx = (INT)NewBtnSize;
-
-            for (ui = 0; ui != This->ToolbarBtnCount; ui++)
-            {
-                tbbi.fsState = TBSTATE_ENABLED;
-
-                /* 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 ((ui + 1) % uiBtnsPerLine == 0)
-                    tbbi.fsState |= TBSTATE_WRAP;
-
-                if (This->ActiveTaskItem != NULL &&
-                    This->ActiveTaskItem->Index == ui)
-                {
-                    tbbi.fsState |= TBSTATE_CHECKED;
-                }
-
-                SendMessage(This->hWndToolbar,
-                            TB_SETBUTTONINFO,
-                            (WPARAM)ui,
-                            (LPARAM)&tbbi);
-            }
-
-#if 0
-            /* FIXME: Force the window to the correct position in case some idiot
-                      did something to us */
-            SetWindowPos(This->hWndToolbar,
-                         NULL,
-                         0,
-                         0,
-                         rcClient.right, /* FIXME */
-                         rcClient.bottom, /* FIXME */
-                         SWP_NOACTIVATE | SWP_NOZORDER);
-#endif
-        }
-        else
-        {
-            This->TbButtonsPerLine = 0;
-            This->ButtonSize.cx = 0;
-        }
-    }
-
-    TaskSwitchWnd_EndUpdate(This);
-}
-
-static BOOL CALLBACK
-TaskSwitchWnd_EnumWindowsProc(IN HWND hWnd,
-                              IN LPARAM lParam)
-{
-    PTASK_SWITCH_WND This = (PTASK_SWITCH_WND)lParam;
-
-    /* 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) &&
-        !ITrayWindow_IsSpecialHWND(This->Tray, hWnd))
-    {
-        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) &&
-            !(exStyle & WS_EX_TOOLWINDOW))
-        {
-            TaskSwitchWnd_AddTask(This,
-                                  hWnd);
-        }
-    }
-
-    return TRUE;
-}
-
-static LRESULT CALLBACK
-TaskSwitchWnd_ToolbarSubclassedProc(IN HWND hWnd,
-                                   IN UINT msg,
-                                   IN WPARAM wParam,
-                                   IN LPARAM lParam,
-                                   IN UINT_PTR uIdSubclass,
-                                   IN DWORD_PTR dwRefData)
-{
-    LRESULT Ret;
-
-    Ret = DefSubclassProc(hWnd,
-                          msg,
-                          wParam,
-                          lParam);
-
-    if (msg == WM_NCHITTEST && Ret == HTCLIENT)
-    {
-        POINT pt;
-
-        /* See if the mouse is on a button */
-        pt.x = (SHORT)LOWORD(lParam);
-        pt.y = (SHORT)HIWORD(lParam);
-
-        if (MapWindowPoints(HWND_DESKTOP,
-                            hWnd,
-                            &pt,
-                            1) != 0 &&
-            (INT)SendMessage(hWnd,
-                             TB_HITTEST,
-                             0,
-                             (LPARAM)&pt) < 0)
-        {
-            /* Make the control appear to be transparent outside of any buttons */
-            Ret = HTTRANSPARENT;
-        }
-    }
-
-    return Ret;
-}
-
-static VOID
-TaskSwitchWnd_UpdateTheme(IN OUT PTASK_SWITCH_WND This)
-{
-    if (This->TaskBandTheme)
-        CloseThemeData(This->TaskBandTheme);
-
-    if (IsThemeActive())
-        This->TaskBandTheme = OpenThemeData(This->hWnd, L"TaskBand");
-    else
-        This->TaskBandTheme = NULL;
-}
-
-static VOID
-TaskSwitchWnd_Create(IN OUT PTASK_SWITCH_WND This)
-{
-    This->hWndToolbar = CreateWindowEx(0,
-                                       TOOLBARCLASSNAME,
-                                       szRunningApps,
-                                       WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
-                                       TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT |
-                                       CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER,
-                                       0,
-                                       0,
-                                       0,
-                                       0,
-                                       This->hWnd,
-                                       NULL,
-                                       hExplorerInstance,
-                                       NULL);
-
-    if (This->hWndToolbar != NULL)
-    {
-        HMODULE hShell32;
-        SIZE BtnSize;
-
-        SetWindowTheme(This->hWndToolbar, L"TaskBand", NULL);
-        TaskSwitchWnd_UpdateTheme(This);
-        /* Identify the version we're using */
-        SendMessage(This->hWndToolbar,
-                    TB_BUTTONSTRUCTSIZE,
-                    sizeof(TBBUTTON),
-                    0);
-
-        This->TaskIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000);
-        SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->TaskIcons);
-
-        /* Calculate the default button size. Don't save this in This->ButtonSize.cx so that
-           the actual button width gets updated correctly on the first recalculation */
-        BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED);
-        This->ButtonSize.cy = BtnSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
-        SendMessage(This->hWndToolbar,
-                    TB_SETBUTTONSIZE,
-                    0,
-                    (LPARAM)MAKELONG(BtnSize.cx,
-                                     BtnSize.cy));
-
-        /* We don't want to see partially clipped buttons...not that we could see them... */
-#if 0
-        SendMessage(This->hWndToolbar,
-                    TB_SETEXTENDEDSTYLE,
-                    0,
-                    TBSTYLE_EX_HIDECLIPPEDBUTTONS);
-#endif
-
-        /* Set proper spacing between buttons */
-        TaskSwitchWnd_UpdateTbButtonSpacing(This,
-                                            ITrayWindow_IsHorizontal(This->Tray),
-                                            0,
-                                            0);
-
-        /* Register the shell hook */
-        This->ShellHookMsg = RegisterWindowMessage(TEXT("SHELLHOOK"));
-        hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-        if (hShell32 != NULL)
-        {
-            REGSHELLHOOK RegShellHook;
-
-            /* RegisterShellHook */
-            RegShellHook = (REGSHELLHOOK)GetProcAddress(hShell32,
-                                                        (LPCSTR)((LONG)181));
-            if (RegShellHook != NULL)
-            {
-                RegShellHook(This->hWnd,
-                             3); /* 1 if no NT! We're targeting NT so we don't care! */
-            }
-        }
-
-        /* Add all windows to the toolbar */
-        EnumWindows(TaskSwitchWnd_EnumWindowsProc,
-                    (LPARAM)This);
-
-        /* Recalculate the button size */
-        TaskSwitchWnd_UpdateButtonsSize(This,
-                                        FALSE);
-
-        /* Subclass the toolbar control because it doesn't provide a
-           NM_NCHITTEST notification */
-        This->IsToolbarSubclassed = SetWindowSubclass(This->hWndToolbar,
-                                                      TaskSwitchWnd_ToolbarSubclassedProc,
-                                                      TSW_TOOLBAR_SUBCLASS_ID,
-                                                      (DWORD_PTR)This);
-    }
-}
-
-static VOID
-TaskSwitchWnd_NCDestroy(IN OUT PTASK_SWITCH_WND This)
-{
-    HMODULE hShell32;
-
-    This->IsDestroying = TRUE;
-
-    /* Unregister the shell hook */
-    hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-    if (hShell32 != NULL)
-    {
-        REGSHELLHOOK RegShellHook;
-
-        /* RegisterShellHook */
-        RegShellHook = (REGSHELLHOOK)GetProcAddress(hShell32,
-                                                    (LPCSTR)((LONG)181));
-        if (RegShellHook != NULL)
-        {
-            RegShellHook(This->hWnd,
-                         FALSE);
-        }
-    }
-
-    CloseThemeData(This->TaskBandTheme);
-    TaskSwitchWnd_DeleteAllTasks(This);
-}
-
-static BOOL
-TaskSwitchWnd_HandleAppCommand(IN OUT PTASK_SWITCH_WND This,
-                               IN WPARAM wParam,
-                               IN LPARAM lParam)
-{
-    BOOL Ret = FALSE;
-
-    switch (GET_APPCOMMAND_LPARAM(lParam))
-    {
-        case APPCOMMAND_BROWSER_SEARCH:
-            Ret = SHFindFiles(NULL,
-                              NULL);
-            break;
-
-        case APPCOMMAND_BROWSER_HOME:
-        case APPCOMMAND_LAUNCH_MAIL:
-        default:
-            TRACE("Shell app command %d unhandled!\n", (INT)GET_APPCOMMAND_LPARAM(lParam));
-            break;
-    }
-
-    return Ret;
-}
-
-
-static LRESULT
-TaskSwitchWnd_HandleShellHookMsg(IN OUT PTASK_SWITCH_WND This,
-                                 IN WPARAM wParam,
-                                 IN LPARAM lParam)
-{
-    BOOL Ret = FALSE;
-
-    switch ((INT)wParam)
-    {
-        case HSHELL_APPCOMMAND:
-            TaskSwitchWnd_HandleAppCommand(This,
-                                           wParam,
-                                           lParam);
-            Ret = TRUE;
-            break;
-
-        case HSHELL_WINDOWCREATED:
-            Ret = TaskSwitchWnd_AddTask(This,
-                                  (HWND)lParam);
-            break;
-
-        case HSHELL_WINDOWDESTROYED:
-            /* The window still exists! Delay destroying it a bit */
-            TaskSwitchWnd_DeleteTask(This, (HWND)lParam);
-            Ret = TRUE;
-            break;
-
-        case HSHELL_RUDEAPPACTIVATED:
-        case HSHELL_WINDOWACTIVATED:
-            if (lParam)
-            {
-                TaskSwitchWnd_ActivateTask(This, (HWND) lParam);
-                Ret = TRUE;
-            }
-            break;
-
-        case HSHELL_GETMINRECT:
-            goto UnhandledShellMessage;
-
-        case HSHELL_FLASH:
-            TaskSwitchWnd_FlashTask(This,
-                                    (HWND)lParam);
-            Ret = TRUE;
-            break;
-
-        case HSHELL_REDRAW:
-            TaskSwitchWnd_RedrawTask(This,
-                                     (HWND)lParam);
-            Ret = TRUE;
-            break;
-
-        case HSHELL_TASKMAN:
-            PostMessage(ITrayWindow_GetHWND(This->Tray), TWM_OPENSTARTMENU,0, 0);
-            break;
-
-        case HSHELL_ACTIVATESHELLWINDOW:
-        case HSHELL_LANGUAGE:
-        case HSHELL_SYSMENU:
-        case HSHELL_ENDTASK:
-        case HSHELL_ACCESSIBILITYSTATE:
-        case HSHELL_WINDOWREPLACED:
-        case HSHELL_WINDOWREPLACING:
-        default:
-        {
-            static const struct {
-                INT msg;
-                LPCWSTR msg_name;
-            } hshell_msg[] = {
-                {HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED"},
-                {HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED"},
-                {HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW"},
-                {HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED"},
-                {HSHELL_GETMINRECT, L"HSHELL_GETMINRECT"},
-                {HSHELL_REDRAW, L"HSHELL_REDRAW"},
-                {HSHELL_TASKMAN, L"HSHELL_TASKMAN"},
-                {HSHELL_LANGUAGE, L"HSHELL_LANGUAGE"},
-                {HSHELL_SYSMENU, L"HSHELL_SYSMENU"},
-                {HSHELL_ENDTASK, L"HSHELL_ENDTASK"},
-                {HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE"},
-                {HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND"},
-                {HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED"},
-                {HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING"},
-                {HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED"},
-            };
-            int i, found;
-UnhandledShellMessage:
-            for (i = 0, found = 0; i != sizeof(hshell_msg) / sizeof(hshell_msg[0]); i++)
-            {
-                if (hshell_msg[i].msg == (INT)wParam)
-                {
-                    TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam);
-                    found = 1;
-                    break;
-                }
-            }
-            if (!found)
-            {
-                TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT)wParam, lParam);
-            }
-            break;
-        }
-    }
-
-    return Ret;
-}
-
-static VOID
-TaskSwitchWnd_EnableGrouping(IN OUT PTASK_SWITCH_WND This,
-                             IN BOOL bEnable)
-{
-    This->IsGroupingEnabled = bEnable;
-
-    /* Collapse or expand groups if neccessary */
-    TaskSwitchWnd_UpdateButtonsSize(This,
-                                    FALSE);
-}
-
-static VOID
-TaskSwitchWnd_HandleTaskItemClick(IN OUT PTASK_SWITCH_WND This,
-                                  IN OUT PTASK_ITEM TaskItem)
-{
-    BOOL bIsMinimized;
-    BOOL bIsActive;
-
-    if (IsWindow(TaskItem->hWnd))
-    {
-        bIsMinimized = IsIconic(TaskItem->hWnd);
-        bIsActive = (TaskItem == This->ActiveTaskItem);
-
-        TRACE("Active TaskItem %p, selected TaskItem %p\n", This->ActiveTaskItem, TaskItem);
-        if (This->ActiveTaskItem)
-            TRACE("Active TaskItem hWnd=%p, TaskItem hWnd %p\n", This->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);
-            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");
-        }
-    }
-}
-
-static VOID
-TaskSwitchWnd_HandleTaskGroupClick(IN OUT PTASK_SWITCH_WND This,
-                                   IN OUT PTASK_GROUP TaskGroup)
-{
-    /* TODO: Show task group menu */
-}
-
-static BOOL
-TaskSwitchWnd_HandleButtonClick(IN OUT PTASK_SWITCH_WND This,
-                                IN WORD wIndex)
-{
-    PTASK_ITEM TaskItem;
-    PTASK_GROUP TaskGroup;
-
-    if (This->IsGroupingEnabled)
-    {
-        TaskGroup = FindTaskGroupByIndex(This,
-                                         (INT)wIndex);
-        if (TaskGroup != NULL && TaskGroup->IsCollapsed)
-        {
-            TaskSwitchWnd_HandleTaskGroupClick(This,
-                                               TaskGroup);
-            return TRUE;
-        }
-    }
-
-    TaskItem = FindTaskItemByIndex(This,
-                                   (INT)wIndex);
-    if (TaskItem != NULL)
-    {
-        TaskSwitchWnd_HandleTaskItemClick(This,
-                                          TaskItem);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-
-static VOID
-TaskSwitchWnd_HandleTaskItemRightClick(IN OUT PTASK_SWITCH_WND This,
-                                  IN OUT PTASK_ITEM TaskItem)
-{
-
-    HMENU hmenu = GetSystemMenu(TaskItem->hWnd, FALSE);
-
-    if (hmenu) {
-        POINT pt;
-        int cmd;
-        GetCursorPos(&pt);
-        cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON|TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, This->hWndToolbar, NULL);
-        if (cmd) {
-            SetForegroundWindow(TaskItem->hWnd);    // reactivate window after the context menu has closed
-            PostMessage(TaskItem->hWnd, WM_SYSCOMMAND, cmd, 0);
-        }
-    }
-}
-
-static VOID
-TaskSwitchWnd_HandleTaskGroupRightClick(IN OUT PTASK_SWITCH_WND This,
-                                   IN OUT PTASK_GROUP TaskGroup)
-{
-    /* TODO: Show task group right click menu */
-}
-
-static BOOL
-TaskSwitchWnd_HandleButtonRightClick(IN OUT PTASK_SWITCH_WND This,
-                                IN WORD wIndex)
-{
-    PTASK_ITEM TaskItem;
-    PTASK_GROUP TaskGroup;
-     if (This->IsGroupingEnabled)
-    {
-       TaskGroup = FindTaskGroupByIndex(This,
-                                         (INT)wIndex);
-        if (TaskGroup != NULL && TaskGroup->IsCollapsed)
-        {
-            TaskSwitchWnd_HandleTaskGroupRightClick(This,
-                                               TaskGroup);
-            return TRUE;
-        }
-    }
-
-    TaskItem = FindTaskItemByIndex(This,
-                                   (INT)wIndex);
-
-    if (TaskItem != NULL)
-    {
-        TaskSwitchWnd_HandleTaskItemRightClick(This,
-                                          TaskItem);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-
-static LRESULT
-TaskSwitchWnd_HandleItemPaint(IN OUT PTASK_SWITCH_WND This,
-                             IN OUT NMTBCUSTOMDRAW *nmtbcd)
-{
-    LRESULT Ret = CDRF_DODEFAULT;
-    PTASK_GROUP TaskGroup;
-    PTASK_ITEM TaskItem;
-
-    TaskItem = FindTaskItemByIndex(This,
-                                   (INT)nmtbcd->nmcd.dwItemSpec);
-    TaskGroup = FindTaskGroupByIndex(This,
-                                     (INT)nmtbcd->nmcd.dwItemSpec);
-    if (TaskGroup == NULL && TaskItem != NULL)
-    {
-        ASSERT(TaskItem != NULL);
-
-        if (TaskItem != NULL && IsWindow(TaskItem->hWnd))
-        {
-            /* Make the entire button flashing if neccessary */
-            if (nmtbcd->nmcd.uItemState & CDIS_MARKED)
-            {
-                Ret = TBCDRF_NOBACKGROUND;
-                if (!This->TaskBandTheme)
-                {
-                    SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT));
-                    Rectangle(nmtbcd->nmcd.hdc,
-                              nmtbcd->nmcd.rc.left,
-                              nmtbcd->nmcd.rc.top,
-                              nmtbcd->nmcd.rc.right,
-                              nmtbcd->nmcd.rc.bottom);
-                }
-                else
-                {
-                    DrawThemeBackground(This->TaskBandTheme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0);
-                }
-                nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
-                return Ret;
-            }
-        }
-    }
-    else if (TaskGroup != NULL)
-    {
-        /* FIXME: Implement painting for task groups */
-    }
-    return Ret;
-}
-
-static LRESULT
-TaskSwitchWnd_HandleToolbarNotification(IN OUT PTASK_SWITCH_WND This,
-                                        IN const NMHDR *nmh)
-{
-    LRESULT Ret = 0;
-
-    switch (nmh->code)
-    {
-        case NM_CUSTOMDRAW:
-        {
-            LPNMTBCUSTOMDRAW nmtbcd = (LPNMTBCUSTOMDRAW)nmh;
-
-            switch (nmtbcd->nmcd.dwDrawStage)
-            {
-
-                case CDDS_ITEMPREPAINT:
-                    Ret = TaskSwitchWnd_HandleItemPaint(This,
-                                                       nmtbcd);
-                    break;
-
-                case CDDS_PREPAINT:
-                    Ret = CDRF_NOTIFYITEMDRAW;
-                    break;
-
-                default:
-                    Ret = CDRF_DODEFAULT;
-                    break;
-            }
-            break;
-        }
-    }
-
-    return Ret;
-}
-
-static VOID
-TaskSwitchWnd_DrawBackground(HWND hwnd,
-                             HDC hdc)
-{
-    RECT rect;
-
-    GetClientRect(hwnd, &rect);
-    DrawThemeParentBackground(hwnd, hdc, &rect);
-}
-
-static LRESULT CALLBACK
-TaskSwitchWndProc(IN HWND hwnd,
-                  IN UINT uMsg,
-                  IN WPARAM wParam,
-                  IN LPARAM lParam)
-{
-    PTASK_SWITCH_WND This = NULL;
-    LRESULT Ret = FALSE;
-
-    if (uMsg != WM_NCCREATE)
-    {
-        This = (PTASK_SWITCH_WND)GetWindowLongPtr(hwnd, 0);
-    }
-
-    if (This != NULL || uMsg == WM_NCCREATE)
-    {
-        switch (uMsg)
-        {
-            case WM_THEMECHANGED:
-                TaskSwitchWnd_UpdateTheme(This);
-                break;
-            case WM_ERASEBKGND:
-                if (!This->TaskBandTheme)
-                    break;
-                TaskSwitchWnd_DrawBackground(hwnd, (HDC) wParam);
-                return TRUE;
-            case WM_SIZE:
-            {
-                SIZE szClient;
-
-                szClient.cx = LOWORD(lParam);
-                szClient.cy = HIWORD(lParam);
-                if (This->hWndToolbar != NULL)
-                {
-                    SetWindowPos(This->hWndToolbar,
-                                 NULL,
-                                 0,
-                                 0,
-                                 szClient.cx,
-                                 szClient.cy,
-                                 SWP_NOZORDER);
-
-                    TaskSwitchWnd_UpdateButtonsSize(This, FALSE);
-                }
-                break;
-            }
-
-            case WM_NCHITTEST:
-            {
-                /* We want the tray window to be draggable everywhere, so make the control
-                   appear transparent */
-                Ret = DefWindowProc(hwnd, uMsg, wParam, lParam);
-                if (Ret != HTVSCROLL && Ret != HTHSCROLL)
-                    return HTTRANSPARENT;
-                return Ret;
-            }
-
-            case WM_COMMAND:
-            {
-                if (lParam != 0 && (HWND)lParam == This->hWndToolbar)
-                {
-                    TaskSwitchWnd_HandleButtonClick(This, LOWORD(wParam));
-                }
-                break;
-            }
-
-            case WM_NOTIFY:
-            {
-                const NMHDR *nmh = (const NMHDR *)lParam;
-
-                if (nmh->hwndFrom == This->hWndToolbar)
-                {
-                    return TaskSwitchWnd_HandleToolbarNotification(This, nmh);
-                }
-                return 0;
-            }
-
-            case TSWM_ENABLEGROUPING:
-            {
-                Ret = This->IsGroupingEnabled;
-                if (wParam != This->IsGroupingEnabled)
-                {
-                    TaskSwitchWnd_EnableGrouping(This,
-                                                 (BOOL)wParam);
-                }
-                return Ret;
-            }
-
-            case TSWM_UPDATETASKBARPOS:
-            {
-                /* Update the button spacing */
-                TaskSwitchWnd_UpdateTbButtonSpacing(This, ITrayWindow_IsHorizontal(This->Tray), 0, 0);
-                break;
-            }
-
-            case WM_CONTEXTMENU:
-            {
-                if (This->hWndToolbar != NULL)
-                {
-                    POINT pt;
-                    INT_PTR iBtn;
-
-                    pt.x = (LONG)LOWORD(lParam);
-                    pt.y = (LONG)HIWORD(lParam);
-
-                    MapWindowPoints(NULL, This->hWndToolbar, &pt, 1);
-
-                    iBtn = (INT_PTR) SendMessage(This->hWndToolbar, TB_HITTEST, 0, (LPARAM) &pt);
-                    if (iBtn >= 0)
-                    {
-                        TaskSwitchWnd_HandleButtonRightClick(This, iBtn);
-                    }
-                    else
-                        goto ForwardContextMenuMsg;
-                }
-                else
-                {
-ForwardContextMenuMsg:
-                    /* Forward message */
-                    Ret = SendMessage(ITrayWindow_GetHWND(This->Tray), uMsg, wParam, lParam);
-                }
-                break;
-            }
-
-            case WM_NCCREATE:
-            {
-                LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
-                This = HeapAlloc(hProcessHeap,
-                                 HEAP_ZERO_MEMORY,
-                                 sizeof(*This));
-                if (This == NULL)
-                    return FALSE;
-
-                This->hWnd = hwnd;
-                This->hWndNotify = CreateStruct->hwndParent;
-                This->Tray = (ITrayWindow*)CreateStruct->lpCreateParams;
-                This->IsGroupingEnabled = TRUE; /* FIXME */
-                SetWindowLongPtr(hwnd,
-                                 0,
-                                 (LONG_PTR)This);
-
-                return TRUE;
-            }
-
-            case WM_CREATE:
-                TaskSwitchWnd_Create(This);
-
-#if DUMP_TASKS != 0
-                SetTimer(hwnd, 1, 5000, NULL);
-#endif
-
-                break;
-
-            case WM_DESTROY:
-                if (This->IsToolbarSubclassed)
-                {
-                    if (RemoveWindowSubclass(This->hWndToolbar,
-                                             TaskSwitchWnd_ToolbarSubclassedProc,
-                                             TSW_TOOLBAR_SUBCLASS_ID))
-                    {
-                        This->IsToolbarSubclassed = FALSE;
-                    }
-                }
-                break;
-
-            case WM_NCDESTROY:
-                TaskSwitchWnd_NCDestroy(This);
-                HeapFree(hProcessHeap, 0, This);
-                SetWindowLongPtr(hwnd, 0, 0);
-                break;
-
-#if DUMP_TASKS != 0
-            case WM_TIMER:
-                switch (wParam)
-                {
-                    case 1:
-                        TaskSwitchWnd_DumpTasks(This);
-                        break;
-                }
-                break;
-#endif
-
-            case WM_KLUDGEMINRECT:
-            {
-                PTASK_ITEM TaskItem = TaskSwitchWnd_FindTaskItem(This, (HWND)wParam);
-                if (TaskItem)
-                {
-                    RECT* prcMinRect = (RECT*)lParam;
-                    RECT rcItem, rcToolbar;
-                    SendMessageW(This->hWndToolbar,TB_GETITEMRECT, TaskItem->Index, (LPARAM)&rcItem);
-                    GetWindowRect(This->hWndToolbar, &rcToolbar);
-
-                    OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top);
-
-                    *prcMinRect = rcItem;
-                    return TRUE;
-                }
-                return FALSE;
-            }
-
-            default:
-/* HandleDefaultMessage: */
-                if (uMsg == This->ShellHookMsg && This->ShellHookMsg != 0)
-                {
-                    /* Process shell messages */
-                    return (LRESULT) TaskSwitchWnd_HandleShellHookMsg(This, wParam, lParam);
-                }
-
-                break;
-        }
-    }
-
-    return DefWindowProc(hwnd, uMsg, wParam, lParam);
-}
-
-
-HWND
-CreateTaskSwitchWnd(IN HWND hWndParent,
-                    IN OUT ITrayWindow *Tray)
-{
-    HWND hwndTaskBar;
-
-    hwndTaskBar = CreateWindowEx(0,
-                                 szTaskSwitchWndClass,
-                                 szRunningApps,
-                                 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP,
-                                 0,
-                                 0,
-                                 0,
-                                 0,
-                                 hWndParent,
-                                 NULL,
-                                 hExplorerInstance,
-                                 (LPVOID)Tray);
-
-    return hwndTaskBar;
-}
-
-BOOL
-RegisterTaskSwitchWndClass(VOID)
-{
-    WNDCLASS wc;
-
-    wc.style = CS_DBLCLKS;
-    wc.lpfnWndProc = TaskSwitchWndProc;
-    wc.cbClsExtra = 0;
-    wc.cbWndExtra = sizeof(PTASK_SWITCH_WND);
-    wc.hInstance = hExplorerInstance;
-    wc.hIcon = NULL;
-    wc.hCursor = LoadCursor(NULL,
-                            IDC_ARROW);
-    wc.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
-    wc.lpszMenuName = NULL;
-    wc.lpszClassName = szTaskSwitchWndClass;
-
-    return RegisterClass(&wc) != 0;
-}
-
-VOID
-UnregisterTaskSwitchWndClass(VOID)
-{
-    UnregisterClass(szTaskSwitchWndClass,
-                    hExplorerInstance);
-}
diff --git a/base/shell/explorer-new/taskswnd.cpp b/base/shell/explorer-new/taskswnd.cpp
new file mode 100644 (file)
index 0000000..0956ba4
--- /dev/null
@@ -0,0 +1,2079 @@
+/*
+ * ReactOS Explorer
+ *
+ * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#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
+
+const WCHAR szTaskSwitchWndClass [] = TEXT("MSTaskSwWClass");
+const WCHAR szRunningApps [] = TEXT("Running Applications");
+
+const struct {
+    INT msg;
+    LPCWSTR msg_name;
+} hshell_msg [] = {
+        { HSHELL_WINDOWCREATED, L"HSHELL_WINDOWCREATED" },
+        { HSHELL_WINDOWDESTROYED, L"HSHELL_WINDOWDESTROYED" },
+        { HSHELL_ACTIVATESHELLWINDOW, L"HSHELL_ACTIVATESHELLWINDOW" },
+        { HSHELL_WINDOWACTIVATED, L"HSHELL_WINDOWACTIVATED" },
+        { HSHELL_GETMINRECT, L"HSHELL_GETMINRECT" },
+        { HSHELL_REDRAW, L"HSHELL_REDRAW" },
+        { HSHELL_TASKMAN, L"HSHELL_TASKMAN" },
+        { HSHELL_LANGUAGE, L"HSHELL_LANGUAGE" },
+        { HSHELL_SYSMENU, L"HSHELL_SYSMENU" },
+        { HSHELL_ENDTASK, L"HSHELL_ENDTASK" },
+        { HSHELL_ACCESSIBILITYSTATE, L"HSHELL_ACCESSIBILITYSTATE" },
+        { HSHELL_APPCOMMAND, L"HSHELL_APPCOMMAND" },
+        { HSHELL_WINDOWREPLACED, L"HSHELL_WINDOWREPLACED" },
+        { HSHELL_WINDOWREPLACING, L"HSHELL_WINDOWREPLACING" },
+        { HSHELL_RUDEAPPACTIVATED, L"HSHELL_RUDEAPPACTIVATED" },
+};
+
+typedef struct _TASK_GROUP
+{
+    /* We have to use a linked list instead of an array so we don't have to
+       update all pointers to groups in the task item array when removing
+       groups. */
+    struct _TASK_GROUP *Next;
+
+    DWORD dwTaskCount;
+    DWORD dwProcessId;
+    INT Index;
+    union
+    {
+        DWORD dwFlags;
+        struct
+        {
+
+            DWORD IsCollapsed : 1;
+        };
+    };
+} TASK_GROUP, *PTASK_GROUP;
+
+typedef struct _TASK_ITEM
+{
+    HWND hWnd;
+    PTASK_GROUP Group;
+    INT Index;
+    INT IconIndex;
+
+
+
+    union
+    {
+        DWORD dwFlags;
+        struct
+        {
+
+            /* IsFlashing is TRUE when the task bar item should be flashing. */
+            DWORD IsFlashing : 1;
+
+            /* RenderFlashed is only TRUE if the task bar item should be
+               drawn with a flash. */
+            DWORD RenderFlashed : 1;
+        };
+    };
+} TASK_ITEM, *PTASK_ITEM;
+
+#define TASK_ITEM_ARRAY_ALLOC   64
+
+class CTaskSwitchWnd :
+    public CWindowImpl < CTaskSwitchWnd, CWindow, CControlWinTraits >
+{
+    CContainedWindow TaskBar;
+
+    HWND hWndNotify;
+
+    UINT ShellHookMsg;
+    CComPtr<ITrayWindow> Tray;
+
+    PTASK_GROUP TaskGroups;
+
+    WORD TaskItemCount;
+    WORD AllocatedTaskItems;
+    PTASK_ITEM TaskItems;
+    PTASK_ITEM ActiveTaskItem;
+
+    HTHEME TaskBandTheme;
+    HWND hWndToolbar;
+    UINT TbButtonsPerLine;
+    WORD ToolbarBtnCount;
+
+    IImageList * TaskIcons;
+
+    BOOL IsGroupingEnabled;
+    BOOL IsDestroying;
+
+    SIZE ButtonSize;
+    WCHAR szBuf[255];
+
+public:
+    CTaskSwitchWnd() :
+        TaskBar(this, 1),
+        hWndNotify(NULL),
+        ShellHookMsg(NULL),
+        TaskGroups(NULL),
+        TaskItemCount(0),
+        AllocatedTaskItems(0),
+        TaskItems(0),
+        ActiveTaskItem(0),
+        TaskBandTheme(NULL),
+        hWndToolbar(NULL),
+        TbButtonsPerLine(0),
+        ToolbarBtnCount(0),
+        TaskIcons(NULL)
+    {
+        ZeroMemory(&ButtonSize, sizeof(ButtonSize));
+        szBuf[0] = 0;
+    }
+    virtual ~CTaskSwitchWnd() { }
+
+#define MAX_TASKS_COUNT (0x7FFF)
+
+    VOID TaskSwitchWnd_UpdateButtonsSize(
+        IN BOOL bRedrawDisabled);
+
+    LPTSTR GetWndTextFromTaskItem(
+        IN PTASK_ITEM TaskItem)
+    {
+        /* 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;
+    }
+
+
+#if DUMP_TASKS != 0
+    VOID DumpTasks()
+    {
+        PTASK_GROUP CurrentGroup;
+        PTASK_ITEM CurrentTaskItem, LastTaskItem;
+
+        TRACE("Tasks dump:\n");
+        if (IsGroupingEnabled)
+        {
+            CurrentGroup = 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;
+                while (CurrentTaskItem != LastTaskItem)
+                {
+                    if (CurrentTaskItem->Group == CurrentGroup)
+                    {
+                        TRACE("  + Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
+                    }
+                    CurrentTaskItem++;
+                }
+
+                CurrentGroup = CurrentGroup->Next;
+            }
+
+            CurrentTaskItem = TaskItems;
+            LastTaskItem = CurrentTaskItem + TaskItemCount;
+            while (CurrentTaskItem != LastTaskItem)
+            {
+                if (CurrentTaskItem->Group == NULL)
+                {
+                    TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
+                }
+                CurrentTaskItem++;
+            }
+        }
+        else
+        {
+            CurrentTaskItem = TaskItems;
+            LastTaskItem = CurrentTaskItem + TaskItemCount;
+            while (CurrentTaskItem != LastTaskItem)
+            {
+                TRACE("- Task hwnd: 0x%p Index: %d\n", CurrentTaskItem->hWnd, CurrentTaskItem->Index);
+                CurrentTaskItem++;
+            }
+        }
+    }
+#endif
+
+    VOID BeginUpdate()
+    {
+        ::SendMessage(hWndToolbar,
+            WM_SETREDRAW,
+            FALSE,
+            0);
+    }
+
+    VOID EndUpdate()
+    {
+        ::SendMessage(hWndToolbar,
+            WM_SETREDRAW,
+            TRUE,
+            0);
+        ::InvalidateRect(hWndToolbar,
+            NULL,
+            TRUE);
+    }
+
+    BOOL SetToolbarButtonCommandId(
+        IN INT iButtonIndex,
+        IN INT iCommandId)
+    {
+        TBBUTTONINFO tbbi;
+
+        tbbi.cbSize = sizeof(tbbi);
+        tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
+        tbbi.idCommand = iCommandId;
+
+        return SendMessage(hWndToolbar,
+            TB_SETBUTTONINFO,
+            (WPARAM) iButtonIndex,
+            (LPARAM) &tbbi) != 0;
+    }
+
+    VOID UpdateIndexesAfterButtonInserted(
+        IN INT iIndex)
+    {
+        PTASK_GROUP CurrentGroup;
+        PTASK_ITEM CurrentTaskItem, LastTaskItem;
+        INT NewIndex;
+
+        if (IsGroupingEnabled)
+        {
+            /* Update all affected groups */
+            CurrentGroup = TaskGroups;
+            while (CurrentGroup != NULL)
+            {
+                if (CurrentGroup->IsCollapsed &&
+                    CurrentGroup->Index >= iIndex)
+                {
+                    /* Update the toolbar buttons */
+                    NewIndex = CurrentGroup->Index + 1;
+                    if (SetToolbarButtonCommandId(
+                        CurrentGroup->Index + 1,
+                        NewIndex))
+                    {
+                        CurrentGroup->Index = NewIndex;
+                    }
+                    else
+                        CurrentGroup->Index = -1;
+                }
+
+                CurrentGroup = CurrentGroup->Next;
+            }
+        }
+
+        /* Update all affected task items */
+        CurrentTaskItem = TaskItems;
+        LastTaskItem = CurrentTaskItem + TaskItemCount;
+        while (CurrentTaskItem != LastTaskItem)
+        {
+            CurrentGroup = CurrentTaskItem->Group;
+            if (CurrentGroup != NULL)
+            {
+                if (!CurrentGroup->IsCollapsed &&
+                    CurrentTaskItem->Index >= iIndex)
+                {
+                    goto UpdateTaskItemBtn;
+                }
+            }
+            else if (CurrentTaskItem->Index >= iIndex)
+            {
+            UpdateTaskItemBtn:
+                /* Update the toolbar buttons */
+                NewIndex = CurrentTaskItem->Index + 1;
+                if (SetToolbarButtonCommandId(
+                    CurrentTaskItem->Index + 1,
+                    NewIndex))
+                {
+                    CurrentTaskItem->Index = NewIndex;
+                }
+                else
+                    CurrentTaskItem->Index = -1;
+            }
+
+            CurrentTaskItem++;
+        }
+    }
+
+    VOID UpdateIndexesAfterButtonDeleted(
+        IN INT iIndex)
+    {
+        PTASK_GROUP CurrentGroup;
+        PTASK_ITEM CurrentTaskItem, LastTaskItem;
+        INT NewIndex;
+
+        if (IsGroupingEnabled)
+        {
+            /* Update all affected groups */
+            CurrentGroup = TaskGroups;
+            while (CurrentGroup != NULL)
+            {
+                if (CurrentGroup->IsCollapsed &&
+                    CurrentGroup->Index > iIndex)
+                {
+                    /* Update the toolbar buttons */
+                    NewIndex = CurrentGroup->Index - 1;
+                    if (SetToolbarButtonCommandId(
+                        CurrentGroup->Index - 1,
+                        NewIndex))
+                    {
+                        CurrentGroup->Index = NewIndex;
+                    }
+                    else
+                        CurrentGroup->Index = -1;
+                }
+
+                CurrentGroup = CurrentGroup->Next;
+            }
+        }
+
+        /* Update all affected task items */
+        CurrentTaskItem = TaskItems;
+        LastTaskItem = CurrentTaskItem + TaskItemCount;
+        while (CurrentTaskItem != LastTaskItem)
+        {
+            CurrentGroup = CurrentTaskItem->Group;
+            if (CurrentGroup != NULL)
+            {
+                if (!CurrentGroup->IsCollapsed &&
+                    CurrentTaskItem->Index > iIndex)
+                {
+                    goto UpdateTaskItemBtn;
+                }
+            }
+            else if (CurrentTaskItem->Index > iIndex)
+            {
+            UpdateTaskItemBtn:
+                /* Update the toolbar buttons */
+                NewIndex = CurrentTaskItem->Index - 1;
+                if (SetToolbarButtonCommandId(
+                    CurrentTaskItem->Index - 1,
+                    NewIndex))
+                {
+                    CurrentTaskItem->Index = NewIndex;
+                }
+                else
+                    CurrentTaskItem->Index = -1;
+            }
+
+            CurrentTaskItem++;
+        }
+    }
+
+    INT UpdateTaskGroupButton(
+        IN PTASK_GROUP TaskGroup)
+    {
+        ASSERT(TaskGroup->Index >= 0);
+
+        /* FIXME: Implement */
+
+        return TaskGroup->Index;
+    }
+
+    VOID ExpandTaskGroup(
+        IN PTASK_GROUP TaskGroup)
+    {
+        ASSERT(TaskGroup->dwTaskCount > 0);
+        ASSERT(TaskGroup->IsCollapsed);
+        ASSERT(TaskGroup->Index >= 0);
+
+        /* FIXME: Implement */
+    }
+
+    HICON GetWndIcon(HWND hwnd)
+    {
+        HICON hIcon = 0;
+
+        SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) &hIcon);
+
+        if (!hIcon)
+            SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) &hIcon);
+
+        if (!hIcon)
+            SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR) &hIcon);
+
+        if (!hIcon)
+            hIcon = (HICON) GetClassLongPtr(hwnd, GCL_HICONSM);
+
+        if (!hIcon)
+            hIcon = (HICON) GetClassLongPtr(hwnd, GCL_HICON);
+
+        return hIcon;
+    }
+    INT UpdateTaskItemButton(IN PTASK_ITEM TaskItem)
+    {
+        TBBUTTONINFO tbbi;
+        HICON icon;
+
+        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)
+            tbbi.fsState |= TBSTATE_CHECKED;
+
+        if (TaskItem->RenderFlashed)
+            tbbi.fsState |= TBSTATE_MARKED;
+
+        /* 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 (TbButtonsPerLine != 0 &&
+            (TaskItem->Index + 1) % TbButtonsPerLine == 0)
+        {
+            tbbi.fsState |= TBSTATE_WRAP;
+        }
+
+        tbbi.pszText = GetWndTextFromTaskItem(
+            TaskItem);
+
+        icon = GetWndIcon(TaskItem->hWnd);
+        TaskIcons->ReplaceIcon(TaskItem->IconIndex, icon, &TaskItem->IconIndex);
+        tbbi.iImage = TaskItem->IconIndex;
+
+        if (!SendMessage(hWndToolbar,
+            TB_SETBUTTONINFO,
+            (WPARAM) TaskItem->Index,
+            (LPARAM) &tbbi))
+        {
+            TaskItem->Index = -1;
+            return -1;
+        }
+
+        TRACE("Updated button %d for hwnd 0x%p\n", TaskItem->Index, TaskItem->hWnd);
+        return TaskItem->Index;
+    }
+
+    VOID RemoveIcon(
+        IN PTASK_ITEM TaskItem)
+    {
+        TBBUTTONINFO tbbi;
+        PTASK_ITEM currentTaskItem, LastItem;
+
+        if (TaskItem->IconIndex == -1)
+            return;
+
+        tbbi.cbSize = sizeof(tbbi);
+        tbbi.dwMask = TBIF_IMAGE;
+
+        currentTaskItem = TaskItems;
+        LastItem = currentTaskItem + TaskItemCount;
+        while (currentTaskItem != LastItem)
+        {
+            if (currentTaskItem->IconIndex > TaskItem->IconIndex)
+            {
+                currentTaskItem->IconIndex--;
+                tbbi.iImage = currentTaskItem->IconIndex;
+
+                SendMessage(hWndToolbar,
+                    TB_SETBUTTONINFO,
+                    currentTaskItem->Index,
+                    (LPARAM) &tbbi);
+            }
+            currentTaskItem++;
+        }
+
+        TaskIcons->Remove(TaskItem->IconIndex);
+    }
+
+    PTASK_ITEM FindLastTaskItemOfGroup(
+        IN PTASK_GROUP TaskGroup  OPTIONAL,
+        IN PTASK_ITEM NewTaskItem  OPTIONAL)
+    {
+        PTASK_ITEM TaskItem, LastTaskItem, FoundTaskItem = NULL;
+        DWORD dwTaskCount;
+
+        ASSERT(IsGroupingEnabled);
+
+        TaskItem = TaskItems;
+        LastTaskItem = TaskItem + TaskItemCount;
+
+        dwTaskCount = (TaskGroup != NULL ? TaskGroup->dwTaskCount : MAX_TASKS_COUNT);
+
+        ASSERT(dwTaskCount > 0);
+
+        while (TaskItem != LastTaskItem)
+        {
+            if (TaskItem->Group == TaskGroup)
+            {
+                if ((NewTaskItem != NULL && TaskItem != NewTaskItem) || NewTaskItem == NULL)
+                {
+                    FoundTaskItem = TaskItem;
+                }
+
+                if (--dwTaskCount == 0)
+                {
+                    /* We found the last task item in the group! */
+                    break;
+                }
+            }
+
+            TaskItem++;
+        }
+
+        return FoundTaskItem;
+    }
+
+    INT CalculateTaskItemNewButtonIndex(
+        IN PTASK_ITEM TaskItem)
+    {
+        PTASK_GROUP TaskGroup;
+        PTASK_ITEM LastTaskItem;
+
+        /* NOTE: This routine assumes that the group is *not* collapsed! */
+
+        TaskGroup = TaskItem->Group;
+        if (IsGroupingEnabled)
+        {
+            if (TaskGroup != NULL)
+            {
+                ASSERT(TaskGroup->Index < 0);
+                ASSERT(!TaskGroup->IsCollapsed);
+
+                if (TaskGroup->dwTaskCount > 1)
+                {
+                    LastTaskItem = FindLastTaskItemOfGroup(
+                        TaskGroup,
+                        TaskItem);
+                    if (LastTaskItem != NULL)
+                    {
+                        /* Since the group is expanded the task items must have an index */
+                        ASSERT(LastTaskItem->Index >= 0);
+
+                        return LastTaskItem->Index + 1;
+                    }
+                }
+            }
+            else
+            {
+                /* Find the last NULL group button. NULL groups are added at the end of the
+                   task item list when grouping is enabled */
+                LastTaskItem = FindLastTaskItemOfGroup(
+                    NULL,
+                    TaskItem);
+                if (LastTaskItem != NULL)
+                {
+                    ASSERT(LastTaskItem->Index >= 0);
+
+                    return LastTaskItem->Index + 1;
+                }
+            }
+        }
+
+        return ToolbarBtnCount;
+    }
+
+    INT AddTaskItemButton(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        TBBUTTON tbBtn;
+        INT iIndex;
+        HICON icon;
+
+        if (TaskItem->Index >= 0)
+        {
+            return UpdateTaskItemButton(
+                TaskItem);
+        }
+
+        if (TaskItem->Group != NULL &&
+            TaskItem->Group->IsCollapsed)
+        {
+            /* The task group is collapsed, we only need to update the group button */
+            return UpdateTaskGroupButton(
+                TaskItem->Group);
+        }
+
+        icon = GetWndIcon(TaskItem->hWnd);
+        TaskIcons->ReplaceIcon(-1, icon, &TaskItem->IconIndex);
+
+        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);
+
+        /* Find out where to insert the new button */
+        iIndex = CalculateTaskItemNewButtonIndex(
+            TaskItem);
+        ASSERT(iIndex >= 0);
+        tbBtn.idCommand = iIndex;
+
+        BeginUpdate();
+
+        if (SendMessage(hWndToolbar,
+            TB_INSERTBUTTON,
+            (WPARAM) iIndex,
+            (LPARAM) &tbBtn))
+        {
+            UpdateIndexesAfterButtonInserted(
+                iIndex);
+
+            TRACE("Added button %d for hwnd 0x%p\n", iIndex, TaskItem->hWnd);
+
+            TaskItem->Index = iIndex;
+            ToolbarBtnCount++;
+
+            /* Update button sizes and fix the button wrapping */
+            UpdateButtonsSize(TRUE);
+            return iIndex;
+        }
+
+        EndUpdate();
+
+        return -1;
+    }
+
+    BOOL DeleteTaskItemButton(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        PTASK_GROUP TaskGroup;
+        INT iIndex;
+
+        TaskGroup = TaskItem->Group;
+
+        if (TaskItem->Index >= 0)
+        {
+            if ((TaskGroup != NULL && !TaskGroup->IsCollapsed) ||
+                TaskGroup == NULL)
+            {
+                BeginUpdate();
+
+                RemoveIcon(TaskItem);
+                iIndex = TaskItem->Index;
+                if (SendMessage(hWndToolbar,
+                    TB_DELETEBUTTON,
+                    (WPARAM) iIndex,
+                    0))
+                {
+                    TaskItem->Index = -1;
+                    ToolbarBtnCount--;
+
+                    UpdateIndexesAfterButtonDeleted(
+                        iIndex);
+
+                    /* Update button sizes and fix the button wrapping */
+                    UpdateButtonsSize(
+                        TRUE);
+                    return TRUE;
+                }
+
+                EndUpdate();
+            }
+        }
+
+        return FALSE;
+    }
+
+    PTASK_GROUP AddToTaskGroup(
+        IN HWND hWnd)
+    {
+        DWORD dwProcessId;
+        PTASK_GROUP TaskGroup, *PrevLink;
+
+        if (!GetWindowThreadProcessId(hWnd,
+            &dwProcessId))
+        {
+            TRACE("Cannot get process id of hwnd 0x%p\n", hWnd);
+            return NULL;
+        }
+
+        /* Try to find an existing task group */
+        TaskGroup = TaskGroups;
+        PrevLink = &TaskGroups;
+        while (TaskGroup != NULL)
+        {
+            if (TaskGroup->dwProcessId == dwProcessId)
+            {
+                TaskGroup->dwTaskCount++;
+                return TaskGroup;
+            }
+
+            PrevLink = &TaskGroup->Next;
+            TaskGroup = TaskGroup->Next;
+        }
+
+        /* Allocate a new task group */
+        TaskGroup = (PTASK_GROUP) HeapAlloc(hProcessHeap,
+            HEAP_ZERO_MEMORY,
+            sizeof(*TaskGroup));
+        if (TaskGroup != NULL)
+        {
+            TaskGroup->dwTaskCount = 1;
+            TaskGroup->dwProcessId = dwProcessId;
+            TaskGroup->Index = -1;
+
+            /* Add the task group to the list */
+            *PrevLink = TaskGroup;
+        }
+
+        return TaskGroup;
+    }
+
+    VOID RemoveTaskFromTaskGroup(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        PTASK_GROUP TaskGroup, CurrentGroup, *PrevLink;
+
+        TaskGroup = TaskItem->Group;
+        if (TaskGroup != NULL)
+        {
+            DWORD dwNewTaskCount = --TaskGroup->dwTaskCount;
+            if (dwNewTaskCount == 0)
+            {
+                /* Find the previous pointer in the chain */
+                CurrentGroup = TaskGroups;
+                PrevLink = &TaskGroups;
+                while (CurrentGroup != TaskGroup)
+                {
+                    PrevLink = &CurrentGroup->Next;
+                    CurrentGroup = CurrentGroup->Next;
+                }
+
+                /* Remove the group from the list */
+                ASSERT(TaskGroup == CurrentGroup);
+                *PrevLink = TaskGroup->Next;
+
+                /* Free the task group */
+                HeapFree(hProcessHeap,
+                    0,
+                    TaskGroup);
+            }
+            else if (TaskGroup->IsCollapsed &&
+                TaskGroup->Index >= 0)
+            {
+                if (dwNewTaskCount > 1)
+                {
+                    /* FIXME: Check if we should expand the group */
+                    /* Update the task group button */
+                    UpdateTaskGroupButton(
+                        TaskGroup);
+                }
+                else
+                {
+                    /* Expand the group of one task button to a task button */
+                    ExpandTaskGroup(
+                        TaskGroup);
+                }
+            }
+        }
+    }
+
+    PTASK_ITEM FindTaskItem(
+        IN HWND hWnd)
+    {
+        PTASK_ITEM TaskItem, LastItem;
+
+        TaskItem = TaskItems;
+        LastItem = TaskItem + TaskItemCount;
+        while (TaskItem != LastItem)
+        {
+            if (TaskItem->hWnd == hWnd)
+                return TaskItem;
+
+            TaskItem++;
+        }
+
+        return NULL;
+    }
+
+    PTASK_ITEM FindOtherTaskItem(
+        IN HWND hWnd)
+    {
+        PTASK_ITEM LastItem, TaskItem;
+        PTASK_GROUP TaskGroup;
+        DWORD dwProcessId;
+
+        if (!GetWindowThreadProcessId(hWnd,
+            &dwProcessId))
+        {
+            return NULL;
+        }
+
+        /* Try to find another task that belongs to the same
+           process as the given window */
+        TaskItem = TaskItems;
+        LastItem = TaskItem + TaskItemCount;
+        while (TaskItem != LastItem)
+        {
+            TaskGroup = TaskItem->Group;
+            if (TaskGroup != NULL)
+            {
+                if (TaskGroup->dwProcessId == dwProcessId)
+                    return TaskItem;
+            }
+            else
+            {
+                DWORD dwProcessIdTask;
+
+                if (GetWindowThreadProcessId(TaskItem->hWnd,
+                    &dwProcessIdTask) &&
+                    dwProcessIdTask == dwProcessId)
+                {
+                    return TaskItem;
+                }
+            }
+
+            TaskItem++;
+        }
+
+        return NULL;
+    }
+
+    PTASK_ITEM AllocTaskItem()
+    {
+        if (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);
+
+        if (TaskItemCount == 0)
+        {
+            TaskItems = (PTASK_ITEM) HeapAlloc(hProcessHeap,
+                0,
+                TASK_ITEM_ARRAY_ALLOC * sizeof(*TaskItems));
+            if (TaskItems != NULL)
+            {
+                AllocatedTaskItems = TASK_ITEM_ARRAY_ALLOC;
+            }
+            else
+                return NULL;
+        }
+        else if (TaskItemCount >= AllocatedTaskItems)
+        {
+            PTASK_ITEM NewArray;
+            SIZE_T NewArrayLength, ActiveTaskItemIndex;
+
+            NewArrayLength = AllocatedTaskItems + TASK_ITEM_ARRAY_ALLOC;
+
+            NewArray = (PTASK_ITEM) HeapReAlloc(hProcessHeap,
+                0,
+                TaskItems,
+                NewArrayLength * sizeof(*TaskItems));
+            if (NewArray != NULL)
+            {
+                if (ActiveTaskItem != NULL)
+                {
+                    /* Fixup the ActiveTaskItem pointer */
+                    ActiveTaskItemIndex = ActiveTaskItem - TaskItems;
+                    ActiveTaskItem = NewArray + ActiveTaskItemIndex;
+                }
+                AllocatedTaskItems = (WORD) NewArrayLength;
+                TaskItems = NewArray;
+            }
+            else
+                return NULL;
+        }
+
+        return TaskItems + TaskItemCount++;
+    }
+
+    VOID FreeTaskItem(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        WORD wIndex;
+
+        if (TaskItem == ActiveTaskItem)
+            ActiveTaskItem = NULL;
+
+        wIndex = (WORD) (TaskItem - TaskItems);
+        if (wIndex + 1 < TaskItemCount)
+        {
+            MoveMemory(TaskItem,
+                TaskItem + 1,
+                (TaskItemCount - wIndex - 1) * sizeof(*TaskItem));
+        }
+
+        TaskItemCount--;
+    }
+
+    VOID DeleteTaskItem(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        if (!IsDestroying)
+        {
+            /* Delete the task button from the toolbar */
+            DeleteTaskItemButton(
+                TaskItem);
+        }
+
+        /* Remove the task from it's group */
+        RemoveTaskFromTaskGroup(
+            TaskItem);
+
+        /* Free the task item */
+        FreeTaskItem(
+            TaskItem);
+    }
+
+    VOID CheckActivateTaskItem(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        PTASK_ITEM CurrentTaskItem;
+        PTASK_GROUP TaskGroup = NULL;
+
+        CurrentTaskItem = ActiveTaskItem;
+
+        if (TaskItem != NULL)
+            TaskGroup = TaskItem->Group;
+
+        if (IsGroupingEnabled &&
+            TaskGroup != NULL &&
+            TaskGroup->IsCollapsed)
+        {
+            /* FIXME */
+            return;
+        }
+
+        if (CurrentTaskItem != NULL)
+        {
+            PTASK_GROUP CurrentTaskGroup;
+
+            if (CurrentTaskItem == TaskItem)
+                return;
+
+            CurrentTaskGroup = CurrentTaskItem->Group;
+
+            if (IsGroupingEnabled &&
+                CurrentTaskGroup != NULL &&
+                CurrentTaskGroup->IsCollapsed)
+            {
+                if (CurrentTaskGroup == TaskGroup)
+                    return;
+
+                /* FIXME */
+            }
+            else
+            {
+                ActiveTaskItem = NULL;
+                if (CurrentTaskItem->Index >= 0)
+                {
+                    UpdateTaskItemButton(CurrentTaskItem);
+                }
+            }
+        }
+
+        ActiveTaskItem = TaskItem;
+
+        if (TaskItem != NULL && TaskItem->Index >= 0)
+        {
+            UpdateTaskItemButton(TaskItem);
+        }
+        else if (TaskItem == NULL)
+        {
+            TRACE("Active TaskItem now NULL\n");
+        }
+    }
+
+    PTASK_ITEM
+        FindTaskItemByIndex(
+        IN INT Index)
+    {
+        PTASK_ITEM TaskItem, LastItem;
+
+        TaskItem = TaskItems;
+        LastItem = TaskItem + TaskItemCount;
+        while (TaskItem != LastItem)
+        {
+            if (TaskItem->Index == Index)
+                return TaskItem;
+
+            TaskItem++;
+        }
+
+        return NULL;
+    }
+
+    PTASK_GROUP
+        FindTaskGroupByIndex(
+        IN INT Index)
+    {
+        PTASK_GROUP CurrentGroup;
+
+        CurrentGroup = TaskGroups;
+        while (CurrentGroup != NULL)
+        {
+            if (CurrentGroup->Index == Index)
+                break;
+
+            CurrentGroup = CurrentGroup->Next;
+        }
+
+        return CurrentGroup;
+    }
+
+    BOOL AddTask(IN HWND hWnd)
+    {
+        PTASK_ITEM TaskItem;
+
+        if (!::IsWindow(hWnd) || Tray->IsSpecialHWND(hWnd))
+            return FALSE;
+
+        TaskItem = FindTaskItem(hWnd);
+        if (TaskItem == NULL)
+        {
+            TRACE("Add window 0x%p\n", hWnd);
+            TaskItem = AllocTaskItem();
+            if (TaskItem != NULL)
+            {
+                ZeroMemory(TaskItem,
+                    sizeof(*TaskItem));
+                TaskItem->hWnd = hWnd;
+                TaskItem->Index = -1;
+                TaskItem->Group = AddToTaskGroup(
+                    hWnd);
+
+                if (!IsDestroying)
+                {
+                    AddTaskItemButton(
+                        TaskItem);
+                }
+            }
+        }
+
+        return TaskItem != NULL;
+    }
+
+    BOOL ActivateTaskItem(
+        IN OUT PTASK_ITEM TaskItem  OPTIONAL)
+    {
+        if (TaskItem != NULL)
+        {
+            TRACE("Activate window 0x%p on button %d\n", TaskItem->hWnd, TaskItem->Index);
+        }
+
+        CheckActivateTaskItem(TaskItem);
+
+        return FALSE;
+    }
+
+    BOOL ActivateTask(
+        IN HWND hWnd)
+    {
+        PTASK_ITEM TaskItem;
+
+        if (!hWnd)
+        {
+            return ActivateTaskItem(NULL);
+        }
+
+        TaskItem = FindTaskItem(
+            hWnd);
+        if (TaskItem == NULL)
+        {
+            TaskItem = FindOtherTaskItem(
+                hWnd);
+        }
+
+        if (TaskItem == NULL)
+        {
+            WARN("Activate window 0x%p, could not find task\n", hWnd);
+            RefreshWindowList();
+        }
+
+        return ActivateTaskItem(TaskItem);
+    }
+
+    BOOL DeleteTask(
+        IN HWND hWnd)
+    {
+        PTASK_ITEM TaskItem;
+
+        TaskItem = FindTaskItem(
+            hWnd);
+        if (TaskItem != NULL)
+        {
+            TRACE("Delete window 0x%p on button %d\n", hWnd, TaskItem->Index);
+            DeleteTaskItem(
+                TaskItem);
+            return TRUE;
+        }
+        //else
+        //TRACE("Failed to delete window 0x%p\n", hWnd);
+
+        return FALSE;
+    }
+
+    VOID DeleteAllTasks()
+    {
+        PTASK_ITEM CurrentTask;
+
+        if (TaskItemCount > 0)
+        {
+            CurrentTask = TaskItems + TaskItemCount;
+            do
+            {
+                DeleteTaskItem(
+                    --CurrentTask);
+            } while (CurrentTask != TaskItems);
+        }
+    }
+
+    VOID FlashTaskItem(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        TaskItem->RenderFlashed = 1;
+        UpdateTaskItemButton(
+            TaskItem);
+    }
+
+    BOOL FlashTask(
+        IN HWND hWnd)
+    {
+        PTASK_ITEM TaskItem;
+
+        TaskItem = FindTaskItem(
+            hWnd);
+        if (TaskItem != NULL)
+        {
+            TRACE("Flashing window 0x%p on button %d\n", hWnd, TaskItem->Index);
+            FlashTaskItem(
+                TaskItem);
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
+    VOID RedrawTaskItem(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+        PTASK_GROUP TaskGroup;
+
+        TaskGroup = TaskItem->Group;
+        if (IsGroupingEnabled && TaskGroup != NULL)
+        {
+            if (TaskGroup->IsCollapsed && TaskGroup->Index >= 0)
+            {
+                UpdateTaskGroupButton(
+                    TaskGroup);
+            }
+            else if (TaskItem->Index >= 0)
+            {
+                goto UpdateTaskItem;
+            }
+        }
+        else if (TaskItem->Index >= 0)
+        {
+        UpdateTaskItem:
+            TaskItem->RenderFlashed = 0;
+            UpdateTaskItemButton(
+                TaskItem);
+        }
+    }
+
+
+    BOOL RedrawTask(
+        IN HWND hWnd)
+    {
+        PTASK_ITEM TaskItem;
+
+        TaskItem = FindTaskItem(
+            hWnd);
+        if (TaskItem != NULL)
+        {
+            RedrawTaskItem(
+                TaskItem);
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
+    INT UpdateTbButtonSpacing(
+        IN BOOL bHorizontal,
+        IN UINT uiRows,
+        IN UINT uiBtnsPerLine)
+    {
+        TBMETRICS tbm;
+
+        tbm.cbSize = sizeof(tbm);
+        tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
+
+        tbm.cxBarPad = tbm.cyBarPad = 0;
+
+        if (bHorizontal || uiBtnsPerLine > 1)
+            tbm.cxButtonSpacing = (3 * GetSystemMetrics(SM_CXEDGE) / 2);
+        else
+            tbm.cxButtonSpacing = 0;
+
+        if (!bHorizontal || uiRows > 1)
+            tbm.cyButtonSpacing = (3 * GetSystemMetrics(SM_CYEDGE) / 2);
+        else
+            tbm.cyButtonSpacing = 0;
+
+        SendMessage(hWndToolbar,
+            TB_SETMETRICS,
+            0,
+            (LPARAM) &tbm);
+
+        return tbm.cxButtonSpacing;
+    }
+
+
+    VOID UpdateButtonsSize(IN BOOL bRedrawDisabled)
+    {
+        RECT rcClient;
+        UINT uiRows, uiMax, uiMin, uiBtnsPerLine, ui;
+        LONG NewBtnSize;
+        BOOL Horizontal;
+        TBBUTTONINFO tbbi;
+        TBMETRICS tbm;
+
+        if (GetClientRect(&rcClient) &&
+            !IsRectEmpty(&rcClient))
+        {
+            if (ToolbarBtnCount > 0)
+            {
+                ZeroMemory(&tbm, sizeof(tbm));
+                tbm.cbSize = sizeof(tbm);
+                tbm.dwMask = TBMF_BUTTONSPACING;
+                SendMessage(hWndToolbar,
+                    TB_GETMETRICS,
+                    0,
+                    (LPARAM) &tbm);
+
+                uiRows = (rcClient.bottom + tbm.cyButtonSpacing) / (ButtonSize.cy + tbm.cyButtonSpacing);
+                if (uiRows == 0)
+                    uiRows = 1;
+
+                uiBtnsPerLine = (ToolbarBtnCount + uiRows - 1) / uiRows;
+
+                Horizontal = Tray->IsHorizontal();
+
+                if (!bRedrawDisabled)
+                    BeginUpdate();
+
+                /* We might need to update the button spacing */
+                tbm.cxButtonSpacing = UpdateTbButtonSpacing(
+                    Horizontal,
+                    uiRows,
+                    uiBtnsPerLine);
+
+                /* Calculate the ideal width and make sure it's within the allowed range */
+                NewBtnSize = (rcClient.right - (uiBtnsPerLine * tbm.cxButtonSpacing)) / uiBtnsPerLine;
+
+                /* Determine the minimum and maximum width of a button */
+                if (Horizontal)
+                    uiMax = GetSystemMetrics(SM_CXMINIMIZED);
+                else
+                    uiMax = rcClient.right;
+
+                uiMin = GetSystemMetrics(SM_CXSIZE) + (2 * GetSystemMetrics(SM_CXEDGE));
+
+                if (NewBtnSize < (LONG) uiMin)
+                    NewBtnSize = uiMin;
+                if (NewBtnSize > (LONG)uiMax)
+                    NewBtnSize = uiMax;
+
+                ButtonSize.cx = NewBtnSize;
+
+                /* Recalculate how many buttons actually fit into one line */
+                uiBtnsPerLine = rcClient.right / (NewBtnSize + tbm.cxButtonSpacing);
+                if (uiBtnsPerLine == 0)
+                    uiBtnsPerLine++;
+                TbButtonsPerLine = uiBtnsPerLine;
+
+                tbbi.cbSize = sizeof(tbbi);
+                tbbi.dwMask = TBIF_BYINDEX | TBIF_SIZE | TBIF_STATE;
+                tbbi.cx = (INT) NewBtnSize;
+
+                for (ui = 0; ui != ToolbarBtnCount; ui++)
+                {
+                    tbbi.fsState = TBSTATE_ENABLED;
+
+                    /* 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 ((ui + 1) % uiBtnsPerLine == 0)
+                        tbbi.fsState |= TBSTATE_WRAP;
+
+                    if (ActiveTaskItem != NULL &&
+                        ActiveTaskItem->Index == (INT)ui)
+                    {
+                        tbbi.fsState |= TBSTATE_CHECKED;
+                    }
+
+                    SendMessage(hWndToolbar,
+                        TB_SETBUTTONINFO,
+                        (WPARAM) ui,
+                        (LPARAM) &tbbi);
+                }
+
+#if 0
+                /* FIXME: Force the window to the correct position in case some idiot
+                          did something to us */
+                SetWindowPos(hWndToolbar,
+                    NULL,
+                    0,
+                    0,
+                    rcClient.right, /* FIXME */
+                    rcClient.bottom, /* FIXME */
+                    SWP_NOACTIVATE | SWP_NOZORDER);
+#endif
+            }
+            else
+            {
+                TbButtonsPerLine = 0;
+                ButtonSize.cx = 0;
+            }
+            }
+
+        EndUpdate();
+        }
+
+    BOOL CALLBACK EnumWindowsProc(IN HWND hWnd)
+    {
+        /* 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))
+        {
+            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) &&
+                !(exStyle & WS_EX_TOOLWINDOW))
+            {
+                TRACE("Adding task for %p...\n", hWnd);
+                AddTask(hWnd);
+            }
+
+        }
+
+        return TRUE;
+    }
+
+    static BOOL CALLBACK s_EnumWindowsProc(IN HWND hWnd,
+        IN LPARAM lParam)
+    {
+        CTaskSwitchWnd * This = (CTaskSwitchWnd *) lParam;
+
+        return This->EnumWindowsProc(hWnd);
+    }
+
+    BOOL RefreshWindowList()
+    {
+        TRACE("Refreshing window list...\n");
+        /* Add all windows to the toolbar */
+        return EnumWindows(s_EnumWindowsProc, (LPARAM)this);
+    }
+
+    LRESULT OnThemeChanged()
+    {
+        if (TaskBandTheme)
+            CloseThemeData(TaskBandTheme);
+
+        if (IsThemeActive())
+            TaskBandTheme = OpenThemeData(m_hWnd, L"TaskBand");
+        else
+            TaskBandTheme = 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)
+    {
+        hWndToolbar = CreateWindowEx(0,
+            TOOLBARCLASSNAME,
+            szRunningApps,
+            WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
+            TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_LIST | TBSTYLE_TRANSPARENT |
+            CCS_TOP | CCS_NORESIZE | CCS_NODIVIDER,
+            0,
+            0,
+            0,
+            0,
+            m_hWnd,
+            NULL,
+            hExplorerInstance,
+            NULL);
+
+        if (hWndToolbar != NULL)
+        {
+            HMODULE hShell32;
+            SIZE BtnSize;
+
+            TaskBar.SubclassWindow(hWndToolbar);
+
+            SetWindowTheme(hWndToolbar, L"TaskBand", NULL);
+            OnThemeChanged();
+
+            /* Identify the version we're using */
+            SendMessage(hWndToolbar,
+                TB_BUTTONSTRUCTSIZE,
+                sizeof(TBBUTTON),
+                0);
+
+            TaskIcons = (IImageList*) ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000);
+            SendMessage(hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM) 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 */
+            BtnSize.cx = GetSystemMetrics(SM_CXMINIMIZED);
+            ButtonSize.cy = BtnSize.cy = GetSystemMetrics(SM_CYSIZE) + (2 * GetSystemMetrics(SM_CYEDGE));
+            SendMessage(hWndToolbar, TB_SETBUTTONSIZE, 0, (LPARAM) MAKELONG(BtnSize.cx, BtnSize.cy));
+
+            /* We don't want to see partially clipped buttons...not that we could see them... */
+#if 0
+            SendMessage(hWndToolbar,
+                TB_SETEXTENDEDSTYLE,
+                0,
+                TBSTYLE_EX_HIDECLIPPEDBUTTONS);
+#endif
+
+            /* Set proper spacing between buttons */
+            UpdateTbButtonSpacing(Tray->IsHorizontal(), 0, 0);
+
+            /* Register the shell hook */
+            ShellHookMsg = RegisterWindowMessage(TEXT("SHELLHOOK"));
+
+            DbgPrint("ShellHookMsg got assigned number %d\n", ShellHookMsg);
+
+            hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
+            if (hShell32 != NULL)
+            {
+                REGSHELLHOOK RegShellHook;
+
+                /* 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! */
+                }
+            }
+
+            RefreshWindowList();
+
+            /* Recalculate the button size */
+            UpdateButtonsSize(FALSE);
+        }
+
+#if DUMP_TASKS != 0
+        SetTimer(hwnd, 1, 5000, NULL);
+#endif
+        return TRUE;
+    }
+
+    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HMODULE hShell32;
+
+        IsDestroying = TRUE;
+
+        /* Unregister the shell hook */
+        hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
+        if (hShell32 != NULL)
+        {
+            REGSHELLHOOK RegShellHook;
+
+            /* RegisterShellHook */
+            RegShellHook = (REGSHELLHOOK) GetProcAddress(hShell32,
+                (LPCSTR) ((LONG) 181));
+            if (RegShellHook != NULL)
+            {
+                RegShellHook(m_hWnd,
+                    FALSE);
+            }
+        }
+
+        CloseThemeData(TaskBandTheme);
+        DeleteAllTasks();
+        return TRUE;
+    }
+
+    BOOL HandleAppCommand(
+        IN WPARAM wParam,
+        IN LPARAM lParam)
+    {
+        BOOL Ret = FALSE;
+
+        switch (GET_APPCOMMAND_LPARAM(lParam))
+        {
+        case APPCOMMAND_BROWSER_SEARCH:
+            Ret = SHFindFiles(NULL,
+                NULL);
+            break;
+
+        case APPCOMMAND_BROWSER_HOME:
+        case APPCOMMAND_LAUNCH_MAIL:
+        default:
+            TRACE("Shell app command %d unhandled!\n", (INT) GET_APPCOMMAND_LPARAM(lParam));
+            break;
+        }
+
+        return Ret;
+    }
+    
+    LRESULT HandleShellHookMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        BOOL Ret = FALSE;
+
+        /* In case the shell hook wasn't registered properly, ignore WM_NULLs*/
+        if (uMsg == 0)
+        {
+            bHandled = FALSE;
+            return 0;
+        }
+
+        DbgPrint("Received shell hook message: wParam=%08lx, lParam=%08lx\n", wParam, lParam);
+
+        switch ((INT) wParam)
+        {
+        case HSHELL_APPCOMMAND:
+            HandleAppCommand(
+                wParam,
+                lParam);
+            Ret = TRUE;
+            break;
+
+        case HSHELL_WINDOWCREATED:
+            Ret = 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;
+            }
+            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);
+            break;
+
+        case HSHELL_ACTIVATESHELLWINDOW:
+        case HSHELL_LANGUAGE:
+        case HSHELL_SYSMENU:
+        case HSHELL_ENDTASK:
+        case HSHELL_ACCESSIBILITYSTATE:
+        case HSHELL_WINDOWREPLACED:
+        case HSHELL_WINDOWREPLACING:
+
+        case HSHELL_GETMINRECT:
+        default:
+        {
+            int i, found;
+            for (i = 0, found = 0; i != sizeof(hshell_msg) / sizeof(hshell_msg[0]); i++)
+            {
+                if (hshell_msg[i].msg == (INT) wParam)
+                {
+                    TRACE("Shell message %ws unhandled (lParam = 0x%p)!\n", hshell_msg[i].msg_name, lParam);
+                    found = 1;
+                    break;
+                }
+            }
+            if (!found)
+            {
+                TRACE("Shell message %d unhandled (lParam = 0x%p)!\n", (INT) wParam, lParam);
+            }
+            break;
+        }
+        }
+
+        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;
+        BOOL bIsActive;
+
+        if (::IsWindow(TaskItem->hWnd))
+        {
+            bIsMinimized = IsIconic(TaskItem->hWnd);
+            bIsActive = (TaskItem == 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("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);
+                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");
+            }
+        }
+    }
+
+    VOID HandleTaskGroupClick(
+        IN OUT PTASK_GROUP TaskGroup)
+    {
+        /* TODO: Show task group menu */
+    }
+
+    BOOL HandleButtonClick(
+        IN WORD wIndex)
+    {
+        PTASK_ITEM TaskItem;
+        PTASK_GROUP TaskGroup;
+
+        if (IsGroupingEnabled)
+        {
+            TaskGroup = FindTaskGroupByIndex((INT) wIndex);
+            if (TaskGroup != NULL && TaskGroup->IsCollapsed)
+            {
+                HandleTaskGroupClick(
+                    TaskGroup);
+                return TRUE;
+            }
+        }
+
+        TaskItem = FindTaskItemByIndex((INT) wIndex);
+        if (TaskItem != NULL)
+        {
+            HandleTaskItemClick(
+                TaskItem);
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
+
+    VOID HandleTaskItemRightClick(
+        IN OUT PTASK_ITEM TaskItem)
+    {
+
+        HMENU hmenu = GetSystemMenu(TaskItem->hWnd, FALSE);
+
+        if (hmenu) {
+            POINT pt;
+            int cmd;
+            GetCursorPos(&pt);
+            cmd = TrackPopupMenu(hmenu, TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hWndToolbar, NULL);
+            if (cmd) {
+                SetForegroundWindow(TaskItem->hWnd);    // reactivate window after the context menu has closed
+                PostMessage(TaskItem->hWnd, WM_SYSCOMMAND, cmd, 0);
+            }
+        }
+    }
+
+    VOID HandleTaskGroupRightClick(
+        IN OUT PTASK_GROUP TaskGroup)
+    {
+        /* TODO: Show task group right click menu */
+    }
+
+    BOOL HandleButtonRightClick(
+        IN WORD wIndex)
+    {
+        PTASK_ITEM TaskItem;
+        PTASK_GROUP TaskGroup;
+        if (IsGroupingEnabled)
+        {
+            TaskGroup = FindTaskGroupByIndex((INT) wIndex);
+            if (TaskGroup != NULL && TaskGroup->IsCollapsed)
+            {
+                HandleTaskGroupRightClick(
+                    TaskGroup);
+                return TRUE;
+            }
+        }
+
+        TaskItem = FindTaskItemByIndex((INT) wIndex);
+
+        if (TaskItem != NULL)
+        {
+            HandleTaskItemRightClick(
+                TaskItem);
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
+
+    LRESULT HandleItemPaint(IN OUT NMTBCUSTOMDRAW *nmtbcd)
+    {
+        LRESULT Ret = CDRF_DODEFAULT;
+        PTASK_GROUP TaskGroup;
+        PTASK_ITEM TaskItem;
+
+        TaskItem = FindTaskItemByIndex((INT) nmtbcd->nmcd.dwItemSpec);
+        TaskGroup = FindTaskGroupByIndex((INT) nmtbcd->nmcd.dwItemSpec);
+        if (TaskGroup == NULL && TaskItem != NULL)
+        {
+            ASSERT(TaskItem != NULL);
+
+            if (TaskItem != NULL && ::IsWindow(TaskItem->hWnd))
+            {
+                /* Make the entire button flashing if neccessary */
+                if (nmtbcd->nmcd.uItemState & CDIS_MARKED)
+                {
+                    Ret = TBCDRF_NOBACKGROUND;
+                    if (!TaskBandTheme)
+                    {
+                        SelectObject(nmtbcd->nmcd.hdc, GetSysColorBrush(COLOR_HIGHLIGHT));
+                        Rectangle(nmtbcd->nmcd.hdc,
+                            nmtbcd->nmcd.rc.left,
+                            nmtbcd->nmcd.rc.top,
+                            nmtbcd->nmcd.rc.right,
+                            nmtbcd->nmcd.rc.bottom);
+                    }
+                    else
+                    {
+                        DrawThemeBackground(TaskBandTheme, nmtbcd->nmcd.hdc, TDP_FLASHBUTTON, 0, &nmtbcd->nmcd.rc, 0);
+                    }
+                    nmtbcd->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+                    return Ret;
+                }
+            }
+        }
+        else if (TaskGroup != NULL)
+        {
+            /* FIXME: Implement painting for task groups */
+        }
+        return Ret;
+    }
+
+    LRESULT HandleToolbarNotification(IN const NMHDR *nmh)
+    {
+        LRESULT Ret = 0;
+
+        switch (nmh->code)
+        {
+        case NM_CUSTOMDRAW:
+        {
+            LPNMTBCUSTOMDRAW nmtbcd = (LPNMTBCUSTOMDRAW) nmh;
+
+            switch (nmtbcd->nmcd.dwDrawStage)
+            {
+
+            case CDDS_ITEMPREPAINT:
+                Ret = HandleItemPaint(
+                    nmtbcd);
+                break;
+
+            case CDDS_PREPAINT:
+                Ret = CDRF_NOTIFYITEMDRAW;
+                break;
+
+            default:
+                Ret = CDRF_DODEFAULT;
+                break;
+            }
+            break;
+        }
+        }
+
+        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;
+
+        if (!IsAppThemed())
+        {
+            bHandled = FALSE;
+            return 0;
+        }
+
+        return DrawBackground(hdc);
+    }
+
+    LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        SIZE szClient;
+
+        szClient.cx = LOWORD(lParam);
+        szClient.cy = HIWORD(lParam);
+        if (hWndToolbar != NULL)
+        {
+            ::SetWindowPos(hWndToolbar,
+                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;
+        /* We want the tray window to be draggable everywhere, so make the control
+        appear transparent */
+        Ret = DefWindowProc(uMsg, wParam, lParam);
+        if (Ret != HTVSCROLL && Ret != HTHSCROLL)
+            Ret = HTTRANSPARENT;
+        return Ret;
+    }
+
+    LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        LRESULT Ret = TRUE;
+        if (lParam != 0 && (HWND) lParam == hWndToolbar)
+        {
+            HandleButtonClick(
+                LOWORD(wParam));
+        }
+        return Ret;
+    }
+
+    LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        LRESULT Ret = TRUE;
+        const NMHDR *nmh = (const NMHDR *) lParam;
+
+        if (nmh->hwndFrom == hWndToolbar)
+        {
+            Ret = HandleToolbarNotification(
+                nmh);
+        }
+        return Ret;
+    }
+
+    LRESULT OnEnableGrouping(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+