[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)
 
 PROJECT(SHELL)
 
-add_definitions(-DWIN32)
+set_cpp(WITH_RUNTIME)
+
+include_directories(${REACTOS_SOURCE_DIR}/lib/atl)
 
 list(APPEND SOURCE
 
 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)
     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)
 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_pch(explorer precomp.h SOURCE)
+
 add_cd_file(TARGET explorer DESTINATION reactos FOR all)
 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 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;
 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);
 
     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;
 
     if (!SUCCEEDED(hRet))
         return 1;
 
-    hDesktop = SHCreateDesktop(pSdt);
+    hDesktop = _SHCreateDesktop(pSdt);
 
 
-    IShellDesktopTray_Release(pSdt);
     if (hDesktop == NULL)
         return 1;
 
     if (hDesktop == NULL)
         return 1;
 
-    (void)InterlockedExchangePointer(&DeskCreateInfo->hDesktop,
-                                     hDesktop);
+    (void)InterlockedExchangePointer(&DeskCreateInfo->hDesktop, hDesktop);
 
     if (!SetEvent(DeskCreateInfo->hEvent))
     {
 
     if (!SetEvent(DeskCreateInfo->hEvent))
     {
@@ -59,7 +58,7 @@ DesktopThreadProc(IN OUT LPVOID lpParameter)
         return 1;
     }
 
         return 1;
     }
 
-    SHDesktopMessageLoop(hDesktop);
+    _SHDesktopMessageLoop(hDesktop);
 
     /* FIXME: Properly rundown the main thread! */
     ExitProcess(0);
 
     /* 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_
 
 #ifndef _EXPLORER_PRECOMP__H_
 #define _EXPLORER_PRECOMP__H_
 
+#define WIN7_COMPAT_MODE 0
+
 #include <stdio.h>
 #include <tchar.h>
 
 #include <stdio.h>
 #include <tchar.h>
 
@@ -16,6 +18,9 @@
 #include <wingdi.h>
 #include <winnls.h>
 #include <wincon.h>
 #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>
 #include <shellapi.h>
 #include <shlobj.h>
 #include <shlobj_undoc.h>
@@ -24,6 +29,7 @@
 #include <uxtheme.h>
 #include <strsafe.h>
 #include <undocuser.h>
 #include <uxtheme.h>
 #include <strsafe.h>
 #include <undocuser.h>
+#include <undocshell.h>
 
 #include "tmschema.h"
 #include "resource.h"
 
 #include "tmschema.h"
 #include "resource.h"
 WINE_DEFAULT_DEBUG_CHANNEL(explorernew);
 
 /* dynamic imports due to lack of support in msvc linker libs */
 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"
 #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
 #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 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. */
 
 
 /* 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); \
 #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;
 
 extern HINSTANCE hExplorerInstance;
 extern HMODULE hUser32;
@@ -103,33 +73,33 @@ extern DRAWCAPTEMP DrawCapTemp;
 
 typedef struct _DROPTARGET_CALLBACKS
 {
 
 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 PVOID Context,
+                          IN const FORMATETC *Format,
                           IN DWORD grfKeyState,
                           IN POINTL pt,
                           IN OUT DWORD *pdwEffect);
                           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,
 } 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
 
 /*
  * explorer.c
@@ -139,46 +109,44 @@ CreateDropTarget(IN HWND hwndTarget,
 
 LONG
 SetWindowStyle(IN HWND hWnd,
 
 LONG
 SetWindowStyle(IN HWND hWnd,
-               IN LONG dwStyleMask,
-               IN LONG dwStyle);
+IN LONG dwStyleMask,
+IN LONG dwStyle);
 
 LONG
 SetWindowExStyle(IN HWND hWnd,
 
 LONG
 SetWindowExStyle(IN HWND hWnd,
-                 IN LONG dwStyleMask,
-                 IN LONG dwStyle);
+IN LONG dwStyleMask,
+IN LONG dwStyle);
 
 HMENU
 LoadPopupMenu(IN HINSTANCE hInstance,
 
 HMENU
 LoadPopupMenu(IN HINSTANCE hInstance,
-              IN LPCTSTR lpMenuName);
+IN LPCTSTR lpMenuName);
 
 HMENU
 FindSubMenu(IN HMENU hMenu,
 
 HMENU
 FindSubMenu(IN HMENU hMenu,
-            IN UINT uItem,
-            IN BOOL fByPosition);
+IN UINT uItem,
+IN BOOL fByPosition);
 
 BOOL
 GetCurrentLoggedOnUserName(OUT LPTSTR szBuffer,
 
 BOOL
 GetCurrentLoggedOnUserName(OUT LPTSTR szBuffer,
-                           IN DWORD dwBufferSize);
+IN DWORD dwBufferSize);
 
 BOOL
 FormatMenuString(IN HMENU hMenu,
 
 BOOL
 FormatMenuString(IN HMENU hMenu,
-                 IN UINT uPosition,
-                 IN UINT uFlags,
-                 ...);
+IN UINT uPosition,
+IN UINT uFlags,
+...);
 
 BOOL
 GetExplorerRegValueSet(IN HKEY hKey,
 
 BOOL
 GetExplorerRegValueSet(IN HKEY hKey,
-                       IN LPCTSTR lpSubKey,
-                       IN LPCTSTR lpValue);
+IN LPCTSTR lpSubKey,
+IN LPCTSTR lpValue);
 
 /*
  *  rshell.c
  */
 
 
 /*
  *  rshell.c
  */
 
-HRESULT
-CStartMenu_Constructor(
-    REFIID riid,
-    void **ppv);
+HRESULT WINAPI
+_CStartMenu_Constructor(REFIID riid, void **ppv);
 
 /*
  * traywnd.c
 
 /*
  * traywnd.c
@@ -186,13 +154,13 @@ CStartMenu_Constructor(
 
 #define TWM_OPENSTARTMENU (WM_USER + 260)
 
 
 #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
 {
 
 typedef struct _TRAYWINDOW_CTXMENU
 {
@@ -203,22 +171,22 @@ typedef struct _TRAYWINDOW_CTXMENU
 extern const GUID IID_IShellDesktopTray;
 
 #define INTERFACE ITrayWindow
 extern const GUID IID_IShellDesktopTray;
 
 #define INTERFACE ITrayWindow
-DECLARE_INTERFACE_(ITrayWindow,IUnknown)
+DECLARE_INTERFACE_(ITrayWindow, IUnknown)
 {
     /*** IUnknown methods ***/
 {
     /*** 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 ***/
     /*** 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
 
 };
 #undef INTERFACE
 
@@ -245,8 +213,7 @@ RegisterTrayWindowClass(VOID);
 VOID
 UnregisterTrayWindowClass(VOID);
 
 VOID
 UnregisterTrayWindowClass(VOID);
 
-ITrayWindow *
-CreateTrayWindow(VOID);
+HRESULT CreateTrayWindow(ITrayWindow ** ppTray);
 
 VOID
 TrayProcessMessages(IN OUT ITrayWindow *Tray);
 
 VOID
 TrayProcessMessages(IN OUT ITrayWindow *Tray);
@@ -259,20 +226,21 @@ TrayMessageLoop(IN OUT ITrayWindow *Tray);
  */
 
 /* Structure to hold non-default options*/
  */
 
 /* Structure to hold non-default options*/
-typedef struct _ADVANCED_SETTINGS {
+typedef struct _ADVANCED_SETTINGS
+{
     BOOL bShowSeconds;
 } ADVANCED_SETTINGS, *PADVANCED_SETTINGS;
 
 extern ADVANCED_SETTINGS AdvancedSettings;
     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,
 
 VOID
 LoadAdvancedSettings(VOID);
 
 BOOL
 SaveSettingDword(IN PCTSTR pszKeyName,
-                 IN PCTSTR pszValueName,
-                 IN DWORD dwValue);
+IN PCTSTR pszValueName,
+IN DWORD dwValue);
 
 /*
  * startup.c
 
 /*
  * startup.c
@@ -305,14 +273,14 @@ DesktopDestroyShellWindow(IN HANDLE hDesktop);
 extern const GUID CLSID_ITaskBand;
 
 #define INTERFACE ITaskBand
 extern const GUID CLSID_ITaskBand;
 
 #define INTERFACE ITaskBand
-DECLARE_INTERFACE_(ITaskBand,IUnknown)
+DECLARE_INTERFACE_(ITaskBand, IUnknown)
 {
     /*** IUnknown methods ***/
 {
     /*** 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 ***/
     /*** ITaskBand methods ***/
-    STDMETHOD_(HRESULT,GetRebarBandID)(THIS_ DWORD *pdwBandID) PURE;
+    STDMETHOD_(HRESULT, GetRebarBandID)(THIS_ DWORD *pdwBandID) PURE;
 };
 #undef INTERFACE
 
 };
 #undef INTERFACE
 
@@ -333,20 +301,20 @@ CreateTaskBand(IN OUT ITrayWindow *Tray);
  */
 
 #define INTERFACE ITrayBandSite
  */
 
 #define INTERFACE ITrayBandSite
-DECLARE_INTERFACE_(ITrayBandSite,IUnknown)
+DECLARE_INTERFACE_(ITrayBandSite, IUnknown)
 {
     /*** IUnknown methods ***/
 {
     /*** 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 ***/
     /*** 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 ***/
     /*** 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
 
 };
 #undef INTERFACE
 
@@ -367,8 +335,8 @@ DECLARE_INTERFACE_(ITrayBandSite,IUnknown)
 
 ITrayBandSite *
 CreateTrayBandSite(IN OUT ITrayWindow *Tray,
 
 ITrayBandSite *
 CreateTrayBandSite(IN OUT ITrayWindow *Tray,
-                   OUT HWND *phWndRebar,
-                   OUT HWND *phWndTaskSwitch);
+OUT HWND *phWndRebar,
+OUT HWND *phWndTaskSwitch);
 
 /*
  * startmnu.c
 
 /*
  * startmnu.c
@@ -377,12 +345,12 @@ CreateTrayBandSite(IN OUT ITrayWindow *Tray,
 extern const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu;
 
 #define INTERFACE IStartMenuSite
 extern const TRAYWINDOW_CTXMENU StartMenuBtnCtxMenu;
 
 #define INTERFACE IStartMenuSite
-DECLARE_INTERFACE_(IStartMenuSite,IUnknown)
+DECLARE_INTERFACE_(IStartMenuSite, IUnknown)
 {
     /*** IUnknown methods ***/
 {
     /*** 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
     /*** IStartMenuSite ***/
 };
 #undef INTERFACE
@@ -397,14 +365,14 @@ DECLARE_INTERFACE_(IStartMenuSite,IUnknown)
 
 IMenuPopup*
 CreateStartMenu(IN ITrayWindow *Tray,
 
 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,
 
 HRESULT
 UpdateStartMenu(IN OUT IMenuPopup *pMenuPopup,
-                IN HBITMAP hbmBanner  OPTIONAL,
-                IN BOOL bSmallIcons);
+IN HBITMAP hbmBanner  OPTIONAL,
+IN BOOL bSmallIcons);
 
 /*
  * trayntfy.c
 
 /*
  * trayntfy.c
@@ -431,16 +399,14 @@ UnregisterTrayNotifyWndClass(VOID);
 
 HWND
 CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow,
 
 HWND
 CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow,
-                    IN BOOL bHideClock);
+IN BOOL bHideClock);
 
 VOID
 
 VOID
-TrayNotify_NotifyMsg(IN HWND hwnd,
-                     IN WPARAM wParam,
-                     IN LPARAM lParam);
+TrayNotify_NotifyMsg(IN WPARAM wParam,
+IN LPARAM lParam);
 
 BOOL
 
 BOOL
-TrayNotify_GetClockRect(IN HWND hwnd,
-                        OUT PRECT rcClock);
+TrayNotify_GetClockRect(OUT PRECT rcClock);
 
 /*
  * taskswnd.c
 
 /*
  * taskswnd.c
@@ -457,9 +423,12 @@ UnregisterTaskSwitchWndClass(VOID);
 
 HWND
 CreateTaskSwitchWnd(IN HWND hWndParent,
 
 HWND
 CreateTaskSwitchWnd(IN HWND hWndParent,
-                    IN OUT ITrayWindow *Tray);
+IN OUT ITrayWindow *Tray);
 
 HRESULT
 Tray_OnStartMenuDismissed();
 
 
 HRESULT
 Tray_OnStartMenuDismissed();
 
+HRESULT
+IsSameObject(IN IUnknown *punk1, IN IUnknown *punk2);
+
 #endif /* _EXPLORER_PRECOMP__H_ */
 #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);
 
 
 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)
     {
 {
     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,
                             NULL,
                             CLSCTX_INPROC_SERVER,
                             riid,
@@ -49,7 +49,7 @@ HRESULT CStartMenu_Constructor(REFIID riid, void **ppv)
 
 typedef HANDLE(WINAPI * PSHCREATEDESKTOP)(IShellDesktopTray *ShellDesk);
 
 
 typedef HANDLE(WINAPI * PSHCREATEDESKTOP)(IShellDesktopTray *ShellDesk);
 
-HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
+HANDLE WINAPI _SHCreateDesktop(IShellDesktopTray *ShellDesk)
 {
     HINSTANCE hFallback;
 
 {
     HINSTANCE hFallback;
 
@@ -83,7 +83,7 @@ HANDLE WINAPI SHCreateDesktop(IShellDesktopTray *ShellDesk)
 
 typedef BOOL(WINAPI *PSHDESKTOPMESSAGELOOP)(HANDLE hDesktop);
 
 
 typedef BOOL(WINAPI *PSHDESKTOPMESSAGELOOP)(HANDLE hDesktop);
 
-BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
+BOOL WINAPI _SHDesktopMessageLoop(HANDLE hDesktop)
 {
     HINSTANCE hFallback;
 
 {
     HINSTANCE hFallback;
 
@@ -117,7 +117,7 @@ BOOL WINAPI SHDesktopMessageLoop(HANDLE hDesktop)
 
 typedef DWORD(WINAPI* PWINLIST_INIT)(void);
 
 
 typedef DWORD(WINAPI* PWINLIST_INIT)(void);
 
-DWORD WINAPI WinList_Init(void)
+DWORD WINAPI _WinList_Init(void)
 {
     HINSTANCE hFallback;
 
 {
     HINSTANCE hFallback;
 
@@ -151,7 +151,7 @@ DWORD WINAPI WinList_Init(void)
 
 typedef void (WINAPI *PSHELLDDEINIT)(BOOL bInit);
 
 
 typedef void (WINAPI *PSHELLDDEINIT)(BOOL bInit);
 
-void WINAPI ShellDDEInit(BOOL bInit)
+void WINAPI _ShellDDEInit(BOOL bInit)
 {
     HINSTANCE hFallback;
 
 {
     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;
 #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)
 
 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)
 {
 
 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);
     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)
 {
     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);
     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)
 {
     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);
     TRACE("Releasing SSO %p\n", pOct);
-    IUnknown_Release(pOct);
+    pOct->Release();
     return TRUE;
 }
 
     return TRUE;
 }
 
@@ -92,14 +92,14 @@ HRESULT InitShellServices(HDPA * phdpa)
         }
 
         hr = CLSIDFromString(value, &clsid);
         }
 
         hr = CLSIDFromString(value, &clsid);
-        if (FAILED(hr))
+        if (FAILED_UNEXPECTEDLY(hr))
         {
             ERR("CLSIDFromString failed %08x.\n", hr);
             goto cleanup;
         }
 
         {
             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;
         {
             ERR("CoCreateInstance failed %08x.\n", hr);
             goto cleanup;
@@ -122,7 +122,7 @@ HRESULT InitShellServices(HDPA * phdpa)
 
     /* Initialize */
     DPA_EnumCallback(hdpa, InitializeAllCallback, &hr);
 
     /* Initialize */
     DPA_EnumCallback(hdpa, InitializeAllCallback, &hr);
-    if (FAILED(hr))
+    if (FAILED_UNEXPECTEDLY(hr))
         goto cleanup;
 
     *phdpa = hdpa;
         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;
     }
 
         goto end;
     }
 
-    szCmdLine = HeapAlloc(hProcessHeap,
+    szCmdLine = (WCHAR*)HeapAlloc(hProcessHeap,
                           0,
                           cbMaxCmdLine);
     if (szCmdLine == NULL)
                           0,
                           cbMaxCmdLine);
     if (szCmdLine == NULL)
@@ -188,7 +188,7 @@ static BOOL ProcessRunKeys(HKEY hkRoot, LPCWSTR szKeyName, BOOL bDelete,
     }
 
     ++cchMaxValue;
     }
 
     ++cchMaxValue;
-    szValue = HeapAlloc(hProcessHeap,
+    szValue = (WCHAR*)HeapAlloc(hProcessHeap,
                         0,
                         cchMaxValue * sizeof(*szValue));
     if (szValue == NULL)
                         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)
+    {
+        LRESULT Ret = IsGroupingEnabled;
+        if ((BOOL)wParam != IsGroupingEnabled)
+        {
+            EnableGrouping((BOOL) wParam);
+        }
+        return Ret;
+    }
+
+    LRESULT OnUpdateTaskbarPos(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        /* Update the button spacing */
+        UpdateTbButtonSpacing(
+            Tray->IsHorizontal(),
+            0,
+            0);
+        return TRUE;
+    }
+
+    LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        LRESULT Ret;
+        if (hWndToolbar != NULL)
+        {
+            POINT pt;
+            INT_PTR iBtn;
+
+            pt.x = (LONG) LOWORD(lParam);
+            pt.y = (LONG) HIWORD(lParam);
+
+            MapWindowPoints(NULL,
+                hWndToolbar,
+                &pt,
+                1);
+
+            iBtn = (INT_PTR) SendMessage(hWndToolbar,
+                TB_HITTEST,
+                0,
+                (LPARAM) &pt);
+            if (iBtn >= 0)
+            {
+                HandleButtonRightClick(
+                    iBtn);
+            }
+            else
+                goto ForwardContextMenuMsg;
+        }
+        else
+        {
+        ForwardContextMenuMsg:
+            /* Forward message */
+            Ret = SendMessage(Tray->GetHWND(),
+                uMsg,
+                wParam,
+                lParam);
+        }
+        return Ret;
+    }
+
+    LRESULT OnKludgeItemRect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        PTASK_ITEM TaskItem = FindTaskItem((HWND) wParam);
+        if (TaskItem)
+        {
+            RECT* prcMinRect = (RECT*) lParam;
+            RECT rcItem, rcToolbar;
+            SendMessageW(hWndToolbar, TB_GETITEMRECT, TaskItem->Index, (LPARAM) &rcItem);
+            GetWindowRect(hWndToolbar, &rcToolbar);
+
+            OffsetRect(&rcItem, rcToolbar.left, rcToolbar.top);
+
+            *prcMinRect = rcItem;
+            return TRUE;
+        }
+        return FALSE;
+    }
+
+    LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+#if DUMP_TASKS != 0
+        switch (wParam)
+        {
+        case 1:
+            DumpTasks();
+            break;
+        }
+#endif
+        return TRUE;
+    }
+
+    DECLARE_WND_CLASS_EX(szTaskSwitchWndClass, CS_DBLCLKS, COLOR_3DFACE)
+
+    BEGIN_MSG_MAP(CTaskSwitchWnd)
+        MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
+        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+        MESSAGE_HANDLER(WM_SIZE, OnSize)
+        MESSAGE_HANDLER(WM_CREATE, OnCreate)
+        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+        MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
+        MESSAGE_HANDLER(WM_COMMAND, OnCommand)
+        MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
+        MESSAGE_HANDLER(TSWM_ENABLEGROUPING, OnEnableGrouping)
+        MESSAGE_HANDLER(TSWM_UPDATETASKBARPOS, OnUpdateTaskbarPos)
+        MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
+        MESSAGE_HANDLER(WM_TIMER, OnTimer)
+        MESSAGE_HANDLER(ShellHookMsg, HandleShellHookMsg)
+    ALT_MSG_MAP(1)
+        MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTestToolbar)
+    END_MSG_MAP()
+
+    HWND _Init(IN HWND hWndParent, IN OUT ITrayWindow *tray)
+    {
+        Tray = tray;
+        hWndNotify = GetParent();
+        IsGroupingEnabled = TRUE; /* FIXME */
+        return Create(hWndParent, 0, szRunningApps, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP);
+    }
+};
+
+HWND
+CreateTaskSwitchWnd(IN HWND hWndParent, IN OUT ITrayWindow *Tray)
+{
+    CTaskSwitchWnd * instance;
+
+    // TODO: Destroy after the window is destroyed
+    instance = new CTaskSwitchWnd();
+
+    return instance->_Init(hWndParent, Tray);
+}
diff --git a/base/shell/explorer-new/tbsite.c b/base/shell/explorer-new/tbsite.c
deleted file mode 100644 (file)
index b29879d..0000000
+++ /dev/null
@@ -1,1067 +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 <shdeprecated.h>
-
-#include "undoc.h"
-
-/*****************************************************************************
- ** ITrayBandSite ************************************************************
- *****************************************************************************/
-
-static const ITrayBandSiteVtbl ITrayBandSiteImpl_Vtbl;
-static const IBandSiteVtbl IBandSiteImpl_Vtbl;
-
-typedef struct
-{
-    const ITrayBandSiteVtbl *lpVtbl;
-    const IBandSiteVtbl *lpBandSiteVtbl;
-    LONG Ref;
-
-    ITrayWindow *Tray;
-
-    IUnknown *punkInner;
-    IBandSite *BandSite;
-    ITaskBand *TaskBand;
-    IWinEventHandler *WindowEventHandler;
-    IContextMenu *ContextMenu;
-
-    HWND hWndRebar;
-
-    union
-    {
-        DWORD dwFlags;
-        struct
-        {
-            DWORD Locked : 1;
-        };
-    };
-} ITrayBandSiteImpl;
-
-static HRESULT
-ITrayBandSiteImpl_Update(IN OUT ITrayBandSiteImpl *This);
-
-static IUnknown *
-IUnknown_from_ITrayBandSiteImpl(ITrayBandSiteImpl *This)
-{
-    return (IUnknown *)&This->lpVtbl;
-}
-
-IMPL_CASTS(ITrayBandSite, ITrayBandSite, lpVtbl)
-IMPL_CASTS(IBandSite, ITrayBandSite, lpBandSiteVtbl)
-
-static ULONG STDMETHODCALLTYPE
-ITrayBandSiteImpl_AddRef(IN OUT ITrayBandSite *iface)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-
-    return InterlockedIncrement(&This->Ref);
-}
-
-static VOID
-ITrayBandSiteImpl_Free(IN OUT ITrayBandSiteImpl *This)
-{
-    if (This->BandSite != NULL)
-    {
-        IBandSite_Release(This->BandSite);
-        This->BandSite = NULL;
-    }
-
-    if (This->WindowEventHandler != NULL)
-    {
-        IWinEventHandler_Release(This->WindowEventHandler);
-        This->WindowEventHandler = NULL;
-    }
-
-    if (This->ContextMenu != NULL)
-    {
-        IContextMenu_Release(This->ContextMenu);
-        This->ContextMenu = NULL;
-    }
-
-    if (This->punkInner != NULL)
-    {
-        IUnknown_Release(This->punkInner);
-        This->punkInner = NULL;
-    }
-
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-static ULONG STDMETHODCALLTYPE
-ITrayBandSiteImpl_Release(IN OUT ITrayBandSite *iface)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-    ULONG Ret;
-
-    Ret = InterlockedDecrement(&This->Ref);
-
-    if (Ret == 0)
-        ITrayBandSiteImpl_Free(This);
-
-    return Ret;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_QueryInterface(IN OUT ITrayBandSite *iface,
-                                 IN REFIID riid,
-                                 OUT LPVOID *ppvObj)
-{
-    ITrayBandSiteImpl *This;
-
-    if (ppvObj == NULL)
-        return E_POINTER;
-
-    This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-
-    if (IsEqualIID(riid, &IID_IUnknown) ||
-        IsEqualIID(riid, &IID_IBandSiteStreamCallback))
-    {
-        /* NOTE: IID_IBandSiteStreamCallback is queried by the shell, we
-                 implement this interface directly */
-        *ppvObj = IUnknown_from_ITrayBandSiteImpl(This);
-    }
-    else if (IsEqualIID(riid, &IID_IBandSite))
-    {
-        *ppvObj = IBandSite_from_ITrayBandSiteImpl(This);
-    }
-    else if (IsEqualIID(riid, &IID_IWinEventHandler))
-    {
-        TRACE("ITaskBandSite: IWinEventHandler queried!\n");
-        *ppvObj = NULL;
-        return E_NOINTERFACE;
-    }
-    else if (This->punkInner != NULL)
-    {
-        return IUnknown_QueryInterface(This->punkInner,
-                                       riid,
-                                       ppvObj);
-    }
-    else
-    {
-        *ppvObj = NULL;
-        return E_NOINTERFACE;
-    }
-
-    ITrayBandSiteImpl_AddRef(iface);
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_OnLoad(IN OUT ITrayBandSite *iface,
-                         IN OUT IStream *pStm,
-                         IN REFIID riid,
-                         OUT PVOID *pvObj)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-    LARGE_INTEGER liPosZero;
-    ULARGE_INTEGER liCurrent;
-    CLSID clsid;
-    ULONG ulRead;
-    HRESULT hRet;
-
-    /* NOTE: Callback routine called by the shell while loading the task band
-             stream. We use it to intercept the default behavior when the task
-             band is loaded from the stream.
-
-       NOTE: riid always points to IID_IUnknown! This is because the shell hasn't
-             read anything from the stream and therefore doesn't know what CLSID
-             it's dealing with. We'll have to find it out ourselves by reading
-             the GUID from the stream. */
-
-    /* Read the current position of the stream, we'll have to reset it everytime
-       we read a CLSID that's not the task band... */
-    ZeroMemory(&liPosZero,
-               sizeof(liPosZero));
-    hRet = IStream_Seek(pStm,
-                        liPosZero,
-                        STREAM_SEEK_CUR,
-                        &liCurrent);
-
-    if (SUCCEEDED(hRet))
-    {
-        /* Now let's read the CLSID from the stream and see if it's our task band */
-#if defined(IStream_Read)
-        hRet = IStream_Read(pStm,
-                            &clsid,
-                            sizeof(clsid),
-                            &ulRead);
-#else
-        ulRead = sizeof(clsid);
-        hRet = IStream_Read(pStm,
-                            &clsid,
-                            sizeof(clsid));
-#endif
-        if (SUCCEEDED(hRet) && ulRead == sizeof(clsid))
-        {
-            if (IsEqualGUID(&clsid,
-                            &CLSID_ITaskBand))
-            {
-                ASSERT(This->TaskBand != NULL);
-                /* We're trying to load the task band! Let's create it... */
-
-                hRet = ITaskBand_QueryInterface(This->TaskBand,
-                                                riid,
-                                                pvObj);
-                if (SUCCEEDED(hRet))
-                {
-                    /* Load the stream */
-                    TRACE("IBandSiteStreamCallback::OnLoad intercepted the task band CLSID!\n");
-                }
-
-                return hRet;
-            }
-        }
-    }
-
-    /* Reset the position and let the shell do all the work for us */
-    hRet = IStream_Seek(pStm,
-                        *(LARGE_INTEGER*)&liCurrent,
-                        STREAM_SEEK_SET,
-                        NULL);
-    if (SUCCEEDED(hRet))
-    {
-        /* Let the shell handle everything else for us :) */
-        hRet = OleLoadFromStream(pStm,
-                                 riid,
-                                 pvObj);
-    }
-
-    if (!SUCCEEDED(hRet))
-    {
-        TRACE("IBandSiteStreamCallback::OnLoad(0x%p, 0x%p, 0x%p) returns 0x%x\n", pStm, riid, pvObj, hRet);
-    }
-
-    return hRet;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_OnSave(IN OUT ITrayBandSite *iface,
-                         IN OUT IUnknown *pUnk,
-                         IN OUT IStream *pStm)
-{
-    /* NOTE: Callback routine called by the shell while saving the task band
-             stream. We use it to intercept the default behavior when the task
-             band is saved to the stream */
-    /* FIXME: Implement */
-    TRACE("IBandSiteStreamCallback::OnSave(0x%p, 0x%p) returns E_NOTIMPL\n", pUnk, pStm);
-    return E_NOTIMPL;
-}
-
-static HRESULT
-IsSameObject(IN IUnknown *punk1,
-             IN IUnknown *punk2)
-{
-    HRESULT hRet;
-
-    hRet = IUnknown_QueryInterface(punk1,
-                                   &IID_IUnknown,
-                                   (PVOID*)&punk1);
-    if (!SUCCEEDED(hRet))
-        return hRet;
-
-    hRet = IUnknown_QueryInterface(punk2,
-                                   &IID_IUnknown,
-                                   (PVOID*)&punk2);
-    IUnknown_Release(punk1);
-
-    if (!SUCCEEDED(hRet))
-        return hRet;
-
-    IUnknown_Release(punk2);
-
-    /* We're dealing with the same object if the IUnknown pointers are equal */
-    return (punk1 == punk2) ? S_OK : S_FALSE;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_IsTaskBand(IN OUT ITrayBandSite *iface,
-                             IN IUnknown *punk)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-    return IsSameObject((IUnknown *)This->BandSite,
-                        punk);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_ProcessMessage(IN OUT ITrayBandSite *iface,
-                                 IN HWND hWnd,
-                                 IN UINT uMsg,
-                                 IN WPARAM wParam,
-                                 IN LPARAM lParam,
-                                 OUT LRESULT *plResult)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-    HRESULT hRet;
-
-    ASSERT(This->hWndRebar != NULL);
-
-    /* Custom task band behavior */
-    switch (uMsg)
-    {
-        case WM_NOTIFY:
-        {
-            const NMHDR *nmh = (const NMHDR *)lParam;
-
-            if (nmh->hwndFrom == This->hWndRebar)
-            {
-                switch (nmh->code)
-                {
-                    case NM_NCHITTEST:
-                    {
-                        LPNMMOUSE nmm = (LPNMMOUSE)lParam;
-
-                        if (nmm->dwHitInfo == RBHT_CLIENT || nmm->dwHitInfo == RBHT_NOWHERE ||
-                            nmm->dwItemSpec == (DWORD_PTR)-1)
-                        {
-                            /* Make the rebar control appear transparent so the user
-                               can drag the tray window */
-                            *plResult = HTTRANSPARENT;
-                        }
-                        return S_OK;
-                    }
-
-                    case RBN_MINMAX:
-                        /* Deny if an Administrator disabled this "feature" */
-                        *plResult = (SHRestricted(REST_NOMOVINGBAND) != 0);
-                        return S_OK;
-                }
-            }
-
-            //TRACE("ITrayBandSite::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u...\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code);
-            break;
-        }
-    };
-
-    /* Forward to the shell's IWinEventHandler interface to get the default
-       shell behavior! */
-    if (This->WindowEventHandler != NULL)
-    {
-        /*TRACE("Calling IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p) This->hWndRebar=0x%p\n", hWnd, uMsg, wParam, lParam, plResult, This->hWndRebar);*/
-        hRet = IWinEventHandler_OnWinEvent(This->WindowEventHandler,
-                                                  hWnd,
-                                                  uMsg,
-                                                  wParam,
-                                                  lParam,
-                                                  plResult);
-        if (!SUCCEEDED(hRet))
-        {
-            if (uMsg == WM_NOTIFY)
-            {
-                const NMHDR *nmh = (const NMHDR *)lParam;
-                TRACE("ITrayBandSite->IWinEventHandler::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u returned 0x%x\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code, hRet);
-            }
-            else
-            {
-                TRACE("ITrayBandSite->IWinEventHandler::ProcessMessage(0x%p,0x%x,0x%p,0x%p,0x%p->0x%p) returned: 0x%x\n", hWnd, uMsg, wParam, lParam, plResult, *plResult, hRet);
-            }
-        }
-    }
-    else
-        hRet = E_FAIL;
-
-    return hRet;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_AddContextMenus(IN OUT ITrayBandSite *iface,
-                                  IN HMENU hmenu,
-                                  IN UINT indexMenu,
-                                  IN UINT idCmdFirst,
-                                  IN UINT idCmdLast,
-                                  IN UINT uFlags,
-                                  OUT IContextMenu **ppcm)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-    IShellService *pSs;
-    HRESULT hRet;
-
-    if (This->ContextMenu == NULL)
-    {
-        /* Cache the context menu so we don't need to CoCreateInstance all the time... */
-        hRet = CoCreateInstance(&CLSID_IShellBandSiteMenu,
-                                NULL,
-                                CLSCTX_INPROC_SERVER,
-                                &IID_IShellService,
-                                (PVOID*)&pSs);
-        TRACE("CoCreateInstance(CLSID_IShellBandSiteMenu) for IShellService returned: 0x%x\n", hRet);
-        if (!SUCCEEDED(hRet))
-            return hRet;
-
-        hRet = IShellService_SetOwner(pSs,
-                                      IUnknown_from_ITrayBandSiteImpl(This));
-        if (!SUCCEEDED(hRet))
-        {
-            IShellService_Release(pSs);
-            return hRet;
-        }
-
-        hRet = IShellService_QueryInterface(pSs,
-                                            &IID_IContextMenu,
-                                            (PVOID*)&This->ContextMenu);
-
-        IShellService_Release(pSs);
-
-        if (!SUCCEEDED(hRet))
-            return hRet;
-    }
-
-    if (ppcm != NULL)
-    {
-        IContextMenu_AddRef(This->ContextMenu);
-        *ppcm = This->ContextMenu;
-    }
-
-    /* Add the menu items */
-    return IContextMenu_QueryContextMenu(This->ContextMenu,
-                                         hmenu,
-                                         indexMenu,
-                                         idCmdFirst,
-                                         idCmdLast,
-                                         uFlags);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_Lock(IN OUT ITrayBandSite *iface,
-                       IN BOOL bLock)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_ITrayBandSite(iface);
-    BOOL bPrevLocked = This->Locked;
-    BANDSITEINFO bsi;
-    HRESULT hRet;
-
-    ASSERT(This->BandSite != NULL);
-
-    if (bPrevLocked != bLock)
-    {
-        This->Locked = bLock;
-
-        bsi.dwMask = BSIM_STYLE;
-        bsi.dwStyle = (This->Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER);
-
-        hRet = IBandSite_SetBandSiteInfo(This->BandSite,
-                                         &bsi);
-        if (SUCCEEDED(hRet))
-        {
-            hRet = ITrayBandSiteImpl_Update(This);
-        }
-
-        return hRet;
-    }
-
-    return S_FALSE;
-}
-
-static const ITrayBandSiteVtbl ITrayBandSiteImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    ITrayBandSiteImpl_QueryInterface,
-    ITrayBandSiteImpl_AddRef,
-    ITrayBandSiteImpl_Release,
-    /*** IBandSiteStreamCallback methods ***/
-    ITrayBandSiteImpl_OnLoad,
-    ITrayBandSiteImpl_OnSave,
-    /*** ITrayBandSite methods ***/
-    ITrayBandSiteImpl_IsTaskBand,
-    ITrayBandSiteImpl_ProcessMessage,
-    ITrayBandSiteImpl_AddContextMenus,
-    ITrayBandSiteImpl_Lock
-};
-
-/*******************************************************************/
-
-METHOD_IUNKNOWN_INHERITED_ADDREF(IBandSite, ITrayBandSite)
-METHOD_IUNKNOWN_INHERITED_RELEASE(IBandSite, ITrayBandSite)
-METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE(IBandSite, ITrayBandSite)
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_AddBand(IN OUT IBandSite *iface,
-                          IN IUnknown *punk)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-    IOleCommandTarget *pOct;
-    HRESULT hRet;
-
-    hRet = IUnknown_QueryInterface(punk,
-                                   &IID_IOleCommandTarget,
-                                   (PVOID*)&pOct);
-    if (SUCCEEDED(hRet))
-    {
-        /* Send the DBID_DELAYINIT command to initialize the band to be added */
-        /* FIXME: Should be delayed */
-        IOleCommandTarget_Exec(pOct,
-                               &IID_IDeskBand,
-                               DBID_DELAYINIT,
-                               0,
-                               NULL,
-                               NULL);
-
-        IOleCommandTarget_Release(pOct);
-    }
-
-    return IBandSite_AddBand(This->BandSite,
-                             punk);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_EnumBands(IN OUT IBandSite *iface,
-                            IN UINT uBand,
-                            OUT DWORD *pdwBandID)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-    return IBandSite_EnumBands(This->BandSite,
-                               uBand,
-                               pdwBandID);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_QueryBand(IN OUT IBandSite *iface,
-                            IN DWORD dwBandID,
-                            OUT IDeskBand **ppstb,
-                            OUT DWORD *pdwState,
-                            OUT LPWSTR pszName,
-                            IN int cchName)
-{
-    HRESULT hRet;
-    IDeskBand *pstb = NULL;
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-
-    hRet = IBandSite_QueryBand(This->BandSite,
-                               dwBandID,
-                               &pstb,
-                               pdwState,
-                               pszName,
-                               cchName);
-
-    if (SUCCEEDED(hRet))
-    {
-        hRet = IsSameObject((IUnknown *)pstb,
-                            (IUnknown *)This->TaskBand);
-        if (hRet == S_OK)
-        {
-            /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */
-            if (pdwState != NULL)
-                *pdwState |= BSSF_UNDELETEABLE;
-        }
-        else if (!SUCCEEDED(hRet))
-        {
-            IDeskBand_Release(pstb);
-            pstb = NULL;
-        }
-
-        if (ppstb != NULL)
-            *ppstb = pstb;
-    }
-    else if (ppstb != NULL)
-        *ppstb = NULL;
-
-    return hRet;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_SetBandState(IN OUT IBandSite *iface,
-                               IN DWORD dwBandID,
-                               IN DWORD dwMask,
-                               IN DWORD dwState)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-    return IBandSite_SetBandState(This->BandSite,
-                                  dwBandID,
-                                  dwMask,
-                                  dwState);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_RemoveBand(IN OUT IBandSite *iface,
-                             IN DWORD dwBandID)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-    return IBandSite_RemoveBand(This->BandSite,
-                                dwBandID);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_GetBandObject(IN OUT IBandSite *iface,
-                                IN DWORD dwBandID,
-                                IN REFIID riid,
-                                OUT VOID **ppv)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-    return IBandSite_GetBandObject(This->BandSite,
-                                   dwBandID,
-                                   riid,
-                                   ppv);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_SetBandSiteInfo(IN OUT IBandSite *iface,
-                                  IN const BANDSITEINFO *pbsinfo)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-    return IBandSite_SetBandSiteInfo(This->BandSite,
-                                     pbsinfo);
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayBandSiteImpl_GetBandSiteInfo(IN OUT IBandSite *iface,
-                                  IN OUT BANDSITEINFO *pbsinfo)
-{
-    ITrayBandSiteImpl *This = ITrayBandSiteImpl_from_IBandSite(iface);
-    return IBandSite_GetBandSiteInfo(This->BandSite,
-                                     pbsinfo);
-}
-
-static const IBandSiteVtbl IBandSiteImpl_Vtbl =
-{
-    /*** IUnknown methods ***/
-    METHOD_IUNKNOWN_INHERITED_QUERYINTERFACE_NAME(IBandSite, ITrayBandSite),
-    METHOD_IUNKNOWN_INHERITED_ADDREF_NAME(IBandSite, ITrayBandSite),
-    METHOD_IUNKNOWN_INHERITED_RELEASE_NAME(IBandSite, ITrayBandSite),
-    /*** IBandSite methods ***/
-    ITrayBandSiteImpl_AddBand,
-    ITrayBandSiteImpl_EnumBands,
-    ITrayBandSiteImpl_QueryBand,
-    ITrayBandSiteImpl_SetBandState,
-    ITrayBandSiteImpl_RemoveBand,
-    ITrayBandSiteImpl_GetBandObject,
-    ITrayBandSiteImpl_SetBandSiteInfo,
-    ITrayBandSiteImpl_GetBandSiteInfo,
-};
-
-static BOOL
-ITrayBandSiteImpl_HasTaskBand(IN OUT ITrayBandSiteImpl *This)
-{
-    ASSERT(This->TaskBand != NULL);
-
-    return SUCCEEDED(ITaskBand_GetRebarBandID(This->TaskBand,
-                                              NULL));
-}
-
-static HRESULT
-ITrayBandSiteImpl_AddTaskBand(IN OUT ITrayBandSiteImpl *This)
-{
-#if 0
-    /* FIXME: This is the code for the simple taskbar */
-    IObjectWithSite *pOws;
-    HRESULT hRet;
-
-    hRet = ITaskBand_QueryInterface(This->TaskBand,
-                                    &IID_IObjectWithSite,
-                                    (PVOID*)&pOws);
-    if (SUCCEEDED(hRet))
-    {
-        hRet = IObjectWithSite_SetSite(pOws,
-                                       (IUnknown *)This->TaskBand);
-
-        IObjectWithSite_Release(pOws);
-    }
-
-    return hRet;
-#else
-    if (!ITrayBandSiteImpl_HasTaskBand(This))
-    {
-        return IBandSite_AddBand(This->BandSite,
-                                 (IUnknown *)This->TaskBand);
-    }
-
-    return S_OK;
-#endif
-}
-
-static HRESULT
-ITrayBandSiteImpl_Update(IN OUT ITrayBandSiteImpl *This)
-{
-    IOleCommandTarget *pOct;
-    HRESULT hRet;
-
-    hRet = IUnknown_QueryInterface(This->punkInner,
-                                   &IID_IOleCommandTarget,
-                                   (PVOID*)&pOct);
-    if (SUCCEEDED(hRet))
-    {
-        /* Send the DBID_BANDINFOCHANGED command to update the band site */
-        hRet = IOleCommandTarget_Exec(pOct,
-                                      &IID_IDeskBand,
-                                      DBID_BANDINFOCHANGED,
-                                      0,
-                                      NULL,
-                                      NULL);
-
-        IOleCommandTarget_Release(pOct);
-    }
-
-    return hRet;
-}
-
-static VOID
-ITrayBandSiteImpl_BroadcastOleCommandExec(IN OUT ITrayBandSiteImpl *This,
-                                          const GUID *pguidCmdGroup,
-                                          DWORD nCmdID,
-                                          DWORD nCmdExecOpt,
-                                          VARIANTARG *pvaIn,
-                                          VARIANTARG *pvaOut)
-{
-    IOleCommandTarget *pOct;
-    DWORD dwBandID;
-    UINT uBand = 0;
-
-    /* Enumerate all bands */
-    while (SUCCEEDED(IBandSite_EnumBands(This->BandSite,
-                                         uBand,
-                                         &dwBandID)))
-    {
-        if (SUCCEEDED(IBandSite_GetBandObject(This->BandSite,
-                                              dwBandID,
-                                              &IID_IOleCommandTarget,
-                                              (PVOID*)&pOct)))
-        {
-            /* Execute the command */
-            IOleCommandTarget_Exec(pOct,
-                                   pguidCmdGroup,
-                                   nCmdID,
-                                   nCmdExecOpt,
-                                   pvaIn,
-                                   pvaOut);
-
-            IOleCommandTarget_Release(pOct);
-        }
-
-        uBand++;
-    }
-}
-
-static HRESULT
-ITrayBandSiteImpl_FinishInit(IN OUT ITrayBandSiteImpl *This)
-{
-    /* Broadcast the DBID_FINISHINIT command */
-    ITrayBandSiteImpl_BroadcastOleCommandExec(This,
-                                              &IID_IDeskBand,
-                                              DBID_FINISHINIT,
-                                              0,
-                                              NULL,
-                                              NULL);
-
-    return S_OK;
-}
-
-static HRESULT
-ITrayBandSiteImpl_Show(IN OUT ITrayBandSiteImpl *This,
-                       IN BOOL bShow)
-{
-    IDeskBarClient *pDbc;
-    HRESULT hRet;
-
-    hRet = IBandSite_QueryInterface(This->BandSite,
-                                    &IID_IDeskBarClient,
-                                    (PVOID*)&pDbc);
-    if (SUCCEEDED(hRet))
-    {
-        hRet = IDeskBarClient_UIActivateDBC(pDbc,
-                                            bShow ? DBC_SHOW : DBC_HIDE);
-        IDeskBarClient_Release(pDbc);
-    }
-
-    return hRet;
-}
-
-static HRESULT
-ITrayBandSiteImpl_LoadFromStream(IN OUT ITrayBandSiteImpl *This,
-                                 IN OUT IStream *pStm)
-{
-    IPersistStream *pPStm;
-    HRESULT hRet;
-
-    ASSERT(This->BandSite != NULL);
-
-    /* We implement the undocumented COM interface IBandSiteStreamCallback
-       that the shell will query so that we can intercept and custom-load
-       the task band when it finds the task band's CLSID (which is internal).
-       This way we can prevent the shell from attempting to CoCreateInstance
-       the (internal) task band, resulting in a failure... */
-    hRet = IBandSite_QueryInterface(This->BandSite,
-                                    &IID_IPersistStream,
-                                    (PVOID*)&pPStm);
-    if (SUCCEEDED(hRet))
-    {
-        hRet = IPersistStream_Load(pPStm,
-                                   pStm);
-        TRACE("IPersistStream_Load() returned 0x%x\n", hRet);
-        IPersistStream_Release(pPStm);
-    }
-
-    return hRet;
-}
-
-static IStream *
-GetUserBandsStream(IN DWORD grfMode)
-{
-    HKEY hkStreams;
-    IStream *Stream = NULL;
-
-    if (RegCreateKey(hkExplorer,
-                     TEXT("Streams"),
-                     &hkStreams) == ERROR_SUCCESS)
-    {
-        Stream = SHOpenRegStream(hkStreams,
-                                 TEXT("Desktop"),
-                                 TEXT("TaskbarWinXP"),
-                                 grfMode);
-
-        RegCloseKey(hkStreams);
-    }
-
-    return Stream;
-}
-
-static IStream *
-GetDefaultBandsStream(IN DWORD grfMode)
-{
-    HKEY hkStreams;
-    IStream *Stream = NULL;
-
-    if (RegCreateKey(HKEY_LOCAL_MACHINE,
-                     TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams"),
-                     &hkStreams) == ERROR_SUCCESS)
-    {
-        Stream = SHOpenRegStream(hkStreams,
-                                 TEXT("Desktop"),
-                                 TEXT("Default Taskbar"),
-                                 grfMode);
-
-        RegCloseKey(hkStreams);
-    }
-
-    return Stream;
-}
-
-static HRESULT
-ITrayBandSiteImpl_Load(IN OUT ITrayBandSiteImpl *This)
-{
-    IStream *pStm;
-    HRESULT hRet;
-
-    /* Try to load the user's settings */
-    pStm = GetUserBandsStream(STGM_READ);
-    if (pStm != NULL)
-    {
-        hRet = ITrayBandSiteImpl_LoadFromStream(This,
-                                                pStm);
-
-        TRACE("Loaded user bands settings: 0x%x\n", hRet);
-        IStream_Release(pStm);
-    }
-    else
-        hRet = E_FAIL;
-
-    /* If the user's settings couldn't be loaded, try with
-       default settings (ie. when the user logs in for the
-       first time! */
-    if (!SUCCEEDED(hRet))
-    {
-        pStm = GetDefaultBandsStream(STGM_READ);
-        if (pStm != NULL)
-        {
-            hRet = ITrayBandSiteImpl_LoadFromStream(This,
-                                                    pStm);
-
-            TRACE("Loaded default user bands settings: 0x%x\n", hRet);
-            IStream_Release(pStm);
-        }
-        else
-            hRet = E_FAIL;
-    }
-
-    return hRet;
-}
-
-static ITrayBandSiteImpl *
-ITrayBandSiteImpl_Construct(IN OUT ITrayWindow *Tray,
-                            OUT HWND *phWndRebar,
-                            OUT HWND *phwndTaskSwitch)
-{
-    ITrayBandSiteImpl *This;
-    IDeskBarClient *pDbc;
-    IDeskBand *pDb;
-    IOleWindow *pOw;
-    HRESULT hRet;
-
-    *phWndRebar = NULL;
-    *phwndTaskSwitch = NULL;
-
-    This = HeapAlloc(hProcessHeap,
-                     HEAP_ZERO_MEMORY,
-                     sizeof(*This));
-    if (This == NULL)
-        return NULL;
-
-    This->lpVtbl = &ITrayBandSiteImpl_Vtbl;
-    This->lpBandSiteVtbl = &IBandSiteImpl_Vtbl;
-    This->Ref = 1;
-    This->Tray = Tray;
-
-    /* Create a RebarBandSite provided by the shell */
-    hRet = CoCreateInstance(&CLSID_RebarBandSite,
-                            (LPUNKNOWN)IBandSite_from_ITrayBandSiteImpl(This),
-                            CLSCTX_INPROC_SERVER,
-                            &IID_IUnknown,
-                            (LPVOID*)&This->punkInner);
-    if (!SUCCEEDED(hRet))
-    {
-        ITrayBandSiteImpl_Free(This);
-        return NULL;
-    }
-
-    hRet = IUnknown_QueryInterface(This->punkInner,
-                                   &IID_IBandSite,
-                                   (PVOID*)&This->BandSite);
-    if (!SUCCEEDED(hRet))
-    {
-        ITrayBandSiteImpl_Free(This);
-        return NULL;
-    }
-
-    hRet = IUnknown_QueryInterface(This->punkInner,
-                                   &IID_IWinEventHandler,
-                                   (PVOID*)&This->WindowEventHandler);
-    if (!SUCCEEDED(hRet))
-    {
-        ITrayBandSiteImpl_Free(This);
-        return NULL;
-    }
-
-    This->TaskBand = CreateTaskBand(Tray);
-    if (This->TaskBand != NULL)
-    {
-        /* Add the task band to the site */
-        hRet = IBandSite_QueryInterface(This->BandSite,
-                                        &IID_IDeskBarClient,
-                                        (PVOID*)&pDbc);
-        if (SUCCEEDED(hRet))
-        {
-            hRet = ITaskBand_QueryInterface(This->TaskBand,
-                                            &IID_IOleWindow,
-                                            (PVOID*)&pOw);
-            if (SUCCEEDED(hRet))
-            {
-                /* We cause IDeskBarClient to create the rebar control by passing the new
-                   task band to it. The band reports the tray window handle as window handle
-                   so that IDeskBarClient knows the parent window of the Rebar control that
-                   it wants to create. */
-                hRet = IDeskBarClient_SetDeskBarSite(pDbc,
-                                                     (IUnknown *)pOw);
-
-                if (SUCCEEDED(hRet))
-                {
-                    /* The Rebar control is now created, we can query the window handle */
-                    hRet = IDeskBarClient_GetWindow(pDbc,
-                                                    &This->hWndRebar);
-
-                    if (SUCCEEDED(hRet))
-                    {
-                        /* We need to manually remove the RBS_BANDBORDERS style! */
-                        SetWindowStyle(This->hWndRebar,
-                                       RBS_BANDBORDERS,
-                                       0);
-                    }
-                }
-
-                IOleWindow_Release(pOw);
-            }
-
-            if (SUCCEEDED(hRet))
-            {
-                DWORD dwMode = 0;
-
-                /* Set the Desk Bar mode to the current one */
-
-                /* FIXME: We need to set the mode (and update) whenever the user docks
-                          the tray window to another monitor edge! */
-
-                if (!ITrayWindow_IsHorizontal(This->Tray))
-                    dwMode = DBIF_VIEWMODE_VERTICAL;
-
-                hRet = IDeskBarClient_SetModeDBC(pDbc,
-                                                 dwMode);
-            }
-
-            IDeskBarClient_Release(pDbc);
-        }
-
-        /* Load the saved state of the task band site */
-        /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */
-        ITrayBandSiteImpl_Load(This);
-
-        /* Add the task bar band if it hasn't been added already */
-        hRet = ITrayBandSiteImpl_AddTaskBand(This);
-        if (SUCCEEDED(hRet))
-        {
-            hRet = ITaskBand_QueryInterface(This->TaskBand,
-                                            &IID_IDeskBand,
-                                            (PVOID*)&pDb);
-            if (SUCCEEDED(hRet))
-            {
-                hRet = IDeskBand_GetWindow(pDb,
-                                           phwndTaskSwitch);
-                if (!SUCCEEDED(hRet))
-                    *phwndTaskSwitch = NULL;
-
-                IDeskBand_Release(pDb);
-            }
-        }
-
-        /* Should we send this after showing it? */
-        ITrayBandSiteImpl_Update(This);
-
-        /* FIXME: When should we send this? Does anyone care anyway? */
-        ITrayBandSiteImpl_FinishInit(This);
-
-        /* Activate the band site */
-        ITrayBandSiteImpl_Show(This,
-                               TRUE);
-    }
-
-    *phWndRebar = This->hWndRebar;
-
-    return This;
-}
-
-/*******************************************************************/
-
-ITrayBandSite *
-CreateTrayBandSite(IN OUT ITrayWindow *Tray,
-                   OUT HWND *phWndRebar,
-                   OUT HWND *phWndTaskSwitch)
-{
-    ITrayBandSiteImpl *This;
-
-    This = ITrayBandSiteImpl_Construct(Tray,
-                                       phWndRebar,
-                                       phWndTaskSwitch);
-    if (This != NULL)
-    {
-        return ITrayBandSite_from_ITrayBandSiteImpl(This);
-    }
-
-    return NULL;
-}
diff --git a/base/shell/explorer-new/tbsite.cpp b/base/shell/explorer-new/tbsite.cpp
new file mode 100644 (file)
index 0000000..b75e343
--- /dev/null
@@ -0,0 +1,831 @@
+/*
+ * 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 <shdeprecated.h>
+
+#include "undoc.h"
+
+/*****************************************************************************
+ ** ITrayBandSite ************************************************************
+ *****************************************************************************/
+
+// WARNING: Can't use ATL for this class due to our ATL not fully supporting the AGGREGATION functions needed for this class to be an "outer" class
+// it works just fine this way.
+class ITrayBandSiteImpl :
+    public ITrayBandSite,
+    public IBandSite,
+    public IBandSiteStreamCallback
+    /* TODO: IWinEventHandler */
+{
+    volatile LONG m_RefCount;
+
+    CComPtr<ITrayWindow> Tray;
+
+    CComPtr<IUnknown> punkInner;
+    CComPtr<IBandSite> BandSite;
+    CComPtr<ITaskBand> TaskBand;
+    CComPtr<IWinEventHandler> WindowEventHandler;
+    CComPtr<IContextMenu> ContextMenu;
+
+    HWND hWndRebar;
+
+    union
+    {
+        DWORD dwFlags;
+        struct
+        {
+            DWORD Locked : 1;
+        };
+    };
+
+public:
+
+    virtual ULONG STDMETHODCALLTYPE AddRef()
+    {
+        return InterlockedIncrement(&m_RefCount);
+    }
+
+    virtual ULONG STDMETHODCALLTYPE Release()
+    {
+        ULONG Ret = InterlockedDecrement(&m_RefCount);
+
+        if (Ret == 0)
+            delete this;
+
+        return Ret;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE QueryInterface(IN REFIID riid, OUT LPVOID *ppvObj)
+    {
+        if (ppvObj == NULL)
+            return E_POINTER;
+
+        if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IBandSiteStreamCallback))
+        {
+            // return IBandSiteStreamCallback's IUnknown
+            *ppvObj = static_cast<IBandSiteStreamCallback*>(this);
+        }
+        else if (IsEqualIID(riid, IID_IBandSite))
+        {
+            *ppvObj = static_cast<IBandSite*>(this);
+        }
+        else if (IsEqualIID(riid, IID_IWinEventHandler))
+        {
+            TRACE("ITaskBandSite: IWinEventHandler queried!\n");
+            *ppvObj = NULL;
+            return E_NOINTERFACE;
+        }
+        else if (punkInner != NULL)
+        {
+            return punkInner->QueryInterface(riid, ppvObj);
+        }
+        else
+        {
+            *ppvObj = NULL;
+            return E_NOINTERFACE;
+        }
+
+        AddRef();
+        return S_OK;
+    }
+
+public:
+    ITrayBandSiteImpl() :
+        m_RefCount(0),
+        hWndRebar(NULL)
+    {
+    }
+
+    virtual ~ITrayBandSiteImpl() { }
+
+    virtual HRESULT STDMETHODCALLTYPE OnLoad(
+        IN OUT IStream *pStm,
+        IN REFIID riid,
+        OUT PVOID *pvObj)
+    {
+        LARGE_INTEGER liPosZero;
+        ULARGE_INTEGER liCurrent;
+        CLSID clsid;
+        ULONG ulRead;
+        HRESULT hRet;
+
+        /* NOTE: Callback routine called by the shell while loading the task band
+                 stream. We use it to intercept the default behavior when the task
+                 band is loaded from the stream.
+
+                 NOTE: riid always points to IID_IUnknown! This is because the shell hasn't
+                 read anything from the stream and therefore doesn't know what CLSID
+                 it's dealing with. We'll have to find it out ourselves by reading
+                 the GUID from the stream. */
+
+        /* Read the current position of the stream, we'll have to reset it everytime
+           we read a CLSID that's not the task band... */
+        ZeroMemory(&liPosZero,
+            sizeof(liPosZero));
+        hRet = pStm->Seek(liPosZero, STREAM_SEEK_CUR, &liCurrent);
+
+        if (SUCCEEDED(hRet))
+        {
+            /* Now let's read the CLSID from the stream and see if it's our task band */
+            hRet = pStm->Read(&clsid, (ULONG)sizeof(clsid), &ulRead);
+
+            if (SUCCEEDED(hRet) && ulRead == sizeof(clsid))
+            {
+                if (IsEqualGUID(clsid, CLSID_ITaskBand))
+                {
+                    ASSERT(TaskBand != NULL);
+                    /* We're trying to load the task band! Let's create it... */
+
+                    hRet = TaskBand->QueryInterface(
+                        riid,
+                        pvObj);
+                    if (SUCCEEDED(hRet))
+                    {
+                        /* Load the stream */
+                        TRACE("IBandSiteStreamCallback::OnLoad intercepted the task band CLSID!\n");
+                    }
+
+                    return hRet;
+                }
+            }
+        }
+
+        /* Reset the position and let the shell do all the work for us */
+        hRet = pStm->Seek(
+            *(LARGE_INTEGER*) &liCurrent,
+            STREAM_SEEK_SET,
+            NULL);
+        if (SUCCEEDED(hRet))
+        {
+            /* Let the shell handle everything else for us :) */
+            hRet = OleLoadFromStream(pStm,
+                riid,
+                pvObj);
+        }
+
+        if (!SUCCEEDED(hRet))
+        {
+            TRACE("IBandSiteStreamCallback::OnLoad(0x%p, 0x%p, 0x%p) returns 0x%x\n", pStm, riid, pvObj, hRet);
+        }
+
+        return hRet;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE OnSave(
+        IN OUT IUnknown *pUnk,
+        IN OUT IStream *pStm)
+    {
+        /* NOTE: Callback routine called by the shell while saving the task band
+                 stream. We use it to intercept the default behavior when the task
+                 band is saved to the stream */
+        /* FIXME: Implement */
+        TRACE("IBandSiteStreamCallback::OnSave(0x%p, 0x%p) returns E_NOTIMPL\n", pUnk, pStm);
+        return E_NOTIMPL;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE IsTaskBand(
+        IN IUnknown *punk)
+    {
+        return IsSameObject((IUnknown *) BandSite,
+            punk);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
+        IN HWND hWnd,
+        IN UINT uMsg,
+        IN WPARAM wParam,
+        IN LPARAM lParam,
+        OUT LRESULT *plResult)
+    {
+        HRESULT hRet;
+
+        ASSERT(hWndRebar != NULL);
+
+        /* Custom task band behavior */
+        switch (uMsg)
+        {
+        case WM_NOTIFY:
+        {
+            const NMHDR *nmh = (const NMHDR *) lParam;
+
+            if (nmh->hwndFrom == hWndRebar)
+            {
+                switch (nmh->code)
+                {
+                case NM_NCHITTEST:
+                {
+                    LPNMMOUSE nmm = (LPNMMOUSE) lParam;
+
+                    if (nmm->dwHitInfo == RBHT_CLIENT || nmm->dwHitInfo == RBHT_NOWHERE ||
+                        nmm->dwItemSpec == (DWORD_PTR) -1)
+                    {
+                        /* Make the rebar control appear transparent so the user
+                           can drag the tray window */
+                        *plResult = HTTRANSPARENT;
+                    }
+                    return S_OK;
+                }
+
+                case RBN_MINMAX:
+                    /* Deny if an Administrator disabled this "feature" */
+                    *plResult = (SHRestricted(REST_NOMOVINGBAND) != 0);
+                    return S_OK;
+                }
+            }
+
+            //TRACE("ITrayBandSite::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u...\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code);
+            break;
+        }
+        }
+
+        /* Forward to the shell's IWinEventHandler interface to get the default shell behavior! */
+        if (!WindowEventHandler)
+            return E_FAIL;
+
+        /*TRACE("Calling IWinEventHandler::ProcessMessage(0x%p, 0x%x, 0x%p, 0x%p, 0x%p) hWndRebar=0x%p\n", hWnd, uMsg, wParam, lParam, plResult, hWndRebar);*/
+        hRet = WindowEventHandler->OnWinEvent(
+            hWnd,
+            uMsg,
+            wParam,
+            lParam,
+            plResult);
+        if (FAILED_UNEXPECTEDLY(hRet))
+        {
+            if (uMsg == WM_NOTIFY)
+            {
+                const NMHDR *nmh = (const NMHDR *) lParam;
+                ERR("ITrayBandSite->IWinEventHandler::ProcessMessage: WM_NOTIFY for 0x%p, From: 0x%p, Code: NM_FIRST-%u returned 0x%x\n", hWnd, nmh->hwndFrom, NM_FIRST - nmh->code, hRet);
+            }
+            else
+            {
+                ERR("ITrayBandSite->IWinEventHandler::ProcessMessage(0x%p,0x%x,0x%p,0x%p,0x%p->0x%p) returned: 0x%x\n", hWnd, uMsg, wParam, lParam, plResult, *plResult, hRet);
+            }
+        }
+
+        return hRet;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE AddContextMenus(
+        IN HMENU hmenu,
+        IN UINT indexMenu,
+        IN UINT idCmdFirst,
+        IN UINT idCmdLast,
+        IN UINT uFlags,
+        OUT IContextMenu **ppcm)
+    {
+        IShellService *pSs;
+        HRESULT hRet;
+
+        if (ContextMenu == NULL)
+        {
+            /* Cache the context menu so we don't need to CoCreateInstance all the time... */
+            hRet = CoCreateInstance(CLSID_IShellBandSiteMenu, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellService, &pSs));
+            TRACE("CoCreateInstance(CLSID_IShellBandSiteMenu) for IShellService returned: 0x%x\n", hRet);
+            if (!SUCCEEDED(hRet))
+                return hRet;
+
+            hRet = pSs->SetOwner((IBandSite*)this);
+            if (!SUCCEEDED(hRet))
+            {
+                pSs->Release();
+                return hRet;
+            }
+
+            hRet = pSs->QueryInterface(IID_PPV_ARG(IContextMenu, &ContextMenu));
+
+            pSs->Release();
+
+            if (!SUCCEEDED(hRet))
+                return hRet;
+        }
+
+        if (ppcm != NULL)
+        {
+            ContextMenu->AddRef();
+            *ppcm = ContextMenu;
+        }
+
+        /* Add the menu items */
+        return ContextMenu->QueryContextMenu(
+            hmenu,
+            indexMenu,
+            idCmdFirst,
+            idCmdLast,
+            uFlags);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Lock(
+        IN BOOL bLock)
+    {
+        BOOL bPrevLocked = Locked;
+        BANDSITEINFO bsi;
+        HRESULT hRet;
+
+        ASSERT(BandSite != NULL);
+
+        if (bPrevLocked != bLock)
+        {
+            Locked = bLock;
+
+            bsi.dwMask = BSIM_STYLE;
+            bsi.dwStyle = (Locked ? BSIS_LOCKED | BSIS_NOGRIPPER : BSIS_AUTOGRIPPER);
+
+            hRet = BandSite->SetBandSiteInfo(&bsi);
+            if (SUCCEEDED(hRet))
+            {
+                hRet = Update();
+            }
+
+            return hRet;
+        }
+
+        return S_FALSE;
+    }
+
+    /*******************************************************************/
+
+    virtual HRESULT STDMETHODCALLTYPE AddBand(
+        IN IUnknown *punk)
+    {
+        IOleCommandTarget *pOct;
+        HRESULT hRet;
+
+        hRet = punk->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOct));
+        if (SUCCEEDED(hRet))
+        {
+            /* Send the DBID_DELAYINIT command to initialize the band to be added */
+            /* FIXME: Should be delayed */
+            pOct->Exec(
+                &IID_IDeskBand,
+                DBID_DELAYINIT,
+                0,
+                NULL,
+                NULL);
+
+            pOct->Release();
+        }
+
+        return BandSite->AddBand(
+            punk);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE EnumBands(
+        IN UINT uBand,
+        OUT DWORD *pdwBandID)
+    {
+        return BandSite->EnumBands(
+            uBand,
+            pdwBandID);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE QueryBand(
+        IN DWORD dwBandID,
+        OUT IDeskBand **ppstb,
+        OUT DWORD *pdwState,
+        OUT LPWSTR pszName,
+        IN int cchName)
+    {
+        HRESULT hRet;
+        IDeskBand *pstb = NULL;
+
+        hRet = BandSite->QueryBand(
+            dwBandID,
+            &pstb,
+            pdwState,
+            pszName,
+            cchName);
+
+        if (SUCCEEDED(hRet))
+        {
+            hRet = IsSameObject(pstb, TaskBand);
+            if (hRet == S_OK)
+            {
+                /* Add the BSSF_UNDELETEABLE flag to pdwState because the task bar band shouldn't be deletable */
+                if (pdwState != NULL)
+                    *pdwState |= BSSF_UNDELETEABLE;
+            }
+            else if (!SUCCEEDED(hRet))
+            {
+                pstb->Release();
+                pstb = NULL;
+            }
+
+            if (ppstb != NULL)
+                *ppstb = pstb;
+        }
+        else if (ppstb != NULL)
+            *ppstb = NULL;
+
+        return hRet;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE SetBandState(
+        IN DWORD dwBandID,
+        IN DWORD dwMask,
+        IN DWORD dwState)
+    {
+        return BandSite->SetBandState(dwBandID, dwMask, dwState);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE RemoveBand(
+        IN DWORD dwBandID)
+    {
+        return BandSite->RemoveBand(dwBandID);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetBandObject(
+        IN DWORD dwBandID,
+        IN REFIID riid,
+        OUT VOID **ppv)
+    {
+        return BandSite->GetBandObject(dwBandID, riid, ppv);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE SetBandSiteInfo(
+        IN const BANDSITEINFO *pbsinfo)
+    {
+        return BandSite->SetBandSiteInfo(pbsinfo);
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetBandSiteInfo(
+        IN OUT BANDSITEINFO *pbsinfo)
+    {
+        return BandSite->GetBandSiteInfo(pbsinfo);
+    }
+
+    virtual BOOL HasTaskBand()
+    {
+        ASSERT(TaskBand != NULL);
+
+        return SUCCEEDED(TaskBand->GetRebarBandID(
+            NULL));
+    }
+
+    virtual HRESULT AddTaskBand()
+    {
+#if 0
+        /* FIXME: This is the code for the simple taskbar */
+        IObjectWithSite *pOws;
+        HRESULT hRet;
+
+        hRet = TaskBand->QueryInterface(
+            &IID_IObjectWithSite,
+            (PVOID*) &pOws);
+        if (SUCCEEDED(hRet))
+        {
+            hRet = pOws->SetSite(
+                (IUnknown *)TaskBand);
+
+            pOws->Release();
+        }
+
+        return hRet;
+#else
+        if (!HasTaskBand())
+        {
+            return BandSite->AddBand(TaskBand);
+        }
+
+        return S_OK;
+#endif
+    }
+
+    virtual HRESULT Update()
+    {
+        IOleCommandTarget *pOct;
+        HRESULT hRet;
+
+        hRet = punkInner->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &pOct));
+        if (SUCCEEDED(hRet))
+        {
+            /* Send the DBID_BANDINFOCHANGED command to update the band site */
+            hRet = pOct->Exec(
+                &IID_IDeskBand,
+                DBID_BANDINFOCHANGED,
+                0,
+                NULL,
+                NULL);
+
+            pOct->Release();
+        }
+
+        return hRet;
+    }
+
+    virtual VOID BroadcastOleCommandExec(const GUID *pguidCmdGroup,
+        DWORD nCmdID,
+        DWORD nCmdExecOpt,
+        VARIANTARG *pvaIn,
+        VARIANTARG *pvaOut)
+    {
+        IOleCommandTarget *pOct;
+        DWORD dwBandID;
+        UINT uBand = 0;
+
+        /* Enumerate all bands */
+        while (SUCCEEDED(BandSite->EnumBands(uBand, &dwBandID)))
+        {
+            if (SUCCEEDED(BandSite->GetBandObject(dwBandID, IID_PPV_ARG(IOleCommandTarget, &pOct))))
+            {
+                /* Execute the command */
+                pOct->Exec(
+                    pguidCmdGroup,
+                    nCmdID,
+                    nCmdExecOpt,
+                    pvaIn,
+                    pvaOut);
+
+                pOct->Release();
+            }
+
+            uBand++;
+        }
+    }
+
+    virtual HRESULT FinishInit()
+    {
+        /* Broadcast the DBID_FINISHINIT command */
+        BroadcastOleCommandExec(&IID_IDeskBand, DBID_FINISHINIT, 0, NULL, NULL);
+
+        return S_OK;
+    }
+
+    virtual HRESULT Show(
+        IN BOOL bShow)
+    {
+        IDeskBarClient *pDbc;
+        HRESULT hRet;
+
+        hRet = BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
+        if (SUCCEEDED(hRet))
+        {
+            hRet = pDbc->UIActivateDBC(
+                bShow ? DBC_SHOW : DBC_HIDE);
+            pDbc->Release();
+        }
+
+        return hRet;
+    }
+
+    virtual HRESULT LoadFromStream(IN OUT IStream *pStm)
+    {
+        IPersistStream *pPStm;
+        HRESULT hRet;
+
+        ASSERT(BandSite != NULL);
+
+        /* We implement the undocumented COM interface IBandSiteStreamCallback
+           that the shell will query so that we can intercept and custom-load
+           the task band when it finds the task band's CLSID (which is internal).
+           This way we can prevent the shell from attempting to CoCreateInstance
+           the (internal) task band, resulting in a failure... */
+        hRet = BandSite->QueryInterface(IID_PPV_ARG(IPersistStream, &pPStm));
+        if (SUCCEEDED(hRet))
+        {
+            hRet = pPStm->Load(
+                pStm);
+            TRACE("->Load() returned 0x%x\n", hRet);
+            pPStm->Release();
+        }
+
+        return hRet;
+    }
+
+    virtual IStream *
+        GetUserBandsStream(IN DWORD grfMode)
+    {
+        HKEY hkStreams;
+        IStream *Stream = NULL;
+
+        if (RegCreateKey(hkExplorer,
+            TEXT("Streams"),
+            &hkStreams) == ERROR_SUCCESS)
+        {
+            Stream = SHOpenRegStream(hkStreams,
+                TEXT("Desktop"),
+                TEXT("TaskbarWinXP"),
+                grfMode);
+
+            RegCloseKey(hkStreams);
+        }
+
+        return Stream;
+    }
+
+    virtual IStream *
+        GetDefaultBandsStream(IN DWORD grfMode)
+    {
+        HKEY hkStreams;
+        IStream *Stream = NULL;
+
+        if (RegCreateKey(HKEY_LOCAL_MACHINE,
+            TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Streams"),
+            &hkStreams) == ERROR_SUCCESS)
+        {
+            Stream = SHOpenRegStream(hkStreams,
+                TEXT("Desktop"),
+                TEXT("Default Taskbar"),
+                grfMode);
+
+            RegCloseKey(hkStreams);
+        }
+
+        return Stream;
+    }
+
+    virtual HRESULT Load()
+    {
+        IStream *pStm;
+        HRESULT hRet;
+
+        /* Try to load the user's settings */
+        pStm = GetUserBandsStream(STGM_READ);
+        if (pStm != NULL)
+        {
+            hRet = LoadFromStream(pStm);
+
+            TRACE("Loaded user bands settings: 0x%x\n", hRet);
+            pStm->Release();
+        }
+        else
+            hRet = E_FAIL;
+
+        /* If the user's settings couldn't be loaded, try with
+           default settings (ie. when the user logs in for the
+           first time! */
+        if (!SUCCEEDED(hRet))
+        {
+            pStm = GetDefaultBandsStream(STGM_READ);
+            if (pStm != NULL)
+            {
+                hRet = LoadFromStream(pStm);
+
+                TRACE("Loaded default user bands settings: 0x%x\n", hRet);
+                pStm->Release();
+            }
+            else
+                hRet = E_FAIL;
+        }
+
+        return hRet;
+    }
+
+    HRESULT _Init(IN OUT ITrayWindow *tray, OUT HWND *phWndRebar, OUT HWND *phwndTaskSwitch)
+    {
+        IDeskBarClient *pDbc;
+        IDeskBand *pDb;
+        IOleWindow *pOw;
+        HRESULT hRet;
+
+        *phWndRebar = NULL;
+        *phwndTaskSwitch = NULL;
+
+        Tray = tray;
+
+        /* Create a RebarBandSite provided by the shell */
+        hRet = CoCreateInstance(CLSID_RebarBandSite,
+            static_cast<IBandSite*>(this),
+            CLSCTX_INPROC_SERVER,
+            IID_PPV_ARG(IUnknown, &punkInner));
+        if (!SUCCEEDED(hRet))
+        {
+            return hRet;
+        }
+
+        hRet = punkInner->QueryInterface(IID_PPV_ARG(IBandSite, &BandSite));
+        if (!SUCCEEDED(hRet))
+        {
+            return hRet;
+        }
+
+        hRet = punkInner->QueryInterface(IID_PPV_ARG(IWinEventHandler, &WindowEventHandler));
+        if (!SUCCEEDED(hRet))
+        {
+            return hRet;
+        }
+
+        TaskBand = CreateTaskBand(Tray);
+        if (TaskBand != NULL)
+        {
+            /* Add the task band to the site */
+            hRet = BandSite->QueryInterface(IID_PPV_ARG(IDeskBarClient, &pDbc));
+            if (SUCCEEDED(hRet))
+            {
+                hRet = TaskBand->QueryInterface(IID_PPV_ARG(IOleWindow, &pOw));
+                if (SUCCEEDED(hRet))
+                {
+                    /* We cause IDeskBarClient to create the rebar control by passing the new
+                       task band to it. The band reports the tray window handle as window handle
+                       so that IDeskBarClient knows the parent window of the Rebar control that
+                       it wants to create. */
+                    hRet = pDbc->SetDeskBarSite(pOw);
+
+                    if (SUCCEEDED(hRet))
+                    {
+                        /* The Rebar control is now created, we can query the window handle */
+                        hRet = pDbc->GetWindow(&hWndRebar);
+
+                        if (SUCCEEDED(hRet))
+                        {
+                            /* We need to manually remove the RBS_BANDBORDERS style! */
+                            SetWindowStyle(hWndRebar, RBS_BANDBORDERS, 0);
+                        }
+                    }
+
+                    pOw->Release();
+                }
+
+                if (SUCCEEDED(hRet))
+                {
+                    DWORD dwMode = 0;
+
+                    /* Set the Desk Bar mode to the current one */
+
+                    /* FIXME: We need to set the mode (and update) whenever the user docks
+                              the tray window to another monitor edge! */
+
+                    if (!Tray->IsHorizontal())
+                        dwMode = DBIF_VIEWMODE_VERTICAL;
+
+                    hRet = pDbc->SetModeDBC(dwMode);
+                }
+
+                pDbc->Release();
+            }
+
+            /* Load the saved state of the task band site */
+            /* FIXME: We should delay loading shell extensions, also see DBID_DELAYINIT */
+            Load();
+
+            /* Add the task bar band if it hasn't been added already */
+            hRet = AddTaskBand();
+            if (SUCCEEDED(hRet))
+            {
+                hRet = TaskBand->QueryInterface(IID_PPV_ARG(IDeskBand, &pDb));
+                if (SUCCEEDED(hRet))
+                {
+                    hRet = pDb->GetWindow(phwndTaskSwitch);
+                    if (!SUCCEEDED(hRet))
+                        *phwndTaskSwitch = NULL;
+
+                    pDb->Release();
+                }
+            }
+
+            /* Should we send this after showing it? */
+            Update();
+
+            /* FIXME: When should we send this? Does anyone care anyway? */
+            FinishInit();
+
+            /* Activate the band site */
+            Show(
+                TRUE);
+        }
+
+        *phWndRebar = hWndRebar;
+
+        return S_OK;
+    }
+        };
+/*******************************************************************/
+
+ITrayBandSite *
+CreateTrayBandSite(IN OUT ITrayWindow *Tray,
+OUT HWND *phWndRebar,
+OUT HWND *phWndTaskSwitch)
+{
+    HRESULT hr;
+
+    ITrayBandSiteImpl * tb = new ITrayBandSiteImpl();
+
+    if (!tb)
+        return NULL;
+
+    tb->AddRef();
+
+    hr = tb->_Init(Tray, phWndRebar, phWndTaskSwitch);
+    if (FAILED_UNEXPECTEDLY(hr))
+        tb->Release();
+
+    return tb;
+}
diff --git a/base/shell/explorer-new/trayntfy.c b/base/shell/explorer-new/trayntfy.c
deleted file mode 100644 (file)
index 49d4687..0000000
+++ /dev/null
@@ -1,1919 +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 <docobj.h>
-
-/*
- * SysPagerWnd
- */
-static const TCHAR szSysPagerWndClass[] = TEXT("SysPager");
-
-typedef struct _NOTIFY_ITEM
-{
-    struct _NOTIFY_ITEM *next;
-    INT Index;
-    INT IconIndex;
-    NOTIFYICONDATA iconData;
-} NOTIFY_ITEM, *PNOTIFY_ITEM, **PPNOTIFY_ITEM;
-
-typedef struct _SYS_PAGER_DATA
-{
-    HWND hWnd;
-    HWND hWndToolbar;
-    HIMAGELIST SysIcons;
-    PNOTIFY_ITEM NotifyItems;
-    INT ButtonCount;
-    INT VisibleButtonCount;
-} SYS_PAGER_WND_DATA, *PSYS_PAGER_WND_DATA;
-
-// Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy
-typedef struct _SYS_PAGER_COPY_DATA
-{
-    DWORD           cookie;
-    DWORD           notify_code;
-    NOTIFYICONDATA  nicon_data;
-} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA;
-
-static PNOTIFY_ITEM
-SysPagerWnd_CreateNotifyItemData(IN OUT PSYS_PAGER_WND_DATA This)
-{
-    PNOTIFY_ITEM *findNotifyPointer = &This->NotifyItems;
-    PNOTIFY_ITEM notifyItem;
-
-    notifyItem = HeapAlloc(hProcessHeap,
-                           HEAP_ZERO_MEMORY,
-                           sizeof(*notifyItem));
-    if (notifyItem == NULL)
-        return NULL;
-
-    notifyItem->next = NULL;
-
-    while (*findNotifyPointer != NULL)
-    {
-        findNotifyPointer = &(*findNotifyPointer)->next;
-    }
-
-    *findNotifyPointer = notifyItem;
-
-    return notifyItem;
-}
-
-static PPNOTIFY_ITEM
-SysPagerWnd_FindPPNotifyItemByIconData(IN OUT PSYS_PAGER_WND_DATA This,
-                                       IN CONST NOTIFYICONDATA *iconData)
-{
-    PPNOTIFY_ITEM findNotifyPointer = &This->NotifyItems;
-
-    while (*findNotifyPointer != NULL)
-    {
-        if ((*findNotifyPointer)->iconData.hWnd == iconData->hWnd &&
-            (*findNotifyPointer)->iconData.uID == iconData->uID)
-        {
-            return findNotifyPointer;
-        }
-        findNotifyPointer = &(*findNotifyPointer)->next;
-    }
-
-    return NULL;
-}
-
-static PPNOTIFY_ITEM
-SysPagerWnd_FindPPNotifyItemByIndex(IN OUT PSYS_PAGER_WND_DATA This,
-                                    IN WORD wIndex)
-{
-    PPNOTIFY_ITEM findNotifyPointer = &This->NotifyItems;
-
-    while (*findNotifyPointer != NULL)
-    {
-        if ((*findNotifyPointer)->Index == wIndex)
-        {
-            return findNotifyPointer;
-        }
-        findNotifyPointer = &(*findNotifyPointer)->next;
-    }
-
-    return NULL;
-}
-
-static VOID
-SysPagerWnd_UpdateButton(IN OUT PSYS_PAGER_WND_DATA This,
-                         IN CONST NOTIFYICONDATA *iconData)
-{
-    TBBUTTONINFO tbbi = {0};
-    PNOTIFY_ITEM notifyItem;
-    PPNOTIFY_ITEM NotifyPointer;
-
-    NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, iconData);
-    notifyItem = *NotifyPointer;
-
-    tbbi.cbSize = sizeof(tbbi);
-    tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
-    tbbi.idCommand = notifyItem->Index;
-
-    if (iconData->uFlags & NIF_MESSAGE)
-    {
-        notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage;
-    }
-
-    if (iconData->uFlags & NIF_ICON)
-    {
-        tbbi.dwMask |= TBIF_IMAGE;
-        notifyItem->IconIndex = tbbi.iImage = ImageList_AddIcon(This->SysIcons, iconData->hIcon);
-    }
-
-    if (iconData->uFlags & NIF_TIP)
-    {
-        StringCchCopy(notifyItem->iconData.szTip, _countof(notifyItem->iconData.szTip), iconData->szTip);
-    }
-
-    if (iconData->uFlags & NIF_STATE)
-    {
-        if (iconData->dwStateMask & NIS_HIDDEN &&
-            (notifyItem->iconData.dwState & NIS_HIDDEN) != (iconData->dwState & NIS_HIDDEN))
-        {
-            tbbi.dwMask |= TBIF_STATE;
-            if (iconData->dwState & NIS_HIDDEN)
-            {
-                tbbi.fsState |= TBSTATE_HIDDEN;
-                This->VisibleButtonCount--;
-            }
-            else
-            {
-                tbbi.fsState &= ~TBSTATE_HIDDEN;
-                This->VisibleButtonCount++;
-            }
-        }
-
-        notifyItem->iconData.dwState &= ~iconData->dwStateMask;
-        notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask);
-    }
-
-    /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
-
-    SendMessage(This->hWndToolbar,
-                TB_SETBUTTONINFO,
-                (WPARAM)notifyItem->Index,
-                (LPARAM)&tbbi);
-}
-
-
-static VOID
-SysPagerWnd_AddButton(IN OUT PSYS_PAGER_WND_DATA This,
-                      IN CONST NOTIFYICONDATA *iconData)
-{
-    TBBUTTON tbBtn;
-    PNOTIFY_ITEM notifyItem;
-    TCHAR text[] = TEXT("");
-
-    notifyItem = SysPagerWnd_CreateNotifyItemData(This);
-
-    notifyItem->next = NULL;
-    notifyItem->Index = This->ButtonCount;
-    This->ButtonCount++;
-    This->VisibleButtonCount++;
-
-    notifyItem->iconData.hWnd = iconData->hWnd;
-    notifyItem->iconData.uID = iconData->uID;
-
-    tbBtn.fsState = TBSTATE_ENABLED;
-    tbBtn.fsStyle = BTNS_NOPREFIX;
-    tbBtn.dwData = notifyItem->Index;
-
-    tbBtn.iString = (INT_PTR)text;
-    tbBtn.idCommand = notifyItem->Index;
-
-    if (iconData->uFlags & NIF_MESSAGE)
-    {
-        notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage;
-    }
-
-    if (iconData->uFlags & NIF_ICON)
-    {
-        notifyItem->IconIndex = tbBtn.iBitmap = ImageList_AddIcon(This->SysIcons, iconData->hIcon);
-    }
-
-    /* TODO: support NIF_TIP */
-
-    if (iconData->uFlags & NIF_STATE)
-    {
-        notifyItem->iconData.dwState &= ~iconData->dwStateMask;
-        notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask);
-        if (notifyItem->iconData.dwState & NIS_HIDDEN)
-        {
-            tbBtn.fsState |= TBSTATE_HIDDEN;
-            This->VisibleButtonCount--;
-        }
-
-    }
-
-    /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
-
-    SendMessage(This->hWndToolbar,
-                TB_INSERTBUTTON,
-                notifyItem->Index,
-                (LPARAM)&tbBtn);
-
-    SendMessage(This->hWndToolbar,
-                TB_SETBUTTONSIZE,
-                0,
-                MAKELONG(16, 16));
-}
-
-static VOID
-SysPagerWnd_RemoveButton(IN OUT PSYS_PAGER_WND_DATA This,
-                         IN CONST NOTIFYICONDATA *iconData)
-{
-    PPNOTIFY_ITEM NotifyPointer;
-
-    NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This, iconData);
-    if (NotifyPointer)
-    {
-        PNOTIFY_ITEM deleteItem;
-        PNOTIFY_ITEM updateItem;
-        deleteItem = *NotifyPointer;
-
-        SendMessage(This->hWndToolbar,
-                    TB_DELETEBUTTON,
-                    deleteItem->Index,
-                    0);
-
-        *NotifyPointer = updateItem = deleteItem->next;
-
-        if (!(deleteItem->iconData.dwState & NIS_HIDDEN))
-            This->VisibleButtonCount--;
-        HeapFree(hProcessHeap,
-                 0,
-                 deleteItem);
-        This->ButtonCount--;
-
-        while (updateItem != NULL)
-        {
-            TBBUTTONINFO tbbi;
-            updateItem->Index--;
-            tbbi.cbSize = sizeof(tbbi);
-            tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
-            tbbi.idCommand = updateItem->Index;
-
-            SendMessage(This->hWndToolbar,
-                        TB_SETBUTTONINFO,
-                        updateItem->Index,
-                        (LPARAM)&tbbi);
-
-            updateItem = updateItem->next;
-        }
-    }
-}
-
-static VOID
-SysPagerWnd_HandleButtonClick(IN OUT PSYS_PAGER_WND_DATA This,
-                              IN WORD wIndex,
-                              IN UINT uMsg,
-                              IN WPARAM wParam)
-{
-    PPNOTIFY_ITEM NotifyPointer;
-
-    NotifyPointer = SysPagerWnd_FindPPNotifyItemByIndex(This, wIndex);
-    if (NotifyPointer)
-    {
-        PNOTIFY_ITEM notifyItem;
-        notifyItem = *NotifyPointer;
-
-        if (IsWindow(notifyItem->iconData.hWnd))
-        {
-            if (uMsg == WM_MOUSEMOVE ||
-                uMsg == WM_LBUTTONDOWN ||
-                uMsg == WM_MBUTTONDOWN ||
-                uMsg == WM_RBUTTONDOWN)
-            {
-                PostMessage(notifyItem->iconData.hWnd,
-                            notifyItem->iconData.uCallbackMessage,
-                            notifyItem->iconData.uID,
-                            uMsg);
-            }
-            else
-            {
-                DWORD pid;
-                GetWindowThreadProcessId(notifyItem->iconData.hWnd, &pid);
-                if (pid == GetCurrentProcessId())
-                {
-                    PostMessage(notifyItem->iconData.hWnd,
-                                notifyItem->iconData.uCallbackMessage,
-                                notifyItem->iconData.uID,
-                                uMsg);
-                }
-                else
-                {
-                    SendMessage(notifyItem->iconData.hWnd,
-                                notifyItem->iconData.uCallbackMessage,
-                                notifyItem->iconData.uID,
-                                uMsg);
-                }
-            }
-        }
-    }
-}
-
-static VOID
-SysPagerWnd_DrawBackground(IN HWND hwnd,
-                           IN HDC hdc)
-{
-    RECT rect;
-
-    GetClientRect(hwnd, &rect);
-    DrawThemeParentBackground(hwnd, hdc, &rect);
-}
-
-static LRESULT CALLBACK
-SysPagerWnd_ToolbarSubclassedProc(IN HWND hWnd,
-                                  IN UINT msg,
-                                  IN WPARAM wParam,
-                                  IN LPARAM lParam,
-                                  IN UINT_PTR uIdSubclass,
-                                  IN DWORD_PTR dwRefData)
-{
-    if (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST)
-    {
-        HWND parent = GetParent(hWnd);
-
-        if (parent)
-        {
-            SendMessage(parent, msg, wParam, lParam);
-        }
-    }
-
-    return DefSubclassProc(hWnd, msg, wParam, lParam);
-}
-
-static VOID
-SysPagerWnd_Create(IN OUT PSYS_PAGER_WND_DATA This)
-{
-    DWORD styles = 
-        WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
-        TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT |
-        CCS_TOP | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER;
-    DWORD exStyles = WS_EX_TOOLWINDOW;
-
-    This->hWndToolbar = CreateWindowEx(exStyles,
-                                       TOOLBARCLASSNAME,
-                                       NULL,
-                                       styles,
-                                       0,
-                                       0,
-                                       0,
-                                       0,
-                                       This->hWnd,
-                                       NULL,
-                                       hExplorerInstance,
-                                       NULL);
-    if (This->hWndToolbar != NULL)
-    {
-        SIZE BtnSize;
-        SetWindowTheme(This->hWndToolbar, L"TrayNotify", NULL);
-        /* Identify the version we're using */
-        SendMessage(This->hWndToolbar,
-                    TB_BUTTONSTRUCTSIZE,
-                    sizeof(TBBUTTON),
-                    0);
-
-        This->SysIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000);
-        SendMessage(This->hWndToolbar, TB_SETIMAGELIST, 0, (LPARAM)This->SysIcons);
-
-        BtnSize.cx = BtnSize.cy = 18;
-        SendMessage(This->hWndToolbar,
-                    TB_SETBUTTONSIZE,
-                    0,
-                    MAKELONG(BtnSize.cx, BtnSize.cy));
-
-        SetWindowSubclass(This->hWndToolbar,
-                          SysPagerWnd_ToolbarSubclassedProc,
-                          2,
-                          (DWORD_PTR)This);
-    }
-}
-
-static VOID
-SysPagerWnd_NCDestroy(IN OUT PSYS_PAGER_WND_DATA This)
-{
-    /* Free allocated resources */
-    SetWindowLongPtr(This->hWnd,
-                     0,
-                     0);
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-static VOID
-SysPagerWnd_NotifyMsg(IN HWND hwnd,
-                      IN WPARAM wParam,
-                      IN LPARAM lParam)
-{
-    PSYS_PAGER_WND_DATA This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0);
-
-    PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT)lParam;
-    if (cpData->dwData == 1)
-    {
-        SYS_PAGER_COPY_DATA * data;
-        NOTIFYICONDATA *iconData;
-        HWND parentHWND;
-        RECT windowRect;
-        parentHWND = GetParent(This->hWnd);
-        parentHWND = GetParent(parentHWND);
-        GetClientRect(parentHWND, &windowRect);
-
-        data = (PSYS_PAGER_COPY_DATA) cpData->lpData;
-        iconData = &data->nicon_data;
-
-        switch (data->notify_code)
-        {
-            case NIM_ADD:
-            {
-                PPNOTIFY_ITEM NotifyPointer;
-
-                NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This,
-                                                                       iconData);
-                if (!NotifyPointer)
-                {
-                    SysPagerWnd_AddButton(This, iconData);
-                }
-                break;
-            }
-            case NIM_MODIFY:
-            {
-                PPNOTIFY_ITEM NotifyPointer;
-
-                NotifyPointer = SysPagerWnd_FindPPNotifyItemByIconData(This,
-                                                                       iconData);
-                if (!NotifyPointer)
-                {
-                    SysPagerWnd_AddButton(This, iconData);
-                }
-                else
-                {
-                    SysPagerWnd_UpdateButton(This, iconData);
-                }
-                break;
-            }
-            case NIM_DELETE:
-            {
-                SysPagerWnd_RemoveButton(This, iconData);
-                break;
-            }
-            default:
-                TRACE("NotifyMessage received with unknown code %d.\n", data->notify_code);
-                break;
-        }
-        SendMessage(parentHWND,
-                    WM_SIZE,
-                    0,
-                    MAKELONG(windowRect.right - windowRect.left,
-                             windowRect.bottom - windowRect.top));
-    }
-}
-
-static void
-SysPagerWnd_GetSize(IN HWND hwnd,
-                    IN WPARAM wParam,
-                    IN PSIZE size)
-{
-    PSYS_PAGER_WND_DATA This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0);
-    INT rows = 0;
-    TBMETRICS tbm;
-
-    if (wParam) /* horizontal */
-    {
-        rows = size->cy / 24;
-        if (rows == 0)
-            rows++;
-        size->cx = (This->VisibleButtonCount+rows - 1) / rows * 24;
-    }
-    else
-    {
-        rows = size->cx / 24;
-        if (rows == 0)
-            rows++;
-        size->cy = (This->VisibleButtonCount+rows - 1) / rows * 24;
-    }
-
-    tbm.cbSize = sizeof(tbm);
-    tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
-    tbm.cxBarPad = tbm.cyBarPad = 0;
-    tbm.cxButtonSpacing = 0;
-    tbm.cyButtonSpacing = 0;
-
-    SendMessage(This->hWndToolbar,
-                TB_SETMETRICS,
-                0,
-                (LPARAM)&tbm);
-}
-
-static LRESULT CALLBACK
-SysPagerWndProc(IN HWND hwnd,
-                IN UINT uMsg,
-                IN WPARAM wParam,
-                IN LPARAM lParam)
-{
-    PSYS_PAGER_WND_DATA This = NULL;
-    LRESULT Ret = FALSE;
-
-    if (uMsg != WM_NCCREATE)
-    {
-        This = (PSYS_PAGER_WND_DATA)GetWindowLongPtr(hwnd, 0);
-    }
-
-    if (This != NULL || uMsg == WM_NCCREATE)
-    {
-        switch (uMsg)
-        {
-            case WM_ERASEBKGND:
-                if (!IsAppThemed())
-                    break;
-
-                SysPagerWnd_DrawBackground(hwnd, (HDC) wParam);
-                return TRUE;
-
-            case WM_NCCREATE:
-            {
-                LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
-                This = CreateStruct->lpCreateParams;
-                This->hWnd = hwnd;
-                This->NotifyItems = NULL;
-                This->ButtonCount = 0;
-                This->VisibleButtonCount = 0;
-
-                SetWindowLongPtr(hwnd, 0, (LONG_PTR) This);
-
-                return TRUE;
-            }
-            case WM_CREATE:
-                SysPagerWnd_Create(This);
-                break;
-            case WM_NCDESTROY:
-                SysPagerWnd_NCDestroy(This);
-                break;
-
-            case WM_NOTIFY:
-            {
-                const NMHDR * nmh = (const NMHDR *) lParam;
-                if (nmh->code == TBN_GETINFOTIPW)
-                {
-                    NMTBGETINFOTIP * nmtip = (NMTBGETINFOTIP *) lParam;
-                    PPNOTIFY_ITEM ptr = SysPagerWnd_FindPPNotifyItemByIndex(This, nmtip->iItem);
-                    if (ptr)
-                    {
-                        PNOTIFY_ITEM item = *ptr;
-                        StringCchCopy(nmtip->pszText, nmtip->cchTextMax, item->iconData.szTip);
-                    }
-                }
-                else if (nmh->code == NM_CUSTOMDRAW)
-                {
-                    NMCUSTOMDRAW * cdraw = (NMCUSTOMDRAW *) lParam;
-                    switch (cdraw->dwDrawStage)
-                    {
-                    case CDDS_PREPAINT:
-                        return CDRF_NOTIFYITEMDRAW;
-
-                    case CDDS_ITEMPREPAINT:
-                        return TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | TBCDRF_NOETCHEDEFFECT;
-                    }
-                }
-
-                break;
-            }
-
-            case WM_SIZE:
-            {
-                SIZE szClient;
-                szClient.cx = LOWORD(lParam);
-                szClient.cy = HIWORD(lParam);
-
-                Ret = DefWindowProc(hwnd, uMsg, wParam, lParam);
-
-                if (This->hWndToolbar != NULL && This->hWndToolbar != hwnd)
-                {
-                    SetWindowPos(This->hWndToolbar, NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER);
-                }
-
-                return Ret;
-            }
-
-            default:
-                if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
-                {
-                    POINT pt;
-                    INT iBtn;
-
-                    pt.x = LOWORD(lParam);
-                    pt.y = HIWORD(lParam);
-
-                    iBtn = (INT)SendMessage(This->hWndToolbar,
-                                            TB_HITTEST,
-                                            0,
-                                            (LPARAM)&pt);
-
-                    if (iBtn >= 0)
-                    {
-                        SysPagerWnd_HandleButtonClick(This,iBtn,uMsg,wParam);
-                    }
-
-                    return 0;
-                }
-
-                break;
-        }
-    }
-
-    return DefWindowProc(hwnd, uMsg, wParam, lParam);
-}
-
-static HWND
-CreateSysPagerWnd(IN HWND hWndParent,
-                  IN BOOL bVisible)
-{
-    PSYS_PAGER_WND_DATA SpData;
-    DWORD dwStyle;
-    HWND hWnd = NULL;
-
-    SpData = HeapAlloc(hProcessHeap,
-                       HEAP_ZERO_MEMORY,
-                       sizeof(*SpData));
-    if (SpData != NULL)
-    {
-        /* Create the window. The tray window is going to move it to the correct
-           position and resize it as needed. */
-        dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
-        if (bVisible)
-            dwStyle |= WS_VISIBLE;
-
-        hWnd = CreateWindowEx(0,
-                              szSysPagerWndClass,
-                              NULL,
-                              dwStyle,
-                              0,
-                              0,
-                              0,
-                              0,
-                              hWndParent,
-                              NULL,
-                              hExplorerInstance,
-                              SpData);
-
-        if (hWnd != NULL)
-        {
-            SetWindowTheme(hWnd, L"TrayNotify", NULL);
-        }
-        else
-        {
-            HeapFree(hProcessHeap,
-                     0,
-                     SpData);
-        }
-    }
-
-    return hWnd;
-
-}
-
-static BOOL
-RegisterSysPagerWndClass(VOID)
-{
-    WNDCLASS wcTrayClock;
-
-    wcTrayClock.style = CS_DBLCLKS;
-    wcTrayClock.lpfnWndProc = SysPagerWndProc;
-    wcTrayClock.cbClsExtra = 0;
-    wcTrayClock.cbWndExtra = sizeof(PSYS_PAGER_WND_DATA);
-    wcTrayClock.hInstance = hExplorerInstance;
-    wcTrayClock.hIcon = NULL;
-    wcTrayClock.hCursor = LoadCursor(NULL, IDC_ARROW);
-    wcTrayClock.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
-    wcTrayClock.lpszMenuName = NULL;
-    wcTrayClock.lpszClassName = szSysPagerWndClass;
-
-    return RegisterClass(&wcTrayClock) != 0;
-}
-
-static VOID
-UnregisterSysPagerWndClass(VOID)
-{
-    UnregisterClass(szSysPagerWndClass,
-                    hExplorerInstance);
-}
-
-/*
- * TrayClockWnd
- */
-
-static const TCHAR szTrayClockWndClass[] = TEXT("TrayClockWClass");
-
-#define ID_TRAYCLOCK_TIMER  0
-#define ID_TRAYCLOCK_TIMER_INIT 1
-
-static const struct
-{
-    BOOL IsTime;
-    DWORD dwFormatFlags;
-    LPCTSTR lpFormat;
-} ClockWndFormats[] = {
-    { TRUE, 0, NULL },
-    { FALSE, 0, TEXT("dddd") },
-    { FALSE, DATE_SHORTDATE, NULL }
-};
-
-#define CLOCKWND_FORMAT_COUNT (sizeof(ClockWndFormats) / sizeof(ClockWndFormats[0]))
-
-#define TRAY_CLOCK_WND_SPACING_X    0
-#define TRAY_CLOCK_WND_SPACING_Y    0
-
-typedef struct _TRAY_CLOCK_WND_DATA
-{
-    HWND hWnd;
-    HWND hWndNotify;
-    HFONT hFont;
-    COLORREF textColor;
-    RECT rcText;
-    SYSTEMTIME LocalTime;
-
-    union
-    {
-        DWORD dwFlags;
-        struct
-        {
-            DWORD IsTimerEnabled : 1;
-            DWORD IsInitTimerEnabled : 1;
-            DWORD LinesMeasured : 1;
-            DWORD IsHorizontal : 1;
-        };
-    };
-    DWORD LineSpacing;
-    SIZE CurrentSize;
-    WORD VisibleLines;
-    SIZE LineSizes[CLOCKWND_FORMAT_COUNT];
-    TCHAR szLines[CLOCKWND_FORMAT_COUNT][48];
-} TRAY_CLOCK_WND_DATA, *PTRAY_CLOCK_WND_DATA;
-
-static VOID
-TrayClockWnd_SetFont(IN OUT PTRAY_CLOCK_WND_DATA This,
-                     IN HFONT hNewFont,
-                     IN BOOL bRedraw);
-
-static VOID
-TrayClockWnd_UpdateTheme(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    LOGFONTW clockFont;
-    HTHEME clockTheme;
-    HFONT hFont;
-
-    clockTheme = OpenThemeData(This->hWnd, L"Clock");
-
-    if (clockTheme)
-    {
-        GetThemeFont(clockTheme,
-                     NULL,
-                     CLP_TIME,
-                     0,
-                     TMT_FONT,
-                     &clockFont);
-
-        hFont = CreateFontIndirectW(&clockFont);
-
-        TrayClockWnd_SetFont(This,
-                             hFont,
-                             FALSE);
-
-        GetThemeColor(clockTheme,
-                      CLP_TIME,
-                      0,
-                      TMT_TEXTCOLOR,
-                      &This->textColor);
-    }
-    else
-    {
-        This->textColor = RGB(0,0,0);
-    }
-
-    CloseThemeData(clockTheme);
-}
-
-static BOOL
-TrayClockWnd_MeasureLines(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    HDC hDC;
-    HFONT hPrevFont;
-    INT c, i;
-    BOOL bRet = TRUE;
-
-    hDC = GetDC(This->hWnd);
-    if (hDC != NULL)
-    {
-        hPrevFont = SelectObject(hDC,
-                                 This->hFont);
-
-        for (i = 0;
-             i != CLOCKWND_FORMAT_COUNT && bRet;
-             i++)
-        {
-            if (This->szLines[i][0] != TEXT('\0') &&
-                !GetTextExtentPoint(hDC,
-                                    This->szLines[i],
-                                    _tcslen(This->szLines[i]),
-                                    &This->LineSizes[i]))
-            {
-                bRet = FALSE;
-                break;
-            }
-        }
-
-        SelectObject(hDC,
-                     hPrevFont);
-
-        ReleaseDC(This->hWnd,
-                  hDC);
-
-        if (bRet)
-        {
-            This->LineSpacing = 0;
-
-            /* calculate the line spacing */
-            for (i = 0, c = 0;
-                 i != CLOCKWND_FORMAT_COUNT;
-                 i++)
-            {
-                if (This->LineSizes[i].cx > 0)
-                {
-                    This->LineSpacing += This->LineSizes[i].cy;
-                    c++;
-                }
-            }
-
-            if (c > 0)
-            {
-                /* We want a spaceing of 1/2 line */
-                This->LineSpacing = (This->LineSpacing / c) / 2;
-            }
-
-            return TRUE;
-        }
-    }
-
-    return FALSE;
-}
-
-static WORD
-TrayClockWnd_GetMinimumSize(IN OUT PTRAY_CLOCK_WND_DATA This,
-                            IN BOOL Horizontal,
-                            IN OUT PSIZE pSize)
-{
-    WORD iLinesVisible = 0;
-    INT i;
-    SIZE szMax = { 0, 0 };
-
-    if (!This->LinesMeasured)
-        This->LinesMeasured = TrayClockWnd_MeasureLines(This);
-
-    if (!This->LinesMeasured)
-        return 0;
-
-    for (i = 0;
-         i != CLOCKWND_FORMAT_COUNT;
-         i++)
-    {
-        if (This->LineSizes[i].cx != 0)
-        {
-            if (iLinesVisible > 0)
-            {
-                if (Horizontal)
-                {
-                    if (szMax.cy + This->LineSizes[i].cy + (LONG)This->LineSpacing >
-                        pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y))
-                    {
-                        break;
-                    }
-                }
-                else
-                {
-                    if (This->LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X))
-                        break;
-                }
-
-                /* Add line spacing */
-                szMax.cy += This->LineSpacing;
-            }
-
-            iLinesVisible++;
-
-            /* Increase maximum rectangle */
-            szMax.cy += This->LineSizes[i].cy;
-            if (This->LineSizes[i].cx > szMax.cx - (2 * TRAY_CLOCK_WND_SPACING_X))
-                szMax.cx = This->LineSizes[i].cx + (2 * TRAY_CLOCK_WND_SPACING_X);
-        }
-    }
-
-    szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X;
-    szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y;
-
-    *pSize = szMax;
-
-    return iLinesVisible;
-}
-
-
-static VOID
-TrayClockWnd_UpdateWnd(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    SIZE szPrevCurrent;
-    INT BufSize, iRet, i;
-    RECT rcClient;
-
-    ZeroMemory(This->LineSizes,
-               sizeof(This->LineSizes));
-
-    szPrevCurrent = This->CurrentSize;
-
-    for (i = 0;
-         i != CLOCKWND_FORMAT_COUNT;
-         i++)
-    {
-        This->szLines[i][0] = TEXT('\0');
-        BufSize = sizeof(This->szLines[0]) / sizeof(This->szLines[0][0]);
-
-        if (ClockWndFormats[i].IsTime)
-        {
-            iRet = GetTimeFormat(LOCALE_USER_DEFAULT,
-                                 AdvancedSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
-                                 &This->LocalTime,
-                                 ClockWndFormats[i].lpFormat,
-                                 This->szLines[i],
-                                 BufSize);
-        }
-        else
-        {
-            iRet = GetDateFormat(LOCALE_USER_DEFAULT,
-                                 ClockWndFormats[i].dwFormatFlags,
-                                 &This->LocalTime,
-                                 ClockWndFormats[i].lpFormat,
-                                 This->szLines[i],
-                                 BufSize);
-        }
-
-        if (iRet != 0 && i == 0)
-        {
-            /* Set the window text to the time only */
-            SetWindowText(This->hWnd,
-                          This->szLines[i]);
-        }
-    }
-
-    This->LinesMeasured = TrayClockWnd_MeasureLines(This);
-
-    if (This->LinesMeasured &&
-        GetClientRect(This->hWnd,
-                      &rcClient))
-    {
-        SIZE szWnd;
-
-        szWnd.cx = rcClient.right;
-        szWnd.cy = rcClient.bottom;
-
-        This->VisibleLines = TrayClockWnd_GetMinimumSize(This,
-                                                         This->IsHorizontal,
-                                                         &szWnd);
-        This->CurrentSize = szWnd;
-    }
-
-    if (IsWindowVisible(This->hWnd))
-    {
-        InvalidateRect(This->hWnd,
-                       NULL,
-                       TRUE);
-
-        if (This->hWndNotify != NULL &&
-            (szPrevCurrent.cx != This->CurrentSize.cx ||
-             szPrevCurrent.cy != This->CurrentSize.cy))
-        {
-            NMHDR nmh;
-
-            nmh.hwndFrom = This->hWnd;
-            nmh.idFrom = GetWindowLongPtr(This->hWnd,
-                                          GWLP_ID);
-            nmh.code = NTNWM_REALIGN;
-
-            SendMessage(This->hWndNotify,
-                        WM_NOTIFY,
-                        (WPARAM)nmh.idFrom,
-                        (LPARAM)&nmh);
-        }
-    }
-}
-
-static VOID
-TrayClockWnd_Update(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    GetLocalTime(&This->LocalTime);
-    TrayClockWnd_UpdateWnd(This);
-}
-
-static UINT
-TrayClockWnd_CalculateDueTime(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    UINT uiDueTime;
-
-    /* Calculate the due time */
-    GetLocalTime(&This->LocalTime);
-    uiDueTime = 1000 - (UINT)This->LocalTime.wMilliseconds;
-    if (AdvancedSettings.bShowSeconds)
-        uiDueTime += (UINT)This->LocalTime.wSecond * 100;
-    else
-        uiDueTime += (59 - (UINT)This->LocalTime.wSecond) * 1000;
-
-    if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM)
-        uiDueTime = 1000;
-    else
-    {
-        /* Add an artificial delay of 0.05 seconds to make sure the timer
-           doesn't fire too early*/
-        uiDueTime += 50;
-    }
-
-    return uiDueTime;
-}
-
-static BOOL
-TrayClockWnd_ResetTime(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    UINT uiDueTime;
-    BOOL Ret;
-
-    /* Disable all timers */
-    if (This->IsTimerEnabled)
-    {
-        KillTimer(This->hWnd,
-                  ID_TRAYCLOCK_TIMER);
-        This->IsTimerEnabled = FALSE;
-    }
-
-    if (This->IsInitTimerEnabled)
-    {
-        KillTimer(This->hWnd,
-                  ID_TRAYCLOCK_TIMER_INIT);
-    }
-
-    uiDueTime = TrayClockWnd_CalculateDueTime(This);
-
-    /* Set the new timer */
-    Ret = SetTimer(This->hWnd,
-                   ID_TRAYCLOCK_TIMER_INIT,
-                   uiDueTime,
-                   NULL) != 0;
-    This->IsInitTimerEnabled = Ret;
-
-    /* Update the time */
-    TrayClockWnd_Update(This);
-
-    return Ret;
-}
-
-static VOID
-TrayClockWnd_CalibrateTimer(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    UINT uiDueTime;
-    BOOL Ret;
-    UINT uiWait1, uiWait2;
-
-    /* Kill the initialization timer */
-    KillTimer(This->hWnd,
-              ID_TRAYCLOCK_TIMER_INIT);
-    This->IsInitTimerEnabled = FALSE;
-
-    uiDueTime = TrayClockWnd_CalculateDueTime(This);
-
-    if (AdvancedSettings.bShowSeconds)
-    {
-        uiWait1 = 1000 - 200;
-        uiWait2 = 1000;
-    }
-    else
-    {
-        uiWait1 = 60 * 1000 - 200;
-        uiWait2 = 60 * 1000;
-    }
-
-    if (uiDueTime > uiWait1)
-    {
-        /* The update of the clock will be up to 200 ms late, but that's
-           acceptable. We're going to setup a timer that fires depending
-           uiWait2. */
-        Ret = SetTimer(This->hWnd,
-                       ID_TRAYCLOCK_TIMER,
-                       uiWait2,
-                       NULL) != 0;
-        This->IsTimerEnabled = Ret;
-
-        /* Update the time */
-        TrayClockWnd_Update(This);
-    }
-    else
-    {
-        /* Recalibrate the timer and recalculate again when the current
-           minute/second ends. */
-        TrayClockWnd_ResetTime(This);
-    }
-}
-
-static VOID
-TrayClockWnd_NCDestroy(IN OUT PTRAY_CLOCK_WND_DATA This)
-{
-    /* Disable all timers */
-    if (This->IsTimerEnabled)
-    {
-        KillTimer(This->hWnd,
-                  ID_TRAYCLOCK_TIMER);
-    }
-
-    if (This->IsInitTimerEnabled)
-    {
-        KillTimer(This->hWnd,
-                  ID_TRAYCLOCK_TIMER_INIT);
-    }
-
-    /* Free allocated resources */
-    SetWindowLongPtr(This->hWnd,
-                     0,
-                     0);
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-static VOID
-TrayClockWnd_Paint(IN OUT PTRAY_CLOCK_WND_DATA This,
-                   IN HDC hDC)
-{
-    RECT rcClient;
-    HFONT hPrevFont;
-    int iPrevBkMode, i, line;
-
-    if (This->LinesMeasured &&
-        GetClientRect(This->hWnd,
-                      &rcClient))
-    {
-        iPrevBkMode = SetBkMode(hDC,
-                                TRANSPARENT);
-
-        SetTextColor(hDC, This->textColor);
-
-        hPrevFont = SelectObject(hDC,
-                                 This->hFont);
-
-        rcClient.left = (rcClient.right / 2) - (This->CurrentSize.cx / 2);
-        rcClient.top = (rcClient.bottom / 2) - (This->CurrentSize.cy / 2);
-        rcClient.right = rcClient.left + This->CurrentSize.cx;
-        rcClient.bottom = rcClient.top + This->CurrentSize.cy;
-
-        for (i = 0, line = 0;
-             i != CLOCKWND_FORMAT_COUNT && line < This->VisibleLines;
-             i++)
-        {
-            if (This->LineSizes[i].cx != 0)
-            {
-                TextOut(hDC,
-                        rcClient.left + (This->CurrentSize.cx / 2) - (This->LineSizes[i].cx / 2) +
-                            TRAY_CLOCK_WND_SPACING_X,
-                        rcClient.top + TRAY_CLOCK_WND_SPACING_Y,
-                        This->szLines[i],
-                        _tcslen(This->szLines[i]));
-
-                rcClient.top += This->LineSizes[i].cy + This->LineSpacing;
-                line++;
-            }
-        }
-
-        SelectObject(hDC,
-                     hPrevFont);
-
-        SetBkMode(hDC,
-                  iPrevBkMode);
-    }
-}
-
-static VOID
-TrayClockWnd_SetFont(IN OUT PTRAY_CLOCK_WND_DATA This,
-                     IN HFONT hNewFont,
-                     IN BOOL bRedraw)
-{
-    This->hFont = hNewFont;
-    This->LinesMeasured = TrayClockWnd_MeasureLines(This);
-    if (bRedraw)
-    {
-        InvalidateRect(This->hWnd,
-                       NULL,
-                       TRUE);
-    }
-}
-
-static VOID
-TrayClockWnd_DrawBackground(IN HWND hwnd,
-                            IN HDC hdc)
-{
-    RECT rect;
-
-    GetClientRect(hwnd, &rect);
-    DrawThemeParentBackground(hwnd, hdc, &rect);
-}
-
-static LRESULT CALLBACK
-TrayClockWndProc(IN HWND hwnd,
-                 IN UINT uMsg,
-                 IN WPARAM wParam,
-                 IN LPARAM lParam)
-{
-    PTRAY_CLOCK_WND_DATA This = NULL;
-
-    if (uMsg != WM_NCCREATE)
-    {
-        This = (PTRAY_CLOCK_WND_DATA)GetWindowLongPtr(hwnd,
-                                                      0);
-    }
-
-    if (This != NULL || uMsg == WM_NCCREATE)
-    {
-        switch (uMsg)
-        {
-            case WM_THEMECHANGED:
-                TrayClockWnd_UpdateTheme(This);
-                break;
-            case WM_ERASEBKGND:
-                if (!IsAppThemed())
-                    break;
-
-                TrayClockWnd_DrawBackground(hwnd, (HDC) wParam);
-                return TRUE;
-            case WM_PAINT:
-            case WM_PRINTCLIENT:
-            {
-                PAINTSTRUCT ps;
-                HDC hDC = (HDC)wParam;
-
-                if (wParam == 0)
-                {
-                    hDC = BeginPaint(This->hWnd, &ps);
-                }
-
-                if (hDC != NULL)
-                {
-                    TrayClockWnd_Paint(This, hDC);
-
-                    if (wParam == 0)
-                    {
-                        EndPaint(This->hWnd, &ps);
-                    }
-                }
-                break;
-            }
-
-            case WM_TIMER:
-                switch (wParam)
-                {
-                    case ID_TRAYCLOCK_TIMER:
-                        TrayClockWnd_Update(This);
-                        break;
-
-                    case ID_TRAYCLOCK_TIMER_INIT:
-                        TrayClockWnd_CalibrateTimer(This);
-                        break;
-                }
-                break;
-
-            case WM_NCHITTEST:
-                /* We want the user to be able to drag the task bar when clicking the clock */
-                return HTTRANSPARENT;
-
-            case TCWM_GETMINIMUMSIZE:
-            {
-                This->IsHorizontal = (BOOL)wParam;
-
-                return (LRESULT) TrayClockWnd_GetMinimumSize(This, (BOOL) wParam, (PSIZE) lParam) != 0;
-            }
-
-            case TCWM_UPDATETIME:
-            {
-                return (LRESULT)TrayClockWnd_ResetTime(This);
-            }
-
-            case WM_NCCREATE:
-            {
-                LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
-                This = (PTRAY_CLOCK_WND_DATA)CreateStruct->lpCreateParams;
-                This->hWnd = hwnd;
-                This->hWndNotify = CreateStruct->hwndParent;
-
-                SetWindowLongPtr(hwnd, 0, (LONG_PTR) This);
-                TrayClockWnd_UpdateTheme(This);
-
-                return TRUE;
-            }
-
-            case WM_SETFONT:
-            {
-                TrayClockWnd_SetFont(This,
-                                     (HFONT)wParam,
-                                     (BOOL)LOWORD(lParam));
-                break;
-            }
-
-            case WM_CREATE:
-                TrayClockWnd_ResetTime(This);
-                break;
-
-            case WM_NCDESTROY:
-                TrayClockWnd_NCDestroy(This);
-                break;
-
-            case WM_SIZE:
-            {
-                SIZE szClient;
-
-                szClient.cx = LOWORD(lParam);
-                szClient.cy = HIWORD(lParam);
-                This->VisibleLines = TrayClockWnd_GetMinimumSize(This,
-                                                                 This->IsHorizontal,
-                                                                 &szClient);
-                This->CurrentSize = szClient;
-
-                InvalidateRect(This->hWnd,
-                               NULL,
-                               TRUE);
-                break;
-            }
-        }
-    }
-
-    return DefWindowProc(hwnd, uMsg, wParam, lParam);
-}
-
-static HWND
-CreateTrayClockWnd(IN HWND hWndParent,
-                   IN BOOL bVisible)
-{
-    PTRAY_CLOCK_WND_DATA TcData;
-    DWORD dwStyle;
-    HWND hWnd = NULL;
-
-    TcData = HeapAlloc(hProcessHeap,
-                       HEAP_ZERO_MEMORY,
-                       sizeof(*TcData));
-    if (TcData != NULL)
-    {
-        TcData->IsHorizontal = TRUE;
-        /* Create the window. The tray window is going to move it to the correct
-           position and resize it as needed. */
-        dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
-        if (bVisible)
-            dwStyle |= WS_VISIBLE;
-
-        hWnd = CreateWindowEx(0,
-                              szTrayClockWndClass,
-                              NULL,
-                              dwStyle,
-                              0,
-                              0,
-                              0,
-                              0,
-                              hWndParent,
-                              NULL,
-                              hExplorerInstance,
-                              TcData);
-
-        if (hWnd != NULL)
-        {
-            SetWindowTheme(hWnd, L"TrayNotify", NULL);
-        }
-        else
-        {
-            HeapFree(hProcessHeap,
-                     0,
-                     TcData);
-        }
-    }
-
-    return hWnd;
-
-}
-
-static BOOL
-RegisterTrayClockWndClass(VOID)
-{
-    WNDCLASS wcTrayClock;
-
-    wcTrayClock.style = CS_DBLCLKS;
-    wcTrayClock.lpfnWndProc = TrayClockWndProc;
-    wcTrayClock.cbClsExtra = 0;
-    wcTrayClock.cbWndExtra = sizeof(PTRAY_CLOCK_WND_DATA);
-    wcTrayClock.hInstance = hExplorerInstance;
-    wcTrayClock.hIcon = NULL;
-    wcTrayClock.hCursor = LoadCursor(NULL,
-                                     IDC_ARROW);
-    wcTrayClock.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
-    wcTrayClock.lpszMenuName = NULL;
-    wcTrayClock.lpszClassName = szTrayClockWndClass;
-
-    return RegisterClass(&wcTrayClock) != 0;
-}
-
-static VOID
-UnregisterTrayClockWndClass(VOID)
-{
-    UnregisterClass(szTrayClockWndClass,
-                    hExplorerInstance);
-}
-
-/*
- * TrayNotifyWnd
- */
-
-static const TCHAR szTrayNotifyWndClass[] = TEXT("TrayNotifyWnd");
-
-#define TRAY_NOTIFY_WND_SPACING_X   2
-#define TRAY_NOTIFY_WND_SPACING_Y   2
-
-typedef struct _TRAY_NOTIFY_WND_DATA
-{
-    HWND hWnd;
-    HWND hWndTrayClock;
-    HWND hWndNotify;
-    HWND hWndSysPager;
-    HTHEME TrayTheme;
-    SIZE szTrayClockMin;
-    SIZE szTrayNotify;
-    MARGINS ContentMargin;
-    ITrayWindow *TrayWindow;
-    HFONT hFontClock;
-    union
-    {
-        DWORD dwFlags;
-        struct
-        {
-            DWORD HideClock : 1;
-            DWORD IsHorizontal : 1;
-        };
-    };
-} TRAY_NOTIFY_WND_DATA, *PTRAY_NOTIFY_WND_DATA;
-
-static VOID
-TrayNotifyWnd_UpdateTheme(IN OUT PTRAY_NOTIFY_WND_DATA This)
-{
-    LONG_PTR style;
-
-    if (This->TrayTheme)
-        CloseThemeData(This->TrayTheme);
-
-    if (IsThemeActive())
-        This->TrayTheme = OpenThemeData(This->hWnd, L"TrayNotify");
-    else
-        This->TrayTheme = 0;
-
-    if (This->TrayTheme)
-    {
-        style = GetWindowLong(This->hWnd, GWL_EXSTYLE);
-        style = style & ~WS_EX_STATICEDGE;
-        SetWindowLong(This->hWnd, GWL_EXSTYLE, style);
-
-        GetThemeMargins(This->TrayTheme,
-                        NULL,
-                        TNP_BACKGROUND,
-                        0,
-                        TMT_CONTENTMARGINS,
-                        NULL,
-                        &This->ContentMargin);
-    }
-    else
-    {
-        style = GetWindowLong(This->hWnd, GWL_EXSTYLE);
-        style = style | WS_EX_STATICEDGE;
-        SetWindowLong(This->hWnd, GWL_EXSTYLE, style);
-
-        This->ContentMargin.cxLeftWidth = 0;
-        This->ContentMargin.cxRightWidth = 0;
-        This->ContentMargin.cyTopHeight = 0;
-        This->ContentMargin.cyBottomHeight = 0;
-    }
-}
-
-static VOID
-TrayNotifyWnd_Create(IN OUT PTRAY_NOTIFY_WND_DATA This)
-{
-    This->hWndTrayClock = CreateTrayClockWnd(This->hWnd,
-                                             !This->HideClock);
-
-    This->hWndSysPager = CreateSysPagerWnd(This->hWnd,
-                                           !This->HideClock);
-
-    TrayNotifyWnd_UpdateTheme(This);
-}
-
-static VOID
-TrayNotifyWnd_NCDestroy(IN OUT PTRAY_NOTIFY_WND_DATA This)
-{
-    SetWindowLongPtr(This->hWnd,
-                     0,
-                     0);
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-static BOOL
-TrayNotifyWnd_GetMinimumSize(IN OUT PTRAY_NOTIFY_WND_DATA This,
-                             IN BOOL Horizontal,
-                             IN OUT PSIZE pSize)
-{
-    SIZE szClock = { 0, 0 };
-    SIZE szTray = { 0, 0 };
-
-    This->IsHorizontal = Horizontal;
-    if (This->IsHorizontal)
-        SetWindowTheme(This->hWnd, L"TrayNotifyHoriz", NULL);
-    else
-        SetWindowTheme(This->hWnd, L"TrayNotifyVert", NULL);
-
-    if (!This->HideClock)
-    {
-        if (Horizontal)
-        {
-            szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
-            if (szClock.cy <= 0)
-                goto NoClock;
-        }
-        else
-        {
-            szClock.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X;
-            if (szClock.cx <= 0)
-                goto NoClock;
-        }
-
-        SendMessage(This->hWndTrayClock,
-                    TCWM_GETMINIMUMSIZE,
-                    (WPARAM)Horizontal,
-                    (LPARAM)&szClock);
-
-        This->szTrayClockMin = szClock;
-    }
-    else
-NoClock:
-        This->szTrayClockMin = szClock;
-
-    if (Horizontal)
-    {
-        szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
-    }
-    else
-    {
-        szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X;
-    }
-
-    SysPagerWnd_GetSize(This->hWndSysPager,
-                        Horizontal,
-                        &szTray);
-
-    This->szTrayNotify = szTray;
-
-    if (Horizontal)
-    {
-        pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X;
-
-        if (!This->HideClock)
-            pSize->cx += TRAY_NOTIFY_WND_SPACING_X + This->szTrayClockMin.cx;
-
-        pSize->cx += szTray.cx;
-    }
-    else
-    {
-        pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y;
-
-        if (!This->HideClock)
-            pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + This->szTrayClockMin.cy;
-
-        pSize->cy += szTray.cy;
-    }
-
-    pSize->cy += This->ContentMargin.cyTopHeight + This->ContentMargin.cyBottomHeight;
-    pSize->cx += This->ContentMargin.cxLeftWidth + This->ContentMargin.cxRightWidth;
-
-    return TRUE;
-}
-
-static VOID
-TrayNotifyWnd_Size(IN OUT PTRAY_NOTIFY_WND_DATA This,
-                   IN const SIZE *pszClient)
-{
-    if (!This->HideClock)
-    {
-        POINT ptClock;
-        SIZE szClock;
-
-        if (This->IsHorizontal)
-        {
-            ptClock.x = pszClient->cx - TRAY_NOTIFY_WND_SPACING_X - This->szTrayClockMin.cx;
-            ptClock.y = TRAY_NOTIFY_WND_SPACING_Y;
-            szClock.cx = This->szTrayClockMin.cx;
-            szClock.cy = pszClient->cy - (2 * TRAY_NOTIFY_WND_SPACING_Y);
-        }
-        else
-        {
-            ptClock.x = TRAY_NOTIFY_WND_SPACING_X;
-            ptClock.y = pszClient->cy - TRAY_NOTIFY_WND_SPACING_Y - This->szTrayClockMin.cy;
-            szClock.cx = pszClient->cx - (2 * TRAY_NOTIFY_WND_SPACING_X);
-            szClock.cy = This->szTrayClockMin.cy;
-        }
-
-        SetWindowPos(This->hWndTrayClock,
-                     NULL,
-                     ptClock.x,
-                     ptClock.y,
-                     szClock.cx,
-                     szClock.cy,
-                     SWP_NOZORDER);
-
-        if (This->IsHorizontal)
-        {
-            ptClock.x -= This->szTrayNotify.cx;
-        }
-        else
-        {
-            ptClock.y -= This->szTrayNotify.cy;
-        }
-
-        SetWindowPos(This->hWndSysPager,
-                     NULL,
-                     ptClock.x,
-                     ptClock.y,
-                     This->szTrayNotify.cx,
-                     This->szTrayNotify.cy,
-                     SWP_NOZORDER);
-    }
-}
-
-static VOID
-TrayNotifyWnd_DrawBackground(IN HWND hwnd,
-                             IN HDC hdc)
-{
-    PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0);
-    RECT rect;
-
-    GetClientRect(hwnd, &rect);
-
-    DrawThemeParentBackground(hwnd, hdc, &rect);
-    DrawThemeBackground(This->TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0);
-}
-
-VOID
-TrayNotify_NotifyMsg(IN HWND hwnd,
-                     IN WPARAM wParam,
-                     IN LPARAM lParam)
-{
-    PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0);
-    if (This->hWndSysPager)
-    {
-        SysPagerWnd_NotifyMsg(This->hWndSysPager,
-                              wParam,
-                              lParam);
-    }
-}
-
-BOOL
-TrayNotify_GetClockRect(IN HWND hwnd,
-                        OUT PRECT rcClock)
-{
-    PTRAY_NOTIFY_WND_DATA This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0);
-    if (!IsWindowVisible(This->hWndTrayClock))
-        return FALSE;
-
-    return GetWindowRect(This->hWndTrayClock, rcClock);
-}
-
-static LRESULT CALLBACK
-TrayNotifyWndProc(IN HWND hwnd,
-                  IN UINT uMsg,
-                  IN WPARAM wParam,
-                  IN LPARAM lParam)
-{
-    PTRAY_NOTIFY_WND_DATA This = NULL;
-
-    if (uMsg != WM_NCCREATE)
-    {
-        This = (PTRAY_NOTIFY_WND_DATA)GetWindowLongPtr(hwnd, 0);
-    }
-
-    if (This != NULL || uMsg == WM_NCCREATE)
-    {
-        switch (uMsg)
-        {
-            case WM_THEMECHANGED:
-                TrayNotifyWnd_UpdateTheme(This);
-                return 0;
-            case WM_ERASEBKGND:
-                if (!This->TrayTheme)
-                    break;
-                TrayNotifyWnd_DrawBackground(hwnd, (HDC) wParam);
-                return 0;
-            case TNWM_GETMINIMUMSIZE:
-            {
-                return (LRESULT) TrayNotifyWnd_GetMinimumSize(This, (BOOL) wParam, (PSIZE) lParam);
-            }
-
-            case TNWM_UPDATETIME:
-            {
-                if (This->hWndTrayClock != NULL)
-                {
-                    /* Forward the message to the tray clock window procedure */
-                    return TrayClockWndProc(This->hWndTrayClock, TCWM_UPDATETIME, wParam, lParam);
-                }
-                return 0;
-            }
-
-            case WM_SIZE:
-            {
-                SIZE szClient;
-
-                szClient.cx = LOWORD(lParam);
-                szClient.cy = HIWORD(lParam);
-
-                TrayNotifyWnd_Size(This, &szClient);
-                return 0;
-            }
-
-            case WM_NCHITTEST:
-                /* We want the user to be able to drag the task bar when clicking the
-                   tray notification window */
-                return HTTRANSPARENT;
-            case TNWM_SHOWCLOCK:
-            {
-                BOOL PrevHidden = This->HideClock;
-                This->HideClock = (wParam == 0);
-
-                if (This->hWndTrayClock != NULL && PrevHidden != This->HideClock)
-                {
-                    ShowWindow(This->hWndTrayClock,
-                               This->HideClock ? SW_HIDE : SW_SHOW);
-                }
-
-                return (LRESULT) (!PrevHidden);
-            }
-
-            case WM_NOTIFY:
-            {
-                const NMHDR *nmh = (const NMHDR *)lParam;
-
-                if (nmh->hwndFrom == This->hWndTrayClock)
-                {
-                    /* Pass down notifications */
-                    return SendMessage(This->hWndNotify, WM_NOTIFY, wParam, lParam);
-                }
-                return 0;
-            }
-
-            case WM_SETFONT:
-            {
-                if (This->hWndTrayClock != NULL)
-                {
-                    SendMessage(This->hWndTrayClock,
-                                WM_SETFONT,
-                                wParam,
-                                lParam);
-                }
-                break;
-            }
-
-            case WM_NCCREATE:
-            {
-                LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
-                This = (PTRAY_NOTIFY_WND_DATA)CreateStruct->lpCreateParams;
-                This->hWnd = hwnd;
-                This->hWndNotify = CreateStruct->hwndParent;
-
-                SetWindowLongPtr(hwnd, 0, (LONG_PTR) This);
-
-                return TRUE;
-            }
-
-            case WM_CREATE:
-                TrayNotifyWnd_Create(This);
-                return 0;
-
-            case WM_NCDESTROY:
-                TrayNotifyWnd_NCDestroy(This);
-                return 0;
-        }
-    }
-
-    return DefWindowProc(hwnd, uMsg, wParam, lParam);
-}
-
-HWND
-CreateTrayNotifyWnd(IN OUT ITrayWindow *TrayWindow,
-                    IN BOOL bHideClock)
-{
-    PTRAY_NOTIFY_WND_DATA TnData;
-    HWND hWndTrayWindow;
-    HWND hWnd = NULL;
-
-    hWndTrayWindow = ITrayWindow_GetHWND(TrayWindow);
-    if (hWndTrayWindow == NULL)
-        return NULL;
-
-    TnData = HeapAlloc(hProcessHeap,
-                       HEAP_ZERO_MEMORY,
-                       sizeof(*TnData));
-    if (TnData != NULL)
-    {
-        TnData->TrayWindow = TrayWindow;
-        TnData->HideClock = bHideClock;
-
-        /* Create the window. The tray window is going to move it to the correct
-           position and resize it as needed. */
-        hWnd = CreateWindowEx(WS_EX_STATICEDGE,
-                              szTrayNotifyWndClass,
-                              NULL,
-                              WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
-                              0,
-                              0,
-                              0,
-                              0,
-                              hWndTrayWindow,
-                              NULL,
-                              hExplorerInstance,
-                              TnData);
-
-        if (hWnd == NULL)
-        {
-            HeapFree(hProcessHeap,
-                     0,
-                     TnData);
-        }
-    }
-
-    return hWnd;
-}
-
-BOOL
-RegisterTrayNotifyWndClass(VOID)
-{
-    WNDCLASS wcTrayWnd;
-    BOOL Ret;
-
-    wcTrayWnd.style = CS_DBLCLKS;
-    wcTrayWnd.lpfnWndProc = TrayNotifyWndProc;
-    wcTrayWnd.cbClsExtra = 0;
-    wcTrayWnd.cbWndExtra = sizeof(PTRAY_NOTIFY_WND_DATA);
-    wcTrayWnd.hInstance = hExplorerInstance;
-    wcTrayWnd.hIcon = NULL;
-    wcTrayWnd.hCursor = LoadCursor(NULL,
-                                   IDC_ARROW);
-    wcTrayWnd.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
-    wcTrayWnd.lpszMenuName = NULL;
-    wcTrayWnd.lpszClassName = szTrayNotifyWndClass;
-
-    Ret = RegisterClass(&wcTrayWnd) != 0;
-
-    if (Ret)
-    {
-        Ret = RegisterTrayClockWndClass();
-        if (!Ret)
-        {
-            UnregisterClass(szTrayNotifyWndClass,
-                            hExplorerInstance);
-        }
-        RegisterSysPagerWndClass();
-    }
-
-    return Ret;
-}
-
-VOID
-UnregisterTrayNotifyWndClass(VOID)
-{
-    UnregisterTrayClockWndClass();
-
-    UnregisterSysPagerWndClass();
-
-    UnregisterClass(szTrayNotifyWndClass,
-                    hExplorerInstance);
-}
diff --git a/base/shell/explorer-new/trayntfy.cpp b/base/shell/explorer-new/trayntfy.cpp
new file mode 100644 (file)
index 0000000..87b6902
--- /dev/null
@@ -0,0 +1,1618 @@
+/*
+ * 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 <docobj.h>
+
+typedef unsigned short USHORT;
+
+/*
+ * SysPagerWnd
+ */
+static const WCHAR szSysPagerWndClass [] = TEXT("SysPager");
+
+typedef struct _NOTIFY_ITEM
+{
+    struct _NOTIFY_ITEM *next;
+    INT Index;
+    INT IconIndex;
+    NOTIFYICONDATA iconData;
+} NOTIFY_ITEM, *PNOTIFY_ITEM, **PPNOTIFY_ITEM;
+
+// Data comes from shell32/systray.cpp -> TrayNotifyCDS_Dummy
+typedef struct _SYS_PAGER_COPY_DATA
+{
+    DWORD           cookie;
+    DWORD           notify_code;
+    NOTIFYICONDATA  nicon_data;
+} SYS_PAGER_COPY_DATA, *PSYS_PAGER_COPY_DATA;
+
+class CSysPagerWnd :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public CWindowImpl < CSysPagerWnd, CWindow, CControlWinTraits >
+{
+    CContainedWindow NotificationBar;
+
+    HWND hWndToolbar;
+    HIMAGELIST SysIcons;
+    PNOTIFY_ITEM NotifyItems;
+    INT ButtonCount;
+    INT VisibleButtonCount;
+
+public:
+    CSysPagerWnd() :
+        NotificationBar(this, 1),
+        hWndToolbar(NULL),
+        SysIcons(NULL),
+        NotifyItems(NULL),
+        ButtonCount(0),
+        VisibleButtonCount(0)
+    {
+    }
+    virtual ~CSysPagerWnd() { }
+
+    PNOTIFY_ITEM CreateNotifyItemData()
+    {
+        PNOTIFY_ITEM *findNotifyPointer = &NotifyItems;
+        PNOTIFY_ITEM notifyItem;
+
+        notifyItem = (PNOTIFY_ITEM) HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(*notifyItem));
+        if (notifyItem == NULL)
+            return NULL;
+
+        notifyItem->next = NULL;
+
+        while (*findNotifyPointer != NULL)
+        {
+            findNotifyPointer = &(*findNotifyPointer)->next;
+        }
+
+        *findNotifyPointer = notifyItem;
+
+        return notifyItem;
+    }
+
+    PPNOTIFY_ITEM FindPPNotifyItemByIconData(IN CONST NOTIFYICONDATA *iconData)
+    {
+        PPNOTIFY_ITEM findNotifyPointer = &NotifyItems;
+
+        while (*findNotifyPointer != NULL)
+        {
+            if ((*findNotifyPointer)->iconData.hWnd == iconData->hWnd &&
+                (*findNotifyPointer)->iconData.uID == iconData->uID)
+            {
+                return findNotifyPointer;
+            }
+            findNotifyPointer = &(*findNotifyPointer)->next;
+        }
+
+        return NULL;
+    }
+
+    PPNOTIFY_ITEM FindPPNotifyItemByIndex(IN WORD wIndex)
+    {
+        PPNOTIFY_ITEM findNotifyPointer = &NotifyItems;
+
+        while (*findNotifyPointer != NULL)
+        {
+            if ((*findNotifyPointer)->Index == wIndex)
+            {
+                return findNotifyPointer;
+            }
+            findNotifyPointer = &(*findNotifyPointer)->next;
+        }
+
+        return NULL;
+    }
+
+    VOID UpdateButton(IN CONST NOTIFYICONDATA *iconData)
+    {
+        TBBUTTONINFO tbbi = { 0 };
+        PNOTIFY_ITEM notifyItem;
+        PPNOTIFY_ITEM NotifyPointer;
+
+        NotifyPointer = FindPPNotifyItemByIconData(iconData);
+        notifyItem = *NotifyPointer;
+
+        tbbi.cbSize = sizeof(tbbi);
+        tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
+        tbbi.idCommand = notifyItem->Index;
+
+        if (iconData->uFlags & NIF_MESSAGE)
+        {
+            notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage;
+        }
+
+        if (iconData->uFlags & NIF_ICON)
+        {
+            tbbi.dwMask |= TBIF_IMAGE;
+            notifyItem->IconIndex = tbbi.iImage = ImageList_AddIcon(SysIcons, iconData->hIcon);
+        }
+
+        if (iconData->uFlags & NIF_TIP)
+        {
+            StringCchCopy(notifyItem->iconData.szTip, _countof(notifyItem->iconData.szTip), iconData->szTip);
+        }
+
+        if (iconData->uFlags & NIF_STATE)
+        {
+            if (iconData->dwStateMask & NIS_HIDDEN &&
+                (notifyItem->iconData.dwState & NIS_HIDDEN) != (iconData->dwState & NIS_HIDDEN))
+            {
+                tbbi.dwMask |= TBIF_STATE;
+                if (iconData->dwState & NIS_HIDDEN)
+                {
+                    tbbi.fsState |= TBSTATE_HIDDEN;
+                    VisibleButtonCount--;
+                }
+                else
+                {
+                    tbbi.fsState &= ~TBSTATE_HIDDEN;
+                    VisibleButtonCount++;
+                }
+            }
+
+            notifyItem->iconData.dwState &= ~iconData->dwStateMask;
+            notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask);
+        }
+
+        /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
+
+        NotificationBar.SendMessageW(TB_SETBUTTONINFO, (WPARAM) notifyItem->Index, (LPARAM) &tbbi);
+    }
+
+    VOID AddButton(IN CONST NOTIFYICONDATA *iconData)
+    {
+        TBBUTTON tbBtn;
+        PNOTIFY_ITEM notifyItem;
+        WCHAR text [] = TEXT("");
+
+        notifyItem = CreateNotifyItemData();
+
+        notifyItem->next = NULL;
+        notifyItem->Index = ButtonCount;
+        ButtonCount++;
+        VisibleButtonCount++;
+
+        notifyItem->iconData.hWnd = iconData->hWnd;
+        notifyItem->iconData.uID = iconData->uID;
+
+        tbBtn.fsState = TBSTATE_ENABLED;
+        tbBtn.fsStyle = BTNS_NOPREFIX;
+        tbBtn.dwData = notifyItem->Index;
+
+        tbBtn.iString = (INT_PTR) text;
+        tbBtn.idCommand = notifyItem->Index;
+
+        if (iconData->uFlags & NIF_MESSAGE)
+        {
+            notifyItem->iconData.uCallbackMessage = iconData->uCallbackMessage;
+        }
+
+        if (iconData->uFlags & NIF_ICON)
+        {
+            notifyItem->IconIndex = tbBtn.iBitmap = ImageList_AddIcon(SysIcons, iconData->hIcon);
+        }
+
+        /* TODO: support NIF_TIP */
+
+        if (iconData->uFlags & NIF_STATE)
+        {
+            notifyItem->iconData.dwState &= ~iconData->dwStateMask;
+            notifyItem->iconData.dwState |= (iconData->dwState & iconData->dwStateMask);
+            if (notifyItem->iconData.dwState & NIS_HIDDEN)
+            {
+                tbBtn.fsState |= TBSTATE_HIDDEN;
+                VisibleButtonCount--;
+            }
+
+        }
+
+        /* TODO: support NIF_INFO, NIF_GUID, NIF_REALTIME, NIF_SHOWTIP */
+
+        NotificationBar.SendMessageW(TB_INSERTBUTTON, notifyItem->Index, (LPARAM) &tbBtn);
+
+        NotificationBar.SendMessageW(TB_SETBUTTONSIZE, 0, MAKELONG(16, 16));
+    }
+
+    VOID RemoveButton(IN CONST NOTIFYICONDATA *iconData)
+    {
+        PPNOTIFY_ITEM NotifyPointer;
+
+        NotifyPointer = FindPPNotifyItemByIconData(iconData);
+        if (NotifyPointer)
+        {
+            PNOTIFY_ITEM deleteItem;
+            PNOTIFY_ITEM updateItem;
+            deleteItem = *NotifyPointer;
+
+            NotificationBar.SendMessageW(TB_DELETEBUTTON, deleteItem->Index, 0);
+
+            *NotifyPointer = updateItem = deleteItem->next;
+
+            if (!(deleteItem->iconData.dwState & NIS_HIDDEN))
+                VisibleButtonCount--;
+            HeapFree(hProcessHeap,
+                0,
+                deleteItem);
+            ButtonCount--;
+
+            while (updateItem != NULL)
+            {
+                TBBUTTONINFO tbbi;
+                updateItem->Index--;
+                tbbi.cbSize = sizeof(tbbi);
+                tbbi.dwMask = TBIF_BYINDEX | TBIF_COMMAND;
+                tbbi.idCommand = updateItem->Index;
+
+                NotificationBar.SendMessageW(TB_SETBUTTONINFO, updateItem->Index, (LPARAM) &tbbi);
+
+                updateItem = updateItem->next;
+            }
+        }
+    }
+
+    VOID SendMouseEvent(IN WORD wIndex, IN UINT uMsg, IN WPARAM wParam)
+    {
+        PPNOTIFY_ITEM NotifyPointer;
+
+        static LPCWSTR eventNames [] = {
+            L"WM_MOUSEMOVE",
+            L"WM_LBUTTONDOWN",
+            L"WM_LBUTTONUP",
+            L"WM_LBUTTONDBLCLK",
+            L"WM_RBUTTONDOWN",
+            L"WM_RBUTTONUP",
+            L"WM_RBUTTONDBLCLK",
+            L"WM_MBUTTONDOWN",
+            L"WM_MBUTTONUP",
+            L"WM_MBUTTONDBLCLK",
+            L"WM_MOUSEWHEEL",
+            L"WM_XBUTTONDOWN",
+            L"WM_XBUTTONUP",
+            L"WM_XBUTTONDBLCLK"
+        };
+
+        NotifyPointer = FindPPNotifyItemByIndex(wIndex);
+        if (!NotifyPointer)
+            return;
+
+        PNOTIFY_ITEM notifyItem = *NotifyPointer;
+
+        if (!::IsWindow(notifyItem->iconData.hWnd))
+            return;
+
+        if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
+        {
+            DbgPrint("Sending message %S from button %d to %p (msg=%x, w=%x, l=%x)...\n",
+                     eventNames[uMsg - WM_MOUSEFIRST], wIndex,
+                     notifyItem->iconData.hWnd, notifyItem->iconData.uCallbackMessage, notifyItem->iconData.uID, uMsg);
+        }
+
+        DWORD pid;
+        GetWindowThreadProcessId(notifyItem->iconData.hWnd, &pid);
+
+        if (pid == GetCurrentProcessId() ||
+            (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST))
+        {
+            PostMessage(notifyItem->iconData.hWnd,
+                notifyItem->iconData.uCallbackMessage,
+                notifyItem->iconData.uID,
+                uMsg);
+        }
+        else
+        {
+            SendMessage(notifyItem->iconData.hWnd,
+                notifyItem->iconData.uCallbackMessage,
+                notifyItem->iconData.uID,
+                uMsg);
+        }
+    }
+
+    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 OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        DWORD styles =
+            WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
+            TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | TBSTYLE_WRAPABLE | TBSTYLE_TRANSPARENT |
+            CCS_TOP | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER;
+        DWORD exStyles = WS_EX_TOOLWINDOW;
+
+        hWndToolbar = CreateWindowEx(exStyles,
+            TOOLBARCLASSNAME,
+            NULL,
+            styles,
+            0,
+            0,
+            0,
+            0,
+            m_hWnd,
+            NULL,
+            hExplorerInstance,
+            NULL);
+        if (hWndToolbar != NULL)
+        {
+            SIZE BtnSize;
+
+            NotificationBar.SubclassWindow(hWndToolbar);
+
+            SetWindowTheme(hWndToolbar, L"TrayNotify", NULL);
+
+            /* Identify the version we're using */
+            NotificationBar.SendMessageW(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
+
+            SysIcons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 1000);
+            NotificationBar.SendMessageW(TB_SETIMAGELIST, 0, (LPARAM) SysIcons);
+
+            BtnSize.cx = BtnSize.cy = 18;
+            NotificationBar.SendMessageW(TB_SETBUTTONSIZE, 0, MAKELONG(BtnSize.cx, BtnSize.cy));
+
+        }
+
+        return TRUE;
+    }
+
+    LRESULT NotifyMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        PCOPYDATASTRUCT cpData = (PCOPYDATASTRUCT) lParam;
+        if (cpData->dwData == 1)
+        {
+            SYS_PAGER_COPY_DATA * data;
+            NOTIFYICONDATA *iconData;
+            HWND parentHWND;
+            RECT windowRect;
+            parentHWND = GetParent();
+            parentHWND = ::GetParent(parentHWND);
+            ::GetClientRect(parentHWND, &windowRect);
+
+            data = (PSYS_PAGER_COPY_DATA) cpData->lpData;
+            iconData = &data->nicon_data;
+
+            switch (data->notify_code)
+            {
+            case NIM_ADD:
+            {
+                PPNOTIFY_ITEM NotifyPointer;
+
+                NotifyPointer = FindPPNotifyItemByIconData(iconData);
+                if (!NotifyPointer)
+                {
+                    AddButton(iconData);
+                }
+                break;
+            }
+            case NIM_MODIFY:
+            {
+                PPNOTIFY_ITEM NotifyPointer;
+
+                NotifyPointer = FindPPNotifyItemByIconData(iconData);
+                if (!NotifyPointer)
+                {
+                    AddButton(iconData);
+                }
+                else
+                {
+                    UpdateButton(iconData);
+                }
+                break;
+            }
+            case NIM_DELETE:
+            {
+                RemoveButton(iconData);
+                break;
+            }
+            default:
+                TRACE("NotifyMessage received with unknown code %d.\n", data->notify_code);
+                break;
+            }
+            SendMessage(parentHWND,
+                WM_SIZE,
+                0,
+                MAKELONG(windowRect.right - windowRect.left,
+                windowRect.bottom - windowRect.top));
+        }
+
+        return TRUE;
+    }
+
+    void GetSize(IN WPARAM wParam, IN PSIZE size)
+    {
+        INT rows = 0;
+        TBMETRICS tbm;
+
+        if (wParam) /* horizontal */
+        {
+            rows = size->cy / 24;
+            if (rows == 0)
+                rows++;
+            size->cx = (VisibleButtonCount + rows - 1) / rows * 24;
+        }
+        else
+        {
+            rows = size->cx / 24;
+            if (rows == 0)
+                rows++;
+            size->cy = (VisibleButtonCount + rows - 1) / rows * 24;
+        }
+
+        tbm.cbSize = sizeof(tbm);
+        tbm.dwMask = TBMF_BARPAD | TBMF_BUTTONSPACING;
+        tbm.cxBarPad = tbm.cyBarPad = 0;
+        tbm.cxButtonSpacing = 0;
+        tbm.cyButtonSpacing = 0;
+
+        NotificationBar.SendMessageW(TB_SETMETRICS, 0, (LPARAM) &tbm);
+    }
+
+    LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return TRUE;
+    }
+
+    LRESULT OnGetInfoTip(INT uCode, LPNMHDR hdr, BOOL& bHandled)
+    {
+        NMTBGETINFOTIPW * nmtip = (NMTBGETINFOTIPW *) hdr;
+        PPNOTIFY_ITEM ptr = FindPPNotifyItemByIndex(nmtip->iItem);
+        if (ptr)
+        {
+            PNOTIFY_ITEM item = *ptr;
+            StringCchCopy(nmtip->pszText, nmtip->cchTextMax, item->iconData.szTip);
+        }
+        return TRUE;
+    }
+
+    LRESULT OnCustomDraw(INT uCode, LPNMHDR hdr, BOOL& bHandled)
+    {
+        NMCUSTOMDRAW * cdraw = (NMCUSTOMDRAW *) hdr;
+        switch (cdraw->dwDrawStage)
+        {
+        case CDDS_PREPAINT:
+            return CDRF_NOTIFYITEMDRAW;
+
+        case CDDS_ITEMPREPAINT:
+            return TBCDRF_NOBACKGROUND | TBCDRF_NOEDGES | TBCDRF_NOOFFSET | TBCDRF_NOMARK | TBCDRF_NOETCHEDEFFECT;
+        }
+        return TRUE;
+    }
+
+    LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        LRESULT Ret = TRUE;
+        SIZE szClient;
+        szClient.cx = LOWORD(lParam);
+        szClient.cy = HIWORD(lParam);
+
+        Ret = DefWindowProc(uMsg, wParam, lParam);
+
+        if (hWndToolbar != NULL && hWndToolbar != m_hWnd)
+        {
+            NotificationBar.SetWindowPos(NULL, 0, 0, szClient.cx, szClient.cy, SWP_NOZORDER);
+
+            NotificationBar.SendMessageW(TB_AUTOSIZE);
+
+            RECT rc;
+            NotificationBar.GetClientRect(&rc);
+
+            SIZE szBar = { rc.right - rc.left, rc.bottom - rc.top };
+
+            INT xOff = (szClient.cx - szBar.cx) / 2;
+            INT yOff = (szClient.cy - szBar.cy) / 2;
+
+            NotificationBar.SetWindowPos(NULL, xOff, yOff, szBar.cx, szBar.cy, SWP_NOZORDER);
+        }
+        return Ret;
+    }
+
+    LRESULT OnMouseEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        POINT pt;
+        INT iBtn;
+
+        pt.x = LOWORD(lParam);
+        pt.y = HIWORD(lParam);
+
+        iBtn = (INT) NotificationBar.SendMessageW(TB_HITTEST, 0, (LPARAM) &pt);
+
+        if (iBtn >= 0)
+        {
+            SendMouseEvent(iBtn, uMsg, wParam);
+        }
+
+        return FALSE;
+    }
+
+    DECLARE_WND_CLASS_EX(szSysPagerWndClass, CS_DBLCLKS, COLOR_3DFACE)
+
+    BEGIN_MSG_MAP(CTaskSwitchWnd)
+        MESSAGE_HANDLER(WM_CREATE, OnCreate)
+        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+        MESSAGE_HANDLER(WM_SIZE, OnSize)
+        NOTIFY_CODE_HANDLER(TBN_GETINFOTIPW, OnGetInfoTip)
+        NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
+    ALT_MSG_MAP(1)
+        MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseEvent)
+    END_MSG_MAP()
+
+    HWND _Init(IN HWND hWndParent, IN BOOL bVisible)
+    {
+        DWORD dwStyle;
+
+        NotifyItems = NULL;
+        ButtonCount = 0;
+        VisibleButtonCount = 0;
+
+        /* Create the window. The tray window is going to move it to the correct
+            position and resize it as needed. */
+        dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
+        if (bVisible)
+            dwStyle |= WS_VISIBLE;
+
+        Create(hWndParent, 0, NULL, dwStyle);
+
+        if (!m_hWnd)
+        {
+            return NULL;
+        }
+
+        SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
+
+        return m_hWnd;
+    }
+};
+
+/*
+ * TrayClockWnd
+ */
+
+static const WCHAR szTrayClockWndClass [] = TEXT("TrayClockWClass");
+
+#define ID_TRAYCLOCK_TIMER  0
+#define ID_TRAYCLOCK_TIMER_INIT 1
+
+static const struct
+{
+    BOOL IsTime;
+    DWORD dwFormatFlags;
+    LPCTSTR lpFormat;
+} ClockWndFormats [] = {
+        { TRUE, 0, NULL },
+        { FALSE, 0, TEXT("dddd") },
+        { FALSE, DATE_SHORTDATE, NULL }
+};
+
+#define CLOCKWND_FORMAT_COUNT (sizeof(ClockWndFormats) / sizeof(ClockWndFormats[0]))
+
+#define TRAY_CLOCK_WND_SPACING_X    0
+#define TRAY_CLOCK_WND_SPACING_Y    0
+
+class CTrayClockWnd :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public CWindowImpl < CTrayClockWnd, CWindow, CControlWinTraits >
+{
+    HWND hWndNotify;
+    HFONT hFont;
+    COLORREF textColor;
+    RECT rcText;
+    SYSTEMTIME LocalTime;
+
+    union
+    {
+        DWORD dwFlags;
+        struct
+        {
+            DWORD IsTimerEnabled : 1;
+            DWORD IsInitTimerEnabled : 1;
+            DWORD LinesMeasured : 1;
+            DWORD IsHorizontal : 1;
+        };
+    };
+    DWORD LineSpacing;
+    SIZE CurrentSize;
+    WORD VisibleLines;
+    SIZE LineSizes[CLOCKWND_FORMAT_COUNT];
+    WCHAR szLines[CLOCKWND_FORMAT_COUNT][48];
+
+public:
+    CTrayClockWnd() :
+        hWndNotify(NULL),
+        hFont(NULL),
+        dwFlags(0),
+        LineSpacing(0),
+        VisibleLines(0)
+    {
+        ZeroMemory(&textColor, sizeof(textColor));
+        ZeroMemory(&rcText, sizeof(rcText));
+        ZeroMemory(&LocalTime, sizeof(LocalTime));
+        ZeroMemory(&CurrentSize, sizeof(CurrentSize));
+        ZeroMemory(LineSizes, sizeof(LineSizes));
+        ZeroMemory(szLines, sizeof(LineSizes));
+    }
+    virtual ~CTrayClockWnd() { }
+
+    LRESULT OnThemeChanged()
+    {
+        LOGFONTW clockFont;
+        HTHEME clockTheme;
+        HFONT hFont;
+
+        clockTheme = OpenThemeData(m_hWnd, L"Clock");
+
+        if (clockTheme)
+        {
+            GetThemeFont(clockTheme,
+                NULL,
+                CLP_TIME,
+                0,
+                TMT_FONT,
+                &clockFont);
+
+            hFont = CreateFontIndirectW(&clockFont);
+
+            GetThemeColor(clockTheme,
+                CLP_TIME,
+                0,
+                TMT_TEXTCOLOR,
+                &textColor);
+        }
+        else
+        {
+            NONCLIENTMETRICS ncm = { 0 };
+            ncm.cbSize = sizeof(ncm);
+            SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, FALSE);
+
+            hFont = CreateFontIndirectW(&ncm.lfMessageFont);
+
+            textColor = RGB(0, 0, 0);
+        }
+
+        SetFont(hFont, FALSE);
+
+        CloseThemeData(clockTheme);
+
+        return TRUE;
+    }
+
+    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return OnThemeChanged();
+    }
+
+    BOOL MeasureLines()
+    {
+        HDC hDC;
+        HFONT hPrevFont;
+        INT c, i;
+        BOOL bRet = TRUE;
+
+        hDC = GetDC(m_hWnd);
+        if (hDC != NULL)
+        {
+            if (hFont)
+                hPrevFont = (HFONT) SelectObject(hDC, hFont);
+
+            for (i = 0; i != CLOCKWND_FORMAT_COUNT && bRet; i++)
+            {
+                if (szLines[i][0] != TEXT('\0') &&
+                    !GetTextExtentPoint(hDC, szLines[i], _tcslen(szLines[i]),
+                    &LineSizes[i]))
+                {
+                    bRet = FALSE;
+                    break;
+                }
+            }
+
+            if (hFont)
+                SelectObject(hDC, hPrevFont);
+
+            ReleaseDC(m_hWnd, hDC);
+
+            if (bRet)
+            {
+                LineSpacing = 0;
+
+                /* calculate the line spacing */
+                for (i = 0, c = 0; i != CLOCKWND_FORMAT_COUNT; i++)
+                {
+                    if (LineSizes[i].cx > 0)
+                    {
+                        LineSpacing += LineSizes[i].cy;
+                        c++;
+                    }
+                }
+
+                if (c > 0)
+                {
+                    /* We want a spaceing of 1/2 line */
+                    LineSpacing = (LineSpacing / c) / 2;
+                }
+
+                return TRUE;
+            }
+        }
+
+        return FALSE;
+    }
+
+    WORD GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize)
+    {
+        WORD iLinesVisible = 0;
+        INT i;
+        SIZE szMax = { 0, 0 };
+
+        if (!LinesMeasured)
+            LinesMeasured = MeasureLines();
+
+        if (!LinesMeasured)
+            return 0;
+
+        for (i = 0;
+            i != CLOCKWND_FORMAT_COUNT;
+            i++)
+        {
+            if (LineSizes[i].cx != 0)
+            {
+                if (iLinesVisible > 0)
+                {
+                    if (Horizontal)
+                    {
+                        if (szMax.cy + LineSizes[i].cy + (LONG) LineSpacing >
+                            pSize->cy - (2 * TRAY_CLOCK_WND_SPACING_Y))
+                        {
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        if (LineSizes[i].cx > pSize->cx - (2 * TRAY_CLOCK_WND_SPACING_X))
+                            break;
+                    }
+
+                    /* Add line spacing */
+                    szMax.cy += LineSpacing;
+                }
+
+                iLinesVisible++;
+
+                /* Increase maximum rectangle */
+                szMax.cy += LineSizes[i].cy;
+                if (LineSizes[i].cx > szMax.cx - (2 * TRAY_CLOCK_WND_SPACING_X))
+                    szMax.cx = LineSizes[i].cx + (2 * TRAY_CLOCK_WND_SPACING_X);
+            }
+        }
+
+        szMax.cx += 2 * TRAY_CLOCK_WND_SPACING_X;
+        szMax.cy += 2 * TRAY_CLOCK_WND_SPACING_Y;
+
+        *pSize = szMax;
+
+        return iLinesVisible;
+    }
+
+
+    VOID        UpdateWnd()
+    {
+        SIZE szPrevCurrent;
+        INT BufSize, iRet, i;
+        RECT rcClient;
+
+        ZeroMemory(LineSizes,
+            sizeof(LineSizes));
+
+        szPrevCurrent = CurrentSize;
+
+        for (i = 0;
+            i != CLOCKWND_FORMAT_COUNT;
+            i++)
+        {
+            szLines[i][0] = TEXT('\0');
+            BufSize = sizeof(szLines[0]) / sizeof(szLines[0][0]);
+
+            if (ClockWndFormats[i].IsTime)
+            {
+                iRet = GetTimeFormat(LOCALE_USER_DEFAULT,
+                    AdvancedSettings.bShowSeconds ? ClockWndFormats[i].dwFormatFlags : TIME_NOSECONDS,
+                    &LocalTime,
+                    ClockWndFormats[i].lpFormat,
+                    szLines[i],
+                    BufSize);
+            }
+            else
+            {
+                iRet = GetDateFormat(LOCALE_USER_DEFAULT,
+                    ClockWndFormats[i].dwFormatFlags,
+                    &LocalTime,
+                    ClockWndFormats[i].lpFormat,
+                    szLines[i],
+                    BufSize);
+            }
+
+            if (iRet != 0 && i == 0)
+            {
+                /* Set the window text to the time only */
+                SetWindowText(szLines[i]);
+            }
+        }
+
+        LinesMeasured = MeasureLines();
+
+        if (LinesMeasured &&
+            GetClientRect(&rcClient))
+        {
+            SIZE szWnd;
+
+            szWnd.cx = rcClient.right;
+            szWnd.cy = rcClient.bottom;
+
+            VisibleLines = GetMinimumSize(IsHorizontal, &szWnd);
+            CurrentSize = szWnd;
+        }
+
+        if (IsWindowVisible(m_hWnd))
+        {
+            InvalidateRect(NULL, TRUE);
+
+            if (hWndNotify != NULL &&
+                (szPrevCurrent.cx != CurrentSize.cx ||
+                szPrevCurrent.cy != CurrentSize.cy))
+            {
+                NMHDR nmh;
+
+                nmh.hwndFrom = m_hWnd;
+                nmh.idFrom = GetWindowLongPtr(m_hWnd, GWLP_ID);
+                nmh.code = NTNWM_REALIGN;
+
+                SendMessage(hWndNotify,
+                    WM_NOTIFY,
+                    (WPARAM) nmh.idFrom,
+                    (LPARAM) &nmh);
+            }
+        }
+    }
+
+    VOID        Update()
+    {
+        GetLocalTime(&LocalTime);
+        UpdateWnd();
+    }
+
+    UINT        CalculateDueTime()
+    {
+        UINT uiDueTime;
+
+        /* Calculate the due time */
+        GetLocalTime(&LocalTime);
+        uiDueTime = 1000 - (UINT) LocalTime.wMilliseconds;
+        if (AdvancedSettings.bShowSeconds)
+            uiDueTime += (UINT) LocalTime.wSecond * 100;
+        else
+            uiDueTime += (59 - (UINT) LocalTime.wSecond) * 1000;
+
+        if (uiDueTime < USER_TIMER_MINIMUM || uiDueTime > USER_TIMER_MAXIMUM)
+            uiDueTime = 1000;
+        else
+        {
+            /* Add an artificial delay of 0.05 seconds to make sure the timer
+               doesn't fire too early*/
+            uiDueTime += 50;
+        }
+
+        return uiDueTime;
+    }
+
+    BOOL        ResetTime()
+    {
+        UINT uiDueTime;
+        BOOL Ret;
+
+        /* Disable all timers */
+        if (IsTimerEnabled)
+        {
+            KillTimer(ID_TRAYCLOCK_TIMER);
+            IsTimerEnabled = FALSE;
+        }
+
+        if (IsInitTimerEnabled)
+        {
+            KillTimer(ID_TRAYCLOCK_TIMER_INIT);
+        }
+
+        uiDueTime = CalculateDueTime();
+
+        /* Set the new timer */
+        Ret = SetTimer(ID_TRAYCLOCK_TIMER_INIT, uiDueTime, NULL) != 0;
+        IsInitTimerEnabled = Ret;
+
+        /* Update the time */
+        Update();
+
+        return Ret;
+    }
+
+    VOID        CalibrateTimer()
+    {
+        UINT uiDueTime;
+        BOOL Ret;
+        UINT uiWait1, uiWait2;
+
+        /* Kill the initialization timer */
+        KillTimer(ID_TRAYCLOCK_TIMER_INIT);
+        IsInitTimerEnabled = FALSE;
+
+        uiDueTime = CalculateDueTime();
+
+        if (AdvancedSettings.bShowSeconds)
+        {
+            uiWait1 = 1000 - 200;
+            uiWait2 = 1000;
+        }
+        else
+        {
+            uiWait1 = 60 * 1000 - 200;
+            uiWait2 = 60 * 1000;
+        }
+
+        if (uiDueTime > uiWait1)
+        {
+            /* The update of the clock will be up to 200 ms late, but that's
+               acceptable. We're going to setup a timer that fires depending
+               uiWait2. */
+            Ret = SetTimer(ID_TRAYCLOCK_TIMER, uiWait2, NULL) != 0;
+            IsTimerEnabled = Ret;
+
+            /* Update the time */
+            Update();
+        }
+        else
+        {
+            /* Recalibrate the timer and recalculate again when the current
+               minute/second ends. */
+            ResetTime();
+        }
+    }
+
+    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        /* Disable all timers */
+        if (IsTimerEnabled)
+        {
+            KillTimer(ID_TRAYCLOCK_TIMER);
+        }
+
+        if (IsInitTimerEnabled)
+        {
+            KillTimer(ID_TRAYCLOCK_TIMER_INIT);
+        }
+
+        return TRUE;
+    }
+
+    LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        RECT rcClient;
+        HFONT hPrevFont;
+        int iPrevBkMode, i, line;
+
+        PAINTSTRUCT ps;
+        HDC hDC = (HDC) wParam;
+
+        if (wParam == 0)
+        {
+            hDC = BeginPaint(&ps);
+        }
+
+        if (hDC == NULL)
+            return FALSE;
+
+        if (LinesMeasured &&
+            GetClientRect(&rcClient))
+        {
+            iPrevBkMode = SetBkMode(hDC, TRANSPARENT);
+
+            SetTextColor(hDC, textColor);
+
+            hPrevFont = (HFONT) SelectObject(hDC, hFont);
+
+            rcClient.left = (rcClient.right / 2) - (CurrentSize.cx / 2);
+            rcClient.top = (rcClient.bottom / 2) - (CurrentSize.cy / 2);
+            rcClient.right = rcClient.left + CurrentSize.cx;
+            rcClient.bottom = rcClient.top + CurrentSize.cy;
+
+            for (i = 0, line = 0;
+                i != CLOCKWND_FORMAT_COUNT && line < VisibleLines;
+                i++)
+            {
+                if (LineSizes[i].cx != 0)
+                {
+                    TextOut(hDC,
+                        rcClient.left + (CurrentSize.cx / 2) - (LineSizes[i].cx / 2) +
+                        TRAY_CLOCK_WND_SPACING_X,
+                        rcClient.top + TRAY_CLOCK_WND_SPACING_Y,
+                        szLines[i],
+                        _tcslen(szLines[i]));
+
+                    rcClient.top += LineSizes[i].cy + LineSpacing;
+                    line++;
+                }
+            }
+
+            SelectObject(hDC, hPrevFont);
+
+            SetBkMode(hDC, iPrevBkMode);
+        }
+
+        if (wParam == 0)
+        {
+            EndPaint(&ps);
+        }
+
+        return TRUE;
+    }
+
+    VOID SetFont(IN HFONT hNewFont, IN BOOL bRedraw)
+    {
+        hFont = hNewFont;
+        LinesMeasured = MeasureLines();
+        if (bRedraw)
+        {
+            InvalidateRect(NULL, TRUE);
+        }
+    }
+
+    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 OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        switch (wParam)
+        {
+        case ID_TRAYCLOCK_TIMER:
+            Update();
+            break;
+
+        case ID_TRAYCLOCK_TIMER_INIT:
+            CalibrateTimer();
+            break;
+        }
+        return TRUE;
+    }
+
+    LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        IsHorizontal = (BOOL) wParam;
+
+        return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam) != 0;
+    }
+
+    LRESULT OnUpdateTime(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return (LRESULT) ResetTime();
+    }
+
+    LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return HTTRANSPARENT;
+    }
+
+    LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        SetFont((HFONT) wParam, (BOOL) LOWORD(lParam));
+        return TRUE;
+    }
+
+    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        ResetTime();
+        return TRUE;
+    }
+
+    LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        SIZE szClient;
+
+        szClient.cx = LOWORD(lParam);
+        szClient.cy = HIWORD(lParam);
+
+        VisibleLines = GetMinimumSize(IsHorizontal, &szClient);
+        CurrentSize = szClient;
+
+        InvalidateRect(NULL, TRUE);
+        return TRUE;
+    }
+
+    DECLARE_WND_CLASS_EX(szTrayClockWndClass, CS_DBLCLKS, COLOR_3DFACE)
+
+    BEGIN_MSG_MAP(CTaskSwitchWnd)
+        MESSAGE_HANDLER(WM_CREATE, OnCreate)
+        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
+        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+        MESSAGE_HANDLER(WM_SIZE, OnSize)
+        MESSAGE_HANDLER(WM_PAINT, OnPaint)
+        MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
+        MESSAGE_HANDLER(WM_TIMER, OnTimer)
+        MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
+        MESSAGE_HANDLER(TCWM_GETMINIMUMSIZE, OnGetMinimumSize)
+        MESSAGE_HANDLER(TCWM_UPDATETIME, OnUpdateTime)
+
+    END_MSG_MAP()
+
+    HWND _Init(IN HWND hWndParent, IN BOOL bVisible)
+    {
+        IsHorizontal = TRUE;
+
+        hWndNotify = hWndParent;
+
+        /* Create the window. The tray window is going to move it to the correct
+            position and resize it as needed. */
+        DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS;
+        if (bVisible)
+            dwStyle |= WS_VISIBLE;
+
+        Create(hWndParent, 0, NULL, dwStyle);
+
+        if (m_hWnd != NULL)
+        {
+            SetWindowTheme(m_hWnd, L"TrayNotify", NULL);
+            OnThemeChanged();
+        }
+
+        return m_hWnd;
+
+    }
+};
+
+/*
+ * TrayNotifyWnd
+ */
+
+static const WCHAR szTrayNotifyWndClass [] = TEXT("TrayNotifyWnd");
+
+#define TRAY_NOTIFY_WND_SPACING_X   2
+#define TRAY_NOTIFY_WND_SPACING_Y   2
+
+class CTrayNotifyWnd :
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public CWindowImpl < CTrayNotifyWnd, CWindow, CControlWinTraits >
+{
+    HWND hWndNotify;
+
+    CSysPagerWnd * m_pager;
+    CTrayClockWnd * m_clock;
+
+    CComPtr<ITrayWindow> TrayWindow;
+
+    HTHEME TrayTheme;
+    SIZE szTrayClockMin;
+    SIZE szTrayNotify;
+    MARGINS ContentMargin;
+    HFONT hFontClock;
+    union
+    {
+        DWORD dwFlags;
+        struct
+        {
+            DWORD HideClock : 1;
+            DWORD IsHorizontal : 1;
+        };
+    };
+
+public:
+    CTrayNotifyWnd() :
+        hWndNotify(NULL),
+        m_pager(NULL),
+        m_clock(NULL),
+        TrayTheme(NULL),
+        hFontClock(NULL),
+        dwFlags(0)
+    {
+        ZeroMemory(&szTrayClockMin, sizeof(szTrayClockMin));
+        ZeroMemory(&szTrayNotify, sizeof(szTrayNotify));
+        ZeroMemory(&ContentMargin, sizeof(ContentMargin));
+    }
+    virtual ~CTrayNotifyWnd() { }
+
+    LRESULT OnThemeChanged()
+    {
+        if (TrayTheme)
+            CloseThemeData(TrayTheme);
+
+        if (IsThemeActive())
+            TrayTheme = OpenThemeData(m_hWnd, L"TrayNotify");
+        else
+            TrayTheme = NULL;
+
+        if (TrayTheme)
+        {
+            SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, 0);
+
+            GetThemeMargins(TrayTheme,
+                NULL,
+                TNP_BACKGROUND,
+                0,
+                TMT_CONTENTMARGINS,
+                NULL,
+                &ContentMargin);
+        }
+        else
+        {
+            SetWindowExStyle(m_hWnd, WS_EX_STATICEDGE, WS_EX_STATICEDGE);
+
+            ContentMargin.cxLeftWidth = 0;
+            ContentMargin.cxRightWidth = 0;
+            ContentMargin.cyTopHeight = 0;
+            ContentMargin.cyBottomHeight = 0;
+        }
+
+        return TRUE;
+    }
+
+    LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return OnThemeChanged();
+    }
+
+    LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        m_clock = new CTrayClockWnd();
+        m_clock->_Init(m_hWnd, !HideClock);
+
+        m_pager = new CSysPagerWnd();
+        m_pager->_Init(m_hWnd, !HideClock);
+
+        OnThemeChanged();
+
+        return TRUE;
+    }
+
+    BOOL GetMinimumSize(IN BOOL Horizontal, IN OUT PSIZE pSize)
+    {
+        SIZE szClock = { 0, 0 };
+        SIZE szTray = { 0, 0 };
+
+        IsHorizontal = Horizontal;
+        if (IsHorizontal)
+            SetWindowTheme(m_hWnd, L"TrayNotifyHoriz", NULL);
+        else
+            SetWindowTheme(m_hWnd, L"TrayNotifyVert", NULL);
+
+        if (!HideClock)
+        {
+            if (Horizontal)
+            {
+                szClock.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
+                if (szClock.cy <= 0)
+                    goto NoClock;
+            }
+            else
+            {
+                szClock.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X;
+                if (szClock.cx <= 0)
+                    goto NoClock;
+            }
+
+            m_clock->SendMessage(TCWM_GETMINIMUMSIZE, (WPARAM) Horizontal, (LPARAM) &szClock);
+
+            szTrayClockMin = szClock;
+        }
+        else
+        NoClock:
+        szTrayClockMin = szClock;
+
+        if (Horizontal)
+        {
+            szTray.cy = pSize->cy - 2 * TRAY_NOTIFY_WND_SPACING_Y;
+        }
+        else
+        {
+            szTray.cx = pSize->cx - 2 * TRAY_NOTIFY_WND_SPACING_X;
+        }
+
+        m_pager->GetSize(Horizontal, &szTray);
+
+        szTrayNotify = szTray;
+
+        if (Horizontal)
+        {
+            pSize->cx = 2 * TRAY_NOTIFY_WND_SPACING_X;
+
+            if (!HideClock)
+                pSize->cx += TRAY_NOTIFY_WND_SPACING_X + szTrayClockMin.cx;
+
+            pSize->cx += szTray.cx;
+        }
+        else
+        {
+            pSize->cy = 2 * TRAY_NOTIFY_WND_SPACING_Y;
+
+            if (!HideClock)
+                pSize->cy += TRAY_NOTIFY_WND_SPACING_Y + szTrayClockMin.cy;
+
+            pSize->cy += szTray.cy;
+        }
+
+        pSize->cy += ContentMargin.cyTopHeight + ContentMargin.cyBottomHeight;
+        pSize->cx += ContentMargin.cxLeftWidth + ContentMargin.cxRightWidth;
+
+        return TRUE;
+    }
+
+    VOID Size(IN const SIZE *pszClient)
+    {
+        if (!HideClock)
+        {
+            POINT ptClock;
+            SIZE szClock;
+
+            if (IsHorizontal)
+            {
+                ptClock.x = pszClient->cx - TRAY_NOTIFY_WND_SPACING_X - szTrayClockMin.cx;
+                ptClock.y = TRAY_NOTIFY_WND_SPACING_Y;
+                szClock.cx = szTrayClockMin.cx;
+                szClock.cy = pszClient->cy - (2 * TRAY_NOTIFY_WND_SPACING_Y);
+            }
+            else
+            {
+                ptClock.x = TRAY_NOTIFY_WND_SPACING_X;
+                ptClock.y = pszClient->cy - TRAY_NOTIFY_WND_SPACING_Y - szTrayClockMin.cy;
+                szClock.cx = pszClient->cx - (2 * TRAY_NOTIFY_WND_SPACING_X);
+                szClock.cy = szTrayClockMin.cy;
+            }
+
+            m_clock->SetWindowPos(
+                NULL,
+                ptClock.x,
+                ptClock.y,
+                szClock.cx,
+                szClock.cy,
+                SWP_NOZORDER);
+
+            if (IsHorizontal)
+            {
+                ptClock.x -= szTrayNotify.cx;
+            }
+            else
+            {
+                ptClock.y -= szTrayNotify.cy;
+            }
+
+            m_pager->SetWindowPos(
+                NULL,
+                ptClock.x,
+                ptClock.y,
+                szTrayNotify.cx,
+                szTrayNotify.cy,
+                SWP_NOZORDER);
+        }
+    }
+
+    LRESULT DrawBackground(HDC hdc)
+    {
+        RECT rect;
+
+        GetClientRect(&rect);
+
+        if (TrayTheme)
+        {
+            if (IsThemeBackgroundPartiallyTransparent(TrayTheme, TNP_BACKGROUND, 0))
+            {
+                DrawThemeParentBackground(m_hWnd, hdc, &rect);
+            }
+
+            DrawThemeBackground(TrayTheme, hdc, TNP_BACKGROUND, 0, &rect, 0);
+        }
+
+        return TRUE;
+    }
+
+    LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HDC hdc = (HDC) wParam;
+
+        if (!TrayTheme)
+        {
+            bHandled = FALSE;
+            return 0;
+        }
+
+        return DrawBackground(hdc);
+    }
+
+    LRESULT NotifyMsg(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (m_pager)
+        {
+            m_pager->NotifyMsg(uMsg, wParam, lParam, bHandled);
+        }
+
+        return TRUE;
+    }
+
+    BOOL GetClockRect(OUT PRECT rcClock)
+    {
+        if (!IsWindowVisible(m_clock->m_hWnd))
+            return FALSE;
+
+        return GetWindowRect(m_clock->m_hWnd, rcClock);
+    }
+
+    LRESULT OnGetMinimumSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return (LRESULT) GetMinimumSize((BOOL) wParam, (PSIZE) lParam);
+    }
+
+    LRESULT OnUpdateTime(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (m_clock != NULL)
+        {
+            /* Forward the message to the tray clock window procedure */
+            return m_clock->OnUpdateTime(uMsg, wParam, lParam, bHandled);
+        }
+        return FALSE;
+    }
+
+    LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        SIZE szClient;
+
+        szClient.cx = LOWORD(lParam);
+        szClient.cy = HIWORD(lParam);
+
+        Size(&szClient);
+
+        return TRUE;
+    }
+
+    LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        return HTTRANSPARENT;
+    }
+
+    LRESULT OnShowClock(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        BOOL PrevHidden = HideClock;
+        HideClock = (wParam == 0);
+
+        if (m_clock != NULL && PrevHidden != HideClock)
+        {
+            m_clock->ShowWindow(HideClock ? SW_HIDE : SW_SHOW);
+        }
+
+        return (LRESULT) (!PrevHidden);
+    }
+
+    LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        const NMHDR *nmh = (const NMHDR *) lParam;
+
+        if (nmh->hwndFrom == m_clock->m_hWnd)
+        {
+            /* Pass down notifications */
+            return m_clock->SendMessage(WM_NOTIFY, wParam, lParam);
+        }
+
+        return FALSE;
+    }
+
+    LRESULT OnSetFont(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (m_clock != NULL)
+        {
+            m_clock->SendMessageW(WM_SETFONT, wParam, lParam);
+        }
+
+        bHandled = FALSE;
+        return FALSE;
+    }
+
+    DECLARE_WND_CLASS_EX(szTrayNotifyWndClass, CS_DBLCLKS, COLOR_3DFACE)
+
+    BEGIN_MSG_MAP(CTaskSwitchWnd)
+        MESSAGE_HANDLER(WM_CREATE, OnCreate)
+        MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
+        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+        MESSAGE_HANDLER(WM_SIZE, OnSize)
+        MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
+        MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
+        MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
+        MESSAGE_HANDLER(TNWM_GETMINIMUMSIZE, OnGetMinimumSize)
+        MESSAGE_HANDLER(TNWM_UPDATETIME, OnUpdateTime)
+        MESSAGE_HANDLER(TNWM_SHOWCLOCK, OnShowClock)
+    END_MSG_MAP()
+
+    HWND _Init(IN OUT ITrayWindow *TrayWindow, IN BOOL bHideClock)
+    {
+        HWND hWndTrayWindow;
+
+        hWndTrayWindow = TrayWindow->GetHWND();
+        if (hWndTrayWindow == NULL)
+            return NULL;
+
+        this->TrayWindow = TrayWindow;
+        this->HideClock = bHideClock;
+        this->hWndNotify = hWndTrayWindow;
+
+        DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+        return Create(hWndTrayWindow, 0, NULL, dwStyle, WS_EX_STATICEDGE);
+    }
+};
+
+static CTrayNotifyWnd * g_Instance;
+
+HWND CreateTrayNotifyWnd(IN OUT ITrayWindow *Tray, BOOL bHideClock)
+{
+    // TODO: Destroy after the window is destroyed
+    g_Instance = new CTrayNotifyWnd();
+
+    return g_Instance->_Init(Tray, bHideClock);
+}
+
+VOID
+TrayNotify_NotifyMsg(WPARAM wParam, LPARAM lParam)
+{
+    BOOL bDummy;
+    g_Instance->NotifyMsg(0, wParam, lParam, bDummy);
+}
+
+BOOL
+TrayNotify_GetClockRect(OUT PRECT rcClock)
+{
+    return g_Instance->GetClockRect(rcClock);
+}
similarity index 99%
rename from base/shell/explorer-new/trayprop.c
rename to base/shell/explorer-new/trayprop.cpp
index 36de295..b813263 100644 (file)
@@ -78,7 +78,7 @@ UpdateTaskbarBitmap(PPROPSHEET_INFO pPropInfo)
                 DeleteObject(pPropInfo->hTaskbarBitmap);
             }
 
                 DeleteObject(pPropInfo->hTaskbarBitmap);
             }
 
-            pPropInfo->hTaskbarBitmap = LoadImage(hExplorerInstance,
+            pPropInfo->hTaskbarBitmap = (HBITMAP)LoadImage(hExplorerInstance,
                                                   lpImageName,
                                                   IMAGE_BITMAP,
                                                   0,
                                                   lpImageName,
                                                   IMAGE_BITMAP,
                                                   0,
@@ -367,7 +367,7 @@ DisplayTrayProperties(IN HWND hwndOwner)
     PROPSHEET_INFO propInfo;
     PROPSHEETHEADER psh;
     PROPSHEETPAGE psp[5];
     PROPSHEET_INFO propInfo;
     PROPSHEETHEADER psh;
     PROPSHEETPAGE psp[5];
-    TCHAR szCaption[256];
+    WCHAR szCaption[256];
 
     if (!LoadString(hExplorerInstance,
                     IDS_TASKBAR_STARTMENU_PROP_CAPTION,
 
     if (!LoadString(hExplorerInstance,
                     IDS_TASKBAR_STARTMENU_PROP_CAPTION,
diff --git a/base/shell/explorer-new/traywnd.c b/base/shell/explorer-new/traywnd.c
deleted file mode 100644 (file)
index 3cd2f77..0000000
+++ /dev/null
@@ -1,3346 +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"
-
-extern HRESULT InitShellServices(HDPA * phdpa);
-extern HRESULT ShutdownShellServices(HDPA hdpa);
-
-static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;
-
-#define WM_APP_TRAYDESTROY  (WM_APP + 0x100)
-
-#define TIMER_ID_AUTOHIDE 1
-#define TIMER_ID_MOUSETRACK 2
-#define MOUSETRACK_INTERVAL 100
-#define AUTOHIDE_DELAY_HIDE 2000
-#define AUTOHIDE_DELAY_SHOW 50
-#define AUTOHIDE_INTERVAL_ANIMATING 10
-
-#define AUTOHIDE_SPEED_SHOW 10
-#define AUTOHIDE_SPEED_HIDE 1
-
-#define AUTOHIDE_HIDDEN 0
-#define AUTOHIDE_SHOWING 1
-#define AUTOHIDE_SHOWN 2
-#define AUTOHIDE_HIDING 3
-
-static LONG TrayWndCount = 0;
-
-static const TCHAR szTrayWndClass[] = TEXT("Shell_TrayWnd");
-
-static const ITrayWindowVtbl ITrayWindowImpl_Vtbl;
-static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl;
-
-/*
- * ITrayWindow
- */
-
-const GUID IID_IShellDesktopTray = {0x213e2df9, 0x9a14, 0x4328, {0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9}};
-
-typedef struct
-{
-    const ITrayWindowVtbl *lpVtbl;
-    const IShellDesktopTrayVtbl *lpVtblShellDesktopTray;
-    LONG Ref;
-
-    HTHEME TaskbarTheme;
-    HWND hWnd;
-    HWND hWndDesktop;
-
-    HWND hwndStart;
-    HIMAGELIST himlStartBtn;
-    SIZE StartBtnSize;
-    HFONT hStartBtnFont;
-    HFONT hCaptionFont;
-
-    ITrayBandSite *TrayBandSite;
-    HWND hwndRebar;
-    HWND hwndTaskSwitch;
-    HWND hwndTrayNotify;
-
-    DWORD Position;
-    HMONITOR Monitor;
-    HMONITOR PreviousMonitor;
-    DWORD DraggingPosition;
-    HMONITOR DraggingMonitor;
-
-    RECT rcTrayWnd[4];
-    RECT rcNewPosSize;
-    SIZE TraySize;
-    union
-    {
-        DWORD Flags;
-        struct
-        {
-            DWORD AutoHide : 1;
-            DWORD AlwaysOnTop : 1;
-            DWORD SmSmallIcons : 1;
-            DWORD HideClock : 1;
-            DWORD Locked : 1;
-
-            /* UI Status */
-            DWORD InSizeMove : 1;
-            DWORD IsDragging : 1;
-            DWORD NewPosSize : 1;
-        };
-    };
-
-    NONCLIENTMETRICS ncm;
-    HFONT hFont;
-
-    IMenuBand *StartMenuBand;
-    IMenuPopup *StartMenuPopup;
-    HBITMAP hbmStartMenu;
-
-    HWND hwndTrayPropertiesOwner;
-    HWND hwndRunFileDlgOwner;
-
-    UINT AutoHideState;
-    SIZE AutoHideOffset;
-    TRACKMOUSEEVENT MouseTrackingInfo;
-
-    HDPA hdpaShellServices;
-} ITrayWindowImpl;
-
-static ITrayWindowImpl * g_TrayWindow;
-
-BOOL LaunchCPanel(HWND hwnd, LPCTSTR applet)
-{
-    TCHAR szParams[MAX_PATH];
-
-    StringCbCopy(szParams, sizeof(szParams),
-        TEXT("shell32.dll,Control_RunDLL "));
-    if (FAILED(StringCbCat(szParams, sizeof(szParams),
-            applet)))
-        return FALSE;
-
-    return (ShellExecute(hwnd, TEXT("open"), TEXT("rundll32.exe"), szParams, NULL, SW_SHOWDEFAULT) > (HINSTANCE)32);
-}
-
-static IUnknown *
-IUnknown_from_impl(ITrayWindowImpl *This)
-{
-    return (IUnknown *)&This->lpVtbl;
-}
-
-static ITrayWindow *
-ITrayWindow_from_impl(ITrayWindowImpl *This)
-{
-    return (ITrayWindow *)&This->lpVtbl;
-}
-
-static IShellDesktopTray *
-IShellDesktopTray_from_impl(ITrayWindowImpl *This)
-{
-    return (IShellDesktopTray *)&This->lpVtblShellDesktopTray;
-}
-
-static ITrayWindowImpl *
-impl_from_ITrayWindow(ITrayWindow *iface)
-{
-    return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl,
-                                                               lpVtbl));
-}
-
-static ITrayWindowImpl *
-impl_from_IShellDesktopTray(IShellDesktopTray *iface)
-{
-    return (ITrayWindowImpl *)((ULONG_PTR)iface - FIELD_OFFSET(ITrayWindowImpl,
-                                                               lpVtblShellDesktopTray));
-}
-
-/*
- * ITrayWindow
- */
-
-static BOOL
-ITrayWindowImpl_UpdateNonClientMetrics(IN OUT ITrayWindowImpl *This)
-{
-    This->ncm.cbSize = sizeof(This->ncm);
-    if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
-                             sizeof(This->ncm),
-                             &This->ncm,
-                             0))
-    {
-        if (This->hFont != NULL)
-            DeleteObject(This->hFont);
-
-        This->hFont = CreateFontIndirect(&This->ncm.lfMessageFont);
-        return TRUE;
-    }
-
-    return FALSE;
-}
-
-static VOID
-ITrayWindowImpl_SetWindowsFont(IN OUT ITrayWindowImpl *This)
-{
-    if (This->hwndTrayNotify != NULL)
-    {
-        SendMessage(This->hwndTrayNotify,
-                    WM_SETFONT,
-                    (WPARAM)This->hFont,
-                    TRUE);
-    }
-}
-
-static HMONITOR
-ITrayWindowImpl_GetScreenRectFromRect(IN OUT ITrayWindowImpl *This,
-                                      IN OUT RECT *pRect,
-                                      IN DWORD dwFlags)
-{
-    MONITORINFO mi;
-    HMONITOR hMon;
-
-    mi.cbSize = sizeof(mi);
-    hMon = MonitorFromRect(pRect,
-                           dwFlags);
-    if (hMon != NULL &&
-        GetMonitorInfo(hMon,
-                       &mi))
-    {
-        *pRect = mi.rcMonitor;
-    }
-    else
-    {
-        pRect->left = 0;
-        pRect->top = 0;
-        pRect->right = GetSystemMetrics(SM_CXSCREEN);
-        pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
-
-        hMon = NULL;
-    }
-
-    return hMon;
-}
-
-static HMONITOR
-ITrayWindowImpl_GetMonitorFromRect(IN OUT ITrayWindowImpl *This,
-                                   IN const RECT *pRect)
-{
-    HMONITOR hMon;
-
-    /* In case the monitor sizes or saved sizes differ a bit (probably
-       not a lot, only so the tray window overlaps into another monitor
-       now), minimize the risk that we determine a wrong monitor by
-       using the center point of the tray window if we can't determine
-       it using the rectangle. */
-    hMon = MonitorFromRect(pRect,
-                           MONITOR_DEFAULTTONULL);
-    if (hMon == NULL)
-    {
-        POINT pt;
-
-        pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
-        pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
-
-        /* be less error-prone, find the nearest monitor */
-        hMon = MonitorFromPoint(pt,
-                                MONITOR_DEFAULTTONEAREST);
-    }
-
-    return hMon;
-}
-
-static HMONITOR
-ITrayWindowImpl_GetScreenRect(IN OUT ITrayWindowImpl *This,
-                              IN HMONITOR hMonitor,
-                              IN OUT RECT *pRect)
-{
-    HMONITOR hMon = NULL;
-
-    if (hMonitor != NULL)
-    {
-        MONITORINFO mi;
-
-        mi.cbSize = sizeof(mi);
-        if (!GetMonitorInfo(hMonitor,
-                            &mi))
-        {
-            /* Hm, the monitor is gone? Try to find a monitor where it
-               could be located now */
-            hMon = ITrayWindowImpl_GetMonitorFromRect(This,
-                                                      pRect);
-            if (hMon == NULL ||
-                !GetMonitorInfo(hMon,
-                                &mi))
-            {
-                hMon = NULL;
-                goto GetPrimaryRect;
-            }
-        }
-
-        *pRect = mi.rcMonitor;
-    }
-    else
-    {
-GetPrimaryRect:
-        pRect->left = 0;
-        pRect->top = 0;
-        pRect->right = GetSystemMetrics(SM_CXSCREEN);
-        pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
-    }
-
-    return hMon;
-}
-
-static VOID
-ITrayWindowImpl_MakeTrayRectWithSize(IN DWORD Position,
-                                     IN const SIZE *pTraySize,
-                                     IN OUT RECT *pRect)
-{
-    switch (Position)
-    {
-        case ABE_LEFT:
-            pRect->right = pRect->left + pTraySize->cx;
-            break;
-
-        case ABE_TOP:
-            pRect->bottom = pRect->top + pTraySize->cy;
-            break;
-
-        case ABE_RIGHT:
-            pRect->left = pRect->right - pTraySize->cx;
-            break;
-
-        case ABE_BOTTOM:
-        default:
-            pRect->top = pRect->bottom - pTraySize->cy;
-            break;
-    }
-}
-
-static VOID
-ITrayWindowImpl_GetTrayRectFromScreenRect(IN OUT ITrayWindowImpl *This,
-                                          IN DWORD Position,
-                                          IN const RECT *pScreen,
-                                          IN const SIZE *pTraySize  OPTIONAL,
-                                          OUT RECT *pRect)
-{
-    if (pTraySize == NULL)
-        pTraySize = &This->TraySize;
-
-    *pRect = *pScreen;
-
-    /* Move the border outside of the screen */
-    InflateRect(pRect,
-                GetSystemMetrics(SM_CXEDGE),
-                GetSystemMetrics(SM_CYEDGE));
-
-    ITrayWindowImpl_MakeTrayRectWithSize(Position,
-                                         pTraySize,
-                                         pRect);
-}
-
-BOOL
-ITrayWindowImpl_IsPosHorizontal(IN OUT ITrayWindowImpl *This)
-{
-    return This->Position == ABE_TOP || This->Position == ABE_BOTTOM;
-}
-
-static HMONITOR
-ITrayWindowImpl_CalculateValidSize(IN OUT ITrayWindowImpl *This,
-                                   IN DWORD Position,
-                                   IN OUT RECT *pRect)
-{
-    RECT rcScreen;
-    //BOOL Horizontal;
-    HMONITOR hMon;
-    SIZE szMax, szWnd;
-
-    //Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
-
-    szWnd.cx = pRect->right - pRect->left;
-    szWnd.cy = pRect->bottom - pRect->top;
-
-    rcScreen = *pRect;
-    hMon = ITrayWindowImpl_GetScreenRectFromRect(This,
-                                                 &rcScreen,
-                                                 MONITOR_DEFAULTTONEAREST);
-
-    /* Calculate the maximum size of the tray window and limit the window
-       size to half of the screen's size. */
-    szMax.cx = (rcScreen.right - rcScreen.left) / 2;
-    szMax.cy = (rcScreen.bottom - rcScreen.top) / 2;
-    if (szWnd.cx > szMax.cx)
-        szWnd.cx = szMax.cx;
-    if (szWnd.cy > szMax.cy)
-        szWnd.cy = szMax.cy;
-
-    /* FIXME - calculate */
-
-    ITrayWindowImpl_GetTrayRectFromScreenRect(This,
-                                              Position,
-                                              &rcScreen,
-                                              &szWnd,
-                                              pRect);
-
-    return hMon;
-}
-
-#if 0
-static VOID
-ITrayWindowImpl_GetMinimumWindowSize(IN OUT ITrayWindowImpl *This,
-                                     OUT RECT *pRect)
-{
-    RECT rcMin = {0};
-
-    AdjustWindowRectEx(&rcMin,
-                       GetWindowLong(This->hWnd,
-                                     GWL_STYLE),
-                       FALSE,
-                       GetWindowLong(This->hWnd,
-                                     GWL_EXSTYLE));
-
-    *pRect = rcMin;
-}
-#endif
-
-
-static DWORD
-ITrayWindowImpl_GetDraggingRectFromPt(IN OUT ITrayWindowImpl *This,
-                                      IN POINT pt,
-                                      OUT RECT *pRect,
-                                      OUT HMONITOR *phMonitor)
-{
-    HMONITOR hMon, hMonNew;
-    DWORD PosH, PosV, Pos;
-    SIZE DeltaPt, ScreenOffset;
-    RECT rcScreen;
-
-    rcScreen.left = 0;
-    rcScreen.top = 0;
-
-    /* Determine the screen rectangle */
-    hMon = MonitorFromPoint(pt,
-                            MONITOR_DEFAULTTONULL);
-
-    if (hMon != NULL)
-    {
-        MONITORINFO mi;
-
-        mi.cbSize = sizeof(mi);
-        if (!GetMonitorInfo(hMon,
-                            &mi))
-        {
-            hMon = NULL;
-            goto GetPrimaryScreenRect;
-        }
-
-        /* make left top corner of the screen zero based to
-           make calculations easier */
-        pt.x -= mi.rcMonitor.left;
-        pt.y -= mi.rcMonitor.top;
-
-        ScreenOffset.cx = mi.rcMonitor.left;
-        ScreenOffset.cy = mi.rcMonitor.top;
-        rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left;
-        rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top;
-    }
-    else
-    {
-GetPrimaryScreenRect:
-        ScreenOffset.cx = 0;
-        ScreenOffset.cy = 0;
-        rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
-        rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
-    }
-
-    /* Calculate the nearest screen border */
-    if (pt.x < rcScreen.right / 2)
-    {
-        DeltaPt.cx = pt.x;
-        PosH = ABE_LEFT;
-    }
-    else
-    {
-        DeltaPt.cx = rcScreen.right - pt.x;
-        PosH = ABE_RIGHT;
-    }
-
-    if (pt.y < rcScreen.bottom / 2)
-    {
-        DeltaPt.cy = pt.y;
-        PosV = ABE_TOP;
-    }
-    else
-    {
-        DeltaPt.cy = rcScreen.bottom - pt.y;
-        PosV = ABE_BOTTOM;
-    }
-
-    Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
-
-    /* Fix the screen origin to be relative to the primary monitor again */
-    OffsetRect(&rcScreen,
-               ScreenOffset.cx,
-               ScreenOffset.cy);
-
-    hMonNew = ITrayWindowImpl_GetMonitorFromRect(This,
-                                                 &This->rcTrayWnd[Pos]);
-    if (hMon != hMonNew)
-    {
-        SIZE szTray;
-
-        /* Recalculate the rectangle, we're dragging to another monitor.
-           We don't need to recalculate the rect on single monitor systems. */
-        szTray.cx = This->rcTrayWnd[Pos].right - This->rcTrayWnd[Pos].left;
-        szTray.cy = This->rcTrayWnd[Pos].bottom - This->rcTrayWnd[Pos].top;
-
-        ITrayWindowImpl_GetTrayRectFromScreenRect(This,
-                                                  Pos,
-                                                  &rcScreen,
-                                                  &szTray,
-                                                  pRect);
-        if (This->AutoHide)
-        {
-            pRect->left += This->AutoHideOffset.cx;
-            pRect->right += This->AutoHideOffset.cx;
-            pRect->top += This->AutoHideOffset.cy;
-            pRect->bottom += This->AutoHideOffset.cy;
-        }
-        hMon = hMonNew;
-    }
-    else
-    {
-        /* The user is dragging the tray window on the same monitor. We don't need
-           to recalculate the rectangle */
-        *pRect = This->rcTrayWnd[Pos];
-        if (This->AutoHide)
-        {
-            pRect->left += This->AutoHideOffset.cx;
-            pRect->right += This->AutoHideOffset.cx;
-            pRect->top += This->AutoHideOffset.cy;
-            pRect->bottom += This->AutoHideOffset.cy;
-        }
-    }
-
-    *phMonitor = hMon;
-
-    return Pos;
-}
-
-static DWORD
-ITrayWindowImpl_GetDraggingRectFromRect(IN OUT ITrayWindowImpl *This,
-                                        IN OUT RECT *pRect,
-                                        OUT HMONITOR *phMonitor)
-{
-    POINT pt;
-
-    /* Calculate the center of the rectangle. We call
-       ITrayWindowImpl_GetDraggingRectFromPt to calculate a valid
-       dragging rectangle */
-    pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
-    pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
-
-    return ITrayWindowImpl_GetDraggingRectFromPt(This,
-                                                 pt,
-                                                 pRect,
-                                                 phMonitor);
-}
-
-static VOID
-ITrayWindowImpl_ChangingWinPos(IN OUT ITrayWindowImpl *This,
-                               IN OUT LPWINDOWPOS pwp)
-{
-    RECT rcTray;
-
-    if (This->IsDragging)
-    {
-        rcTray.left = pwp->x;
-        rcTray.top = pwp->y;
-        rcTray.right = rcTray.left + pwp->cx;
-        rcTray.bottom = rcTray.top + pwp->cy;
-        if (This->AutoHide)
-        {
-            rcTray.left -= This->AutoHideOffset.cx;
-            rcTray.right -= This->AutoHideOffset.cx;
-            rcTray.top -= This->AutoHideOffset.cy;
-            rcTray.bottom -= This->AutoHideOffset.cy;
-        }
-
-        if (!EqualRect(&rcTray,
-                       &This->rcTrayWnd[This->DraggingPosition]))
-        {
-            /* Recalculate the rectangle, the user dragged the tray
-               window to another monitor or the window was somehow else
-               moved or resized */
-            This->DraggingPosition = ITrayWindowImpl_GetDraggingRectFromRect(This,
-                                                                             &rcTray,
-                                                                             &This->DraggingMonitor);
-            //This->rcTrayWnd[This->DraggingPosition] = rcTray;
-        }
-
-        //This->Monitor = ITrayWindowImpl_CalculateValidSize(This,
-        //                                                   This->DraggingPosition,
-        //                                                   &rcTray);
-
-        This->Monitor = This->DraggingMonitor;
-        This->Position = This->DraggingPosition;
-        This->IsDragging = FALSE;
-
-        This->rcTrayWnd[This->Position] = rcTray;
-        goto ChangePos;
-    }
-    else if (GetWindowRect(This->hWnd,
-                           &rcTray))
-    {
-        if (This->InSizeMove)
-        {
-            if (!(pwp->flags & SWP_NOMOVE))
-            {
-                rcTray.left = pwp->x;
-                rcTray.top = pwp->y;
-            }
-
-            if (!(pwp->flags & SWP_NOSIZE))
-            {
-                rcTray.right = rcTray.left + pwp->cx;
-                rcTray.bottom = rcTray.top + pwp->cy;
-            }
-
-            This->Position = ITrayWindowImpl_GetDraggingRectFromRect(This,
-                                                                     &rcTray,
-                                                                     &This->Monitor);
-
-            if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
-            {
-                SIZE szWnd;
-
-                szWnd.cx = pwp->cx;
-                szWnd.cy = pwp->cy;
-
-                ITrayWindowImpl_MakeTrayRectWithSize(This->Position,
-                                                     &szWnd,
-                                                     &rcTray);
-            }
-
-            if (This->AutoHide)
-            {
-                rcTray.left -= This->AutoHideOffset.cx;
-                rcTray.right -= This->AutoHideOffset.cx;
-                rcTray.top -= This->AutoHideOffset.cy;
-                rcTray.bottom -= This->AutoHideOffset.cy;
-            }
-            This->rcTrayWnd[This->Position] = rcTray;
-        }
-        else
-        {
-            /* If the user isn't resizing the tray window we need to make sure the
-               new size or position is valid. This is to prevent changes to the window
-               without user interaction. */
-            rcTray = This->rcTrayWnd[This->Position];
-        }
-
-ChangePos:
-        This->TraySize.cx = rcTray.right - rcTray.left;
-        This->TraySize.cy = rcTray.bottom - rcTray.top;
-
-        if (This->AutoHide)
-        {
-            rcTray.left += This->AutoHideOffset.cx;
-            rcTray.right += This->AutoHideOffset.cx;
-            rcTray.top += This->AutoHideOffset.cy;
-            rcTray.bottom += This->AutoHideOffset.cy;
-        }
-
-        pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
-        pwp->x = rcTray.left;
-        pwp->y = rcTray.top;
-        pwp->cx = This->TraySize.cx;
-        pwp->cy = This->TraySize.cy;
-    }
-}
-
-static VOID
-ITrayWindowImpl_ApplyClipping(IN OUT ITrayWindowImpl *This,
-                              IN BOOL Clip)
-{
-    RECT rcClip, rcWindow;
-    HRGN hClipRgn;
-
-    if (GetWindowRect(This->hWnd,
-                      &rcWindow))
-    {
-        /* Disable clipping on systems with only one monitor */
-        if (GetSystemMetrics(SM_CMONITORS) <= 1)
-            Clip = FALSE;
-
-        if (Clip)
-        {
-            rcClip = rcWindow;
-
-            ITrayWindowImpl_GetScreenRect(This,
-                                          This->Monitor,
-                                          &rcClip);
-
-            if (!IntersectRect(&rcClip,
-                               &rcClip,
-                               &rcWindow))
-            {
-                rcClip = rcWindow;
-            }
-
-            OffsetRect(&rcClip,
-                       -rcWindow.left,
-                       -rcWindow.top);
-
-            hClipRgn = CreateRectRgnIndirect(&rcClip);
-        }
-        else
-            hClipRgn = NULL;
-
-        /* Set the clipping region or make sure the window isn't clipped
-           by disabling it explicitly. */
-        SetWindowRgn(This->hWnd,
-                     hClipRgn,
-                     TRUE);
-    }
-}
-
-static VOID
-ITrayWindowImpl_ResizeWorkArea(IN OUT ITrayWindowImpl *This)
-{
-    RECT rcTray,rcWorkArea;
-
-    /* If monitor has changed then fix the previous monitors work area */
-    if (This->PreviousMonitor != This->Monitor)
-    {
-        ITrayWindowImpl_GetScreenRect(This,
-                                    This->PreviousMonitor,
-                                    &rcWorkArea);
-        SystemParametersInfo(SPI_SETWORKAREA,
-                             1,
-                             &rcWorkArea,
-                             SPIF_SENDCHANGE);
-    }
-
-    rcTray = This->rcTrayWnd[This->Position];
-
-    ITrayWindowImpl_GetScreenRect(This,
-                                  This->Monitor,
-                                  &rcWorkArea);
-    This->PreviousMonitor = This->Monitor;
-
-    /* If AutoHide is false then change the workarea to exclude the area that
-       the taskbar covers. */
-    if (!This->AutoHide)
-    {
-        switch (This->Position)
-        {
-            case ABE_TOP:
-                rcWorkArea.top = rcTray.bottom;
-                break;
-            case ABE_LEFT:
-                rcWorkArea.left = rcTray.right;
-                break;
-            case ABE_RIGHT:
-                rcWorkArea.right = rcTray.left;
-                break;
-            case ABE_BOTTOM:
-                rcWorkArea.bottom = rcTray.top;
-                break;
-        }
-    }
-
-    SystemParametersInfo(SPI_SETWORKAREA,
-                         1,
-                         &rcWorkArea,
-                         SPIF_SENDCHANGE);
-}
-
-static VOID
-ITrayWindowImpl_CheckTrayWndPosition(IN OUT ITrayWindowImpl *This)
-{
-    RECT rcTray;
-
-    rcTray = This->rcTrayWnd[This->Position];
-    
-    if (This->AutoHide)
-    {
-        rcTray.left += This->AutoHideOffset.cx;
-        rcTray.right += This->AutoHideOffset.cx;
-        rcTray.top += This->AutoHideOffset.cy;
-        rcTray.bottom += This->AutoHideOffset.cy;
-    }
-
-//    TRACE("CheckTray: %d: %d,%d,%d,%d\n", This->Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
-
-    /* Move the tray window */
-    SetWindowPos(This->hWnd,
-                 NULL,
-                 rcTray.left,
-                 rcTray.top,
-                 rcTray.right - rcTray.left,
-                 rcTray.bottom - rcTray.top,
-                 SWP_NOZORDER);
-
-    ITrayWindowImpl_ResizeWorkArea(This);
-
-    ITrayWindowImpl_ApplyClipping(This,
-                                  TRUE);
-}
-
-typedef struct _TW_STUCKRECTS2
-{
-    DWORD cbSize;
-    LONG Unknown;
-    DWORD dwFlags;
-    DWORD Position;
-    SIZE Size;
-    RECT Rect;
-} TW_STRUCKRECTS2, *PTW_STUCKRECTS2;
-
-static VOID
-ITrayWindowImpl_RegLoadSettings(IN OUT ITrayWindowImpl *This)
-{
-    DWORD Pos;
-    TW_STRUCKRECTS2 sr;
-    RECT rcScreen;
-    SIZE WndSize, EdgeSize, DlgFrameSize;
-    DWORD cbSize = sizeof(sr);
-
-    EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
-    EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
-    DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
-    DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
-
-    if (SHGetValue(hkExplorer,
-                   TEXT("StuckRects2"),
-                   TEXT("Settings"),
-                   NULL,
-                   &sr,
-                   &cbSize) == ERROR_SUCCESS &&
-        sr.cbSize == sizeof(sr))
-    {
-        This->AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0;
-        This->AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0;
-        This->SmSmallIcons = (sr.dwFlags & 0x4) != 0;
-        This->HideClock = (sr.dwFlags & 0x8) != 0;
-
-        /* FIXME: Are there more flags? */
-
-        if (sr.Position > ABE_BOTTOM)
-            This->Position = ABE_BOTTOM;
-        else
-            This->Position = sr.Position;
-
-        /* Try to find out which monitor the tray window was located on last.
-           Here we're only interested in the monitor screen that we think
-           is the last one used. We're going to determine on which monitor
-           we really are after calculating the docked position. */
-        rcScreen = sr.Rect;
-        ITrayWindowImpl_GetScreenRectFromRect(This,
-                                              &rcScreen,
-                                              MONITOR_DEFAULTTONEAREST);
-    }
-    else
-    {
-        This->Position = ABE_BOTTOM;
-        This->AlwaysOnTop = TRUE;
-
-        /* Use the minimum size of the taskbar, we'll use the start
-           button as a minimum for now. Make sure we calculate the
-           entire window size, not just the client size. However, we
-           use a thinner border than a standard thick border, so that
-           the start button and bands are not stuck to the screen border. */
-        sr.Size.cx = This->StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
-        sr.Size.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
-
-        /* Use the primary screen by default */
-        rcScreen.left = 0;
-        rcScreen.top = 0;
-        rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
-        rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
-        ITrayWindowImpl_GetScreenRectFromRect(This,
-                                              &rcScreen,
-                                              MONITOR_DEFAULTTOPRIMARY);
-    }
-
-    if (This->hWnd != NULL)
-        SetWindowPos(This->hWnd,
-        This->AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
-        0,
-        0,
-        0,
-        0,
-        SWP_NOMOVE | SWP_NOSIZE);
-
-    /* Determine a minimum tray window rectangle. The "client" height is
-       zero here since we cannot determine an optimal minimum width when
-       loaded as a vertical tray window. We just need to make sure the values
-       loaded from the registry are at least. The windows explorer behaves
-       the same way, it allows the user to save a zero width vertical tray
-       window, but not a zero height horizontal tray window. */
-    WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
-    WndSize.cy = This->StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
-
-    if (WndSize.cx < sr.Size.cx)
-        WndSize.cx = sr.Size.cx;
-    if (WndSize.cy < sr.Size.cy)
-        WndSize.cy = sr.Size.cy;
-
-    /* Save the calculated size */
-    This->TraySize = WndSize;
-
-    /* Calculate all docking rectangles. We need to do this here so they're
-       initialized and dragging the tray window to another position gives
-       usable results */
-    for (Pos = ABE_LEFT;
-         Pos <= ABE_BOTTOM;
-         Pos++)
-    {
-        ITrayWindowImpl_GetTrayRectFromScreenRect(This,
-                                                  Pos,
-                                                  &rcScreen,
-                                                  &This->TraySize,
-                                                  &This->rcTrayWnd[Pos]);
-//        TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, This->Position, This->rcTrayWnd[Pos].left, This->rcTrayWnd[Pos].top, This->rcTrayWnd[Pos].right, This->rcTrayWnd[Pos].bottom);
-    }
-
-    /* Determine which monitor we are on. It shouldn't matter which docked
-       position rectangle we use */
-    This->Monitor = ITrayWindowImpl_GetMonitorFromRect(This,
-                                                       &This->rcTrayWnd[ABE_LEFT]);
-}
-
-static UINT
-ITrayWindowImpl_TrackMenu(IN OUT ITrayWindowImpl *This,
-                          IN HMENU hMenu,
-                          IN POINT *ppt  OPTIONAL,
-                          IN HWND hwndExclude  OPTIONAL,
-                          IN BOOL TrackUp,
-                          IN BOOL IsContextMenu)
-{
-    TPMPARAMS tmp, *ptmp = NULL;
-    POINT pt;
-    UINT cmdId;
-    UINT fuFlags;
-
-    if (hwndExclude != NULL)
-    {
-        /* Get the client rectangle and map it to screen coordinates */
-        if (GetClientRect(hwndExclude,
-                          &tmp.rcExclude) &&
-            MapWindowPoints(hwndExclude,
-                            NULL,
-                            (LPPOINT)&tmp.rcExclude,
-                            2) != 0)
-        {
-            ptmp = &tmp;
-        }
-    }
-
-    if (ppt == NULL)
-    {
-        if (ptmp == NULL &&
-            GetClientRect(This->hWnd,
-                          &tmp.rcExclude) &&
-            MapWindowPoints(This->hWnd,
-                            NULL,
-                            (LPPOINT)&tmp.rcExclude,
-                            2) != 0)
-        {
-            ptmp = &tmp;
-        }
-
-        if (ptmp != NULL)
-        {
-            /* NOTE: TrackPopupMenuEx will eventually align the track position
-                     for us, no need to take care of it here as long as the
-                     coordinates are somewhere within the exclusion rectangle */
-            pt.x = ptmp->rcExclude.left;
-            pt.y = ptmp->rcExclude.top;
-        }
-        else
-            pt.x = pt.y = 0;
-    }
-    else
-        pt = *ppt;
-
-    tmp.cbSize = sizeof(tmp);
-
-    fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
-    fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
-    if (IsContextMenu)
-        fuFlags |= TPM_RIGHTBUTTON;
-    else
-        fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
-
-    cmdId = TrackPopupMenuEx(hMenu,
-                             fuFlags,
-                             pt.x,
-                             pt.y,
-                             This->hWnd,
-                             ptmp);
-
-    return cmdId;
-}
-
-static UINT
-ITrayWindowImpl_TrackCtxMenu(IN OUT ITrayWindowImpl *This,
-                             IN const TRAYWINDOW_CTXMENU *pMenu,
-                             IN POINT *ppt  OPTIONAL,
-                             IN HWND hwndExclude  OPTIONAL,
-                             IN BOOL TrackUp,
-                             IN PVOID Context  OPTIONAL)
-{
-    HMENU hPopup;
-    UINT cmdId = 0;
-    PVOID pcmContext = NULL;
-
-    hPopup = pMenu->CreateCtxMenu(This->hWnd,
-                                  &pcmContext,
-                                  Context);
-    if (hPopup != NULL)
-    {
-        cmdId = ITrayWindowImpl_TrackMenu(This,
-                                          hPopup,
-                                          ppt,
-                                          hwndExclude,
-                                          TrackUp,
-                                          TRUE);
-
-        pMenu->CtxMenuCommand(This->hWnd,
-                              cmdId,
-                              pcmContext,
-                              Context);
-
-        DestroyMenu(hPopup);
-    }
-
-    return cmdId;
-}
-
-static VOID
-ITrayWindowImpl_Free(ITrayWindowImpl *This)
-{
-    HeapFree(hProcessHeap,
-             0,
-             This);
-}
-
-
-static ULONG STDMETHODCALLTYPE
-ITrayWindowImpl_Release(IN OUT ITrayWindow *iface)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-    ULONG Ret;
-
-    Ret = InterlockedDecrement(&This->Ref);
-    if (Ret == 0)
-        ITrayWindowImpl_Free(This);
-
-    return Ret;
-}
-
-static VOID
-ITrayWindowImpl_Destroy(ITrayWindowImpl *This)
-{
-    (void)InterlockedExchangePointer((PVOID*)&This->hWnd,
-                                     NULL);
-
-
-    if (This->hdpaShellServices != NULL)
-    {
-        ShutdownShellServices(This->hdpaShellServices);
-        This->hdpaShellServices = NULL;
-    }
-
-    if (This->himlStartBtn != NULL)
-    {
-        ImageList_Destroy(This->himlStartBtn);
-        This->himlStartBtn = NULL;
-    }
-
-    if (This->hCaptionFont != NULL)
-    {
-        DeleteObject(This->hCaptionFont);
-        This->hCaptionFont = NULL;
-    }
-
-    if (This->hStartBtnFont != NULL)
-    {
-        DeleteObject(This->hStartBtnFont);
-        This->hStartBtnFont = NULL;
-    }
-
-    if (This->hFont != NULL)
-    {
-        DeleteObject(This->hFont);
-        This->hFont = NULL;
-    }
-
-    if (This->StartMenuPopup != NULL)
-    {
-        IMenuPopup_Release(This->StartMenuPopup);
-        This->StartMenuPopup = NULL;
-    }
-
-    if (This->hbmStartMenu != NULL)
-    {
-        DeleteObject(This->hbmStartMenu);
-        This->hbmStartMenu = NULL;
-    }
-
-    if (This->StartMenuBand != NULL)
-    {
-        IMenuBand_Release(This->StartMenuBand);
-        This->StartMenuBand = NULL;
-    }
-
-    if (This->TrayBandSite != NULL)
-    {
-        /* FIXME: Unload bands */
-        ITrayBandSite_Release(This->TrayBandSite);
-        This->TrayBandSite = NULL;
-    }
-
-    if (This->TaskbarTheme)
-    {
-        CloseThemeData(This->TaskbarTheme);
-        This->TaskbarTheme = NULL;
-    }
-
-    ITrayWindowImpl_Release(ITrayWindow_from_impl(This));
-
-    if (InterlockedDecrement(&TrayWndCount) == 0)
-        PostQuitMessage(0);
-}
-
-static ULONG STDMETHODCALLTYPE
-ITrayWindowImpl_AddRef(IN OUT ITrayWindow *iface)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-
-    return InterlockedIncrement(&This->Ref);
-}
-
-
-static BOOL
-ITrayWindowImpl_NCCreate(IN OUT ITrayWindowImpl *This)
-{
-    ITrayWindowImpl_AddRef(ITrayWindow_from_impl(This));
-
-    return TRUE;
-}
-
-static VOID
-ITrayWindowImpl_UpdateStartButton(IN OUT ITrayWindowImpl *This,
-                                  IN HBITMAP hbmStart  OPTIONAL)
-{
-    SIZE Size = { 0, 0 };
-
-    if (This->himlStartBtn == NULL ||
-        !SendMessage(This->hwndStart,
-                     BCM_GETIDEALSIZE,
-                     0,
-                     (LPARAM)&Size))
-    {
-        Size.cx = GetSystemMetrics(SM_CXEDGE);
-        Size.cy = GetSystemMetrics(SM_CYEDGE);
-
-        if (hbmStart == NULL)
-        {
-            hbmStart = (HBITMAP)SendMessage(This->hwndStart,
-                                            BM_GETIMAGE,
-                                            IMAGE_BITMAP,
-                                            0);
-        }
-
-        if (hbmStart != NULL)
-        {
-            BITMAP bmp;
-
-            if (GetObject(hbmStart,
-                          sizeof(bmp),
-                          &bmp) != 0)
-            {
-                Size.cx += bmp.bmWidth;
-                Size.cy += max(bmp.bmHeight,
-                               GetSystemMetrics(SM_CYCAPTION));
-            }
-            else
-            {
-                /* Huh?! Shouldn't happen... */
-                goto DefSize;
-            }
-        }
-        else
-        {
-DefSize:
-            Size.cx += GetSystemMetrics(SM_CXMINIMIZED);
-            Size.cy += GetSystemMetrics(SM_CYCAPTION);
-        }
-    }
-
-    /* Save the size of the start button */
-    This->StartBtnSize = Size;
-}
-
-static VOID
-ITrayWindowImpl_AlignControls(IN OUT ITrayWindowImpl *This,
-                              IN PRECT prcClient  OPTIONAL)
-{
-    RECT rcClient;
-    SIZE TraySize, StartSize;
-    POINT ptTrayNotify = { 0, 0 };
-    BOOL Horizontal;
-    HDWP dwp;
-
-    ITrayWindowImpl_UpdateStartButton(This, NULL);
-    if (prcClient != NULL)
-    {
-        rcClient = *prcClient;
-    }
-    else
-    {
-        if (!GetClientRect(This->hWnd,
-                           &rcClient))
-        {
-            return;
-        }
-    }
-
-    Horizontal = ITrayWindowImpl_IsPosHorizontal(This);
-
-    /* We're about to resize/move the start button, the rebar control and
-       the tray notification control */
-    dwp = BeginDeferWindowPos(3);
-    if (dwp == NULL)
-        return;
-
-    /* Limit the Start button width to the client width, if neccessary */
-    StartSize = This->StartBtnSize;
-    if (StartSize.cx > rcClient.right)
-        StartSize.cx = rcClient.right;
-
-    if (This->hwndStart != NULL)
-    {
-        /* Resize and reposition the button */
-        dwp = DeferWindowPos(dwp,
-                             This->hwndStart,
-                             NULL,
-                             0,
-                             0,
-                             StartSize.cx,
-                             StartSize.cy,
-                             SWP_NOZORDER | SWP_NOACTIVATE);
-        if (dwp == NULL)
-            return;
-    }
-
-    /* Determine the size that the tray notification window needs */
-    if (Horizontal)
-    {
-        TraySize.cx = 0;
-        TraySize.cy = rcClient.bottom;
-    }
-    else
-    {
-        TraySize.cx = rcClient.right;
-        TraySize.cy = 0;
-    }
-
-    if (This->hwndTrayNotify != NULL &&
-        SendMessage(This->hwndTrayNotify,
-                    TNWM_GETMINIMUMSIZE,
-                    (WPARAM)Horizontal,
-                    (LPARAM)&TraySize))
-    {
-        /* Move the tray notification window to the desired location */
-        if (Horizontal)
-            ptTrayNotify.x = rcClient.right - TraySize.cx;
-        else
-            ptTrayNotify.y = rcClient.bottom - TraySize.cy;
-
-        dwp = DeferWindowPos(dwp,
-                             This->hwndTrayNotify,
-                             NULL,
-                             ptTrayNotify.x,
-                             ptTrayNotify.y,
-                             TraySize.cx,
-                             TraySize.cy,
-                             SWP_NOZORDER | SWP_NOACTIVATE);
-        if (dwp == NULL)
-            return;
-    }
-
-    /* Resize/Move the rebar control */
-    if (This->hwndRebar != NULL)
-    {
-        POINT ptRebar = { 0, 0 };
-        SIZE szRebar;
-
-        SetWindowStyle(This->hwndRebar,
-                       CCS_VERT,
-                       Horizontal ? 0 : CCS_VERT);
-
-        if (Horizontal)
-        {
-            ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME);
-            szRebar.cx = ptTrayNotify.x - ptRebar.x;
-            szRebar.cy = rcClient.bottom;
-        }
-        else
-        {
-            ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME);
-            szRebar.cx = rcClient.right;
-            szRebar.cy = ptTrayNotify.y - ptRebar.y;
-        }
-
-        dwp = DeferWindowPos(dwp,
-                             This->hwndRebar,
-                             NULL,
-                             ptRebar.x,
-                             ptRebar.y,
-                             szRebar.cx,
-                             szRebar.cy,
-                             SWP_NOZORDER | SWP_NOACTIVATE);
-    }
-
-    if (dwp != NULL)
-        EndDeferWindowPos(dwp);
-
-    if (This->hwndTaskSwitch != NULL)
-    {
-        /* Update the task switch window configuration */
-        SendMessage(This->hwndTaskSwitch,
-                    TSWM_UPDATETASKBARPOS,
-                    0,
-                    0);
-    }
-}
-
-static BOOL
-ITrayWindowImpl_CreateStartBtnImageList(IN OUT ITrayWindowImpl *This)
-{
-    HICON hIconStart;
-    SIZE IconSize;
-
-    if (This->himlStartBtn != NULL)
-        return TRUE;
-
-    IconSize.cx = GetSystemMetrics(SM_CXSMICON);
-    IconSize.cy = GetSystemMetrics(SM_CYSMICON);
-
-    /* Load the start button icon and create a image list for it */
-    hIconStart = LoadImage(hExplorerInstance,
-                           MAKEINTRESOURCE(IDI_START),
-                           IMAGE_ICON,
-                           IconSize.cx,
-                           IconSize.cy,
-                           LR_SHARED | LR_DEFAULTCOLOR);
-
-    if (hIconStart != NULL)
-    {
-        This->himlStartBtn = ImageList_Create(IconSize.cx,
-                                              IconSize.cy,
-                                              ILC_COLOR32 | ILC_MASK,
-                                              1,
-                                              1);
-        if (This->himlStartBtn != NULL)
-        {
-            if (ImageList_AddIcon(This->himlStartBtn,
-                                  hIconStart) >= 0)
-            {
-                return TRUE;
-            }
-
-            /* Failed to add the icon! */
-            ImageList_Destroy(This->himlStartBtn);
-            This->himlStartBtn = NULL;
-        }
-    }
-
-    return FALSE;
-}
-
-static HBITMAP
-ITrayWindowImpl_CreateStartButtonBitmap(IN OUT ITrayWindowImpl *This)
-{
-    TCHAR szStartCaption[32];
-    HFONT  hFontOld;
-    HDC hDC = NULL;
-    HDC hDCScreen = NULL;
-    SIZE Size, SmallIcon;
-    HBITMAP hbmpOld, hbmp = NULL;
-    HBITMAP hBitmap = NULL;
-    HICON hIconStart;
-    BOOL Ret;
-    UINT Flags;
-    RECT rcButton;
-
-    /* NOTE: This is the backwards compatibility code that is used if the
-             Common Controls Version 6.0 are not available! */
-
-    if (!LoadString(hExplorerInstance,
-                    IDS_START,
-                    szStartCaption,
-                    sizeof(szStartCaption) / sizeof(szStartCaption[0])))
-    {
-        return NULL;
-    }
-
-    /* Load the start button icon */
-    SmallIcon.cx = GetSystemMetrics(SM_CXSMICON);
-    SmallIcon.cy = GetSystemMetrics(SM_CYSMICON);
-    hIconStart = LoadImage(hExplorerInstance,
-                           MAKEINTRESOURCE(IDI_START),
-                           IMAGE_ICON,
-                           SmallIcon.cx,
-                           SmallIcon.cy,
-                           LR_SHARED | LR_DEFAULTCOLOR);
-
-    hDCScreen = GetDC(NULL);
-    if (hDCScreen == NULL)
-        goto Cleanup;
-
-    hDC = CreateCompatibleDC(hDCScreen);
-    if (hDC == NULL)
-        goto Cleanup;
-
-    hFontOld = SelectObject(hDC,
-                            This->hStartBtnFont);
-
-    Ret = GetTextExtentPoint32(hDC,
-                               szStartCaption,
-                               _tcslen(szStartCaption),
-                               &Size);
-
-    SelectObject(hDC,
-                 hFontOld);
-    if (!Ret)
-        goto Cleanup;
-
-    /* Make sure the height is at least the size of a caption icon. */
-    if (hIconStart != NULL)
-        Size.cx += SmallIcon.cx + 4;
-    Size.cy = max(Size.cy,
-                  SmallIcon.cy);
-
-    /* Create the bitmap */
-    hbmp = CreateCompatibleBitmap(hDCScreen,
-                                  Size.cx,
-                                  Size.cy);
-    if (hbmp == NULL)
-        goto Cleanup;
-
-    /* Caluclate the button rect */
-    rcButton.left = 0;
-    rcButton.top = 0;
-    rcButton.right = Size.cx;
-    rcButton.bottom = Size.cy;
-
-    /* Draw the button */
-    hbmpOld = SelectObject(hDC,
-                           hbmp);
-
-    Flags = DC_TEXT | DC_INBUTTON;
-    if (hIconStart != NULL)
-        Flags |= DC_ICON;
-
-    if (DrawCapTemp != NULL)
-    {
-        Ret = DrawCapTemp(NULL,
-                          hDC,
-                          &rcButton,
-                          This->hStartBtnFont,
-                          hIconStart,
-                          szStartCaption,
-                          Flags);
-    }
-
-    SelectObject(hDC,
-                 hbmpOld);
-
-    if (!Ret)
-        goto Cleanup;
-
-    /* We successfully created the bitmap! */
-    hBitmap = hbmp;
-    hbmp = NULL;
-
-Cleanup:
-    if (hDCScreen != NULL)
-    {
-        ReleaseDC(NULL,
-            hDCScreen);
-    }
-
-    if (hbmp != NULL)
-        DeleteObject(hbmp);
-
-    if (hDC != NULL)
-        DeleteDC(hDC);
-
-    return hBitmap;
-}
-
-static VOID
-ITrayWindowImpl_UpdateTheme(IN OUT ITrayWindowImpl *This)
-{
-    if (This->TaskbarTheme)
-        CloseThemeData(This->TaskbarTheme);
-
-    if (IsThemeActive())
-        This->TaskbarTheme = OpenThemeData(This->hWnd, L"Taskbar");
-    else
-        This->TaskbarTheme = 0;
-}
-
-static VOID
-ITrayWindowImpl_Create(IN OUT ITrayWindowImpl *This)
-{
-    TCHAR szStartCaption[32];
-
-    SetWindowTheme(This->hWnd, L"TaskBar", NULL);
-    ITrayWindowImpl_UpdateTheme(This);
-
-    InterlockedIncrement(&TrayWndCount);
-
-    if (!LoadString(hExplorerInstance,
-                    IDS_START,
-                    szStartCaption,
-                    sizeof(szStartCaption) / sizeof(szStartCaption[0])))
-    {
-        szStartCaption[0] = TEXT('\0');
-    }
-
-    if (This->hStartBtnFont == NULL || This->hCaptionFont == NULL)
-    {
-        NONCLIENTMETRICS ncm;
-
-        /* Get the system fonts, we use the caption font,
-           always bold, though. */
-        ncm.cbSize = sizeof(ncm);
-        if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
-                                 sizeof(ncm),
-                                 &ncm,
-                                 FALSE))
-        {
-            if (This->hCaptionFont == NULL)
-            {
-                ncm.lfCaptionFont.lfWeight = FW_NORMAL;
-                This->hCaptionFont = CreateFontIndirect(&ncm.lfCaptionFont);
-            }
-
-            if (This->hStartBtnFont == NULL)
-            {
-                ncm.lfCaptionFont.lfWeight = FW_BOLD;
-                This->hStartBtnFont = CreateFontIndirect(&ncm.lfCaptionFont);
-            }
-        }
-    }
-
-    /* Create the Start button */
-    This->hwndStart = CreateWindowEx(0,
-                                     WC_BUTTON,
-                                     szStartCaption,
-                                     WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
-                                         BS_PUSHBUTTON | BS_CENTER | BS_VCENTER | BS_BITMAP,
-                                     0,
-                                     0,
-                                     0,
-                                     0,
-                                     This->hWnd,
-                                     (HMENU)IDC_STARTBTN,
-                                     hExplorerInstance,
-                                     NULL);
-    if (This->hwndStart)
-    {
-        SetWindowTheme(This->hwndStart, L"Start", NULL);
-        SendMessage(This->hwndStart,
-                    WM_SETFONT,
-                    (WPARAM)This->hStartBtnFont,
-                    FALSE);
-
-        if (ITrayWindowImpl_CreateStartBtnImageList(This))
-        {
-            BUTTON_IMAGELIST bil;
-
-            /* Try to set the start button image. This requires the Common
-               Controls 6.0 to be present (XP and later) */
-            bil.himl = This->himlStartBtn;
-            bil.margin.left = bil.margin.right = 1;
-            bil.margin.top = bil.margin.bottom = 1;
-            bil.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
-
-            if (!SendMessage(This->hwndStart,
-                             BCM_SETIMAGELIST,
-                             0,
-                             (LPARAM)&bil))
-            {
-                /* Fall back to the deprecated method on older systems that don't
-                   support Common Controls 6.0 */
-                ImageList_Destroy(This->himlStartBtn);
-                This->himlStartBtn = NULL;
-
-                goto SetStartBtnImage;
-            }
-
-            /* We're using the image list, remove the BS_BITMAP style and
-               don't center it horizontally */
-            SetWindowStyle(This->hwndStart,
-                           BS_BITMAP | BS_RIGHT,
-                           0);
-
-            ITrayWindowImpl_UpdateStartButton(This,
-                                              NULL);
-        }
-        else
-        {
-            HBITMAP hbmStart, hbmOld;
-
-SetStartBtnImage:
-            hbmStart = ITrayWindowImpl_CreateStartButtonBitmap(This);
-            if (hbmStart != NULL)
-            {
-                ITrayWindowImpl_UpdateStartButton(This,
-                                                  hbmStart);
-
-                hbmOld = (HBITMAP)SendMessage(This->hwndStart,
-                                              BM_SETIMAGE,
-                                              IMAGE_BITMAP,
-                                              (LPARAM)hbmStart);
-
-                if (hbmOld != NULL)
-                    DeleteObject(hbmOld);
-            }
-        }
-    }
-
-    /* Load the saved tray window settings */
-    ITrayWindowImpl_RegLoadSettings(This);
-
-    /* Create and initialize the start menu */
-    This->hbmStartMenu = LoadBitmap(hExplorerInstance,
-                                    MAKEINTRESOURCE(IDB_STARTMENU));
-    This->StartMenuPopup = CreateStartMenu(ITrayWindow_from_impl(This),
-                                           &This->StartMenuBand,
-                                           This->hbmStartMenu,
-                                           0);
-
-    /* Load the tray band site */
-    if (This->TrayBandSite != NULL)
-    {
-        ITrayBandSite_Release(This->TrayBandSite);
-    }
-
-    This->TrayBandSite = CreateTrayBandSite(ITrayWindow_from_impl(This),
-                                            &This->hwndRebar,
-                                            &This->hwndTaskSwitch);
-    SetWindowTheme(This->hwndRebar, L"TaskBar", NULL);
-
-    /* Create the tray notification window */
-    This->hwndTrayNotify = CreateTrayNotifyWnd(ITrayWindow_from_impl(This),
-                                               This->HideClock);
-
-    if (ITrayWindowImpl_UpdateNonClientMetrics(This))
-    {
-        ITrayWindowImpl_SetWindowsFont(This);
-    }
-
-    /* Move the tray window to the right position and resize it if neccessary */
-    ITrayWindowImpl_CheckTrayWndPosition(This);
-
-    /* Align all controls on the tray window */
-    ITrayWindowImpl_AlignControls(This,
-                                  NULL);
-
-    InitShellServices(&(This->hdpaShellServices));
-
-    if (This->AutoHide)
-    {
-        This->AutoHideState = AUTOHIDE_HIDING;
-        SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
-    }
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayWindowImpl_QueryInterface(IN OUT ITrayWindow *iface,
-                               IN REFIID riid,
-                               OUT LPVOID *ppvObj)
-{
-    ITrayWindowImpl *This;
-
-    if (ppvObj == NULL)
-        return E_POINTER;
-
-    This = impl_from_ITrayWindow(iface);
-
-    if (IsEqualIID(riid,
-                   &IID_IUnknown))
-    {
-        *ppvObj = IUnknown_from_impl(This);
-    }
-    else if (IsEqualIID(riid,
-                        &IID_IShellDesktopTray))
-    {
-        *ppvObj = IShellDesktopTray_from_impl(This);
-    }
-    else
-    {
-        *ppvObj = NULL;
-        return E_NOINTERFACE;
-    }
-
-    ITrayWindowImpl_AddRef(iface);
-    return S_OK;
-}
-
-static ITrayWindowImpl *
-ITrayWindowImpl_Construct(VOID)
-{
-    ITrayWindowImpl *This;
-
-    This = HeapAlloc(hProcessHeap,
-                     HEAP_ZERO_MEMORY,
-                     sizeof(*This));
-    if (This == NULL)
-        return NULL;
-
-    This->lpVtbl = &ITrayWindowImpl_Vtbl;
-    This->lpVtblShellDesktopTray = &IShellDesktopTrayImpl_Vtbl;
-    This->Ref = 1;
-    This->Position = (DWORD)-1;
-
-    return This;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayWindowImpl_Open(IN OUT ITrayWindow *iface)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-    HRESULT Ret = S_OK;
-    HWND hWnd;
-    DWORD dwExStyle;
-
-    /* Check if there's already a window created and try to show it.
-       If it was somehow destroyed just create a new tray window. */
-    if (This->hWnd != NULL)
-    {
-        if (IsWindow(This->hWnd))
-        {
-            if (!IsWindowVisible(This->hWnd))
-            {
-                ITrayWindowImpl_CheckTrayWndPosition(This);
-
-                ShowWindow(This->hWnd,
-                           SW_SHOW);
-            }
-        }
-        else
-            goto TryCreateTrayWnd;
-    }
-    else
-    {
-        RECT rcWnd;
-
-TryCreateTrayWnd:
-        dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
-        if (This->AlwaysOnTop)
-            dwExStyle |= WS_EX_TOPMOST;
-
-        if (This->Position != (DWORD)-1)
-            rcWnd = This->rcTrayWnd[This->Position];
-        else
-        {
-            ZeroMemory(&rcWnd,
-                       sizeof(rcWnd));
-        }
-
-        hWnd = CreateWindowEx(dwExStyle,
-                              szTrayWndClass,
-                              NULL,
-                              WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
-                                  WS_BORDER | WS_THICKFRAME,
-                              rcWnd.left,
-                              rcWnd.top,
-                              rcWnd.right - rcWnd.left,
-                              rcWnd.bottom - rcWnd.top,
-                              NULL,
-                              NULL,
-                              hExplorerInstance,
-                              This);
-        if (hWnd == NULL)
-            Ret = E_FAIL;
-    }
-
-    return Ret;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayWindowImpl_Close(IN OUT ITrayWindow *iface)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-
-    if (This->hWnd != NULL)
-    {
-        SendMessage(This->hWnd,
-                    WM_APP_TRAYDESTROY,
-                    0,
-                    0);
-    }
-
-    return S_OK;
-}
-
-static HWND STDMETHODCALLTYPE
-ITrayWindowImpl_GetHWND(IN OUT ITrayWindow *iface)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-
-    return This->hWnd;
-}
-
-static BOOL STDMETHODCALLTYPE
-ITrayWindowImpl_IsSpecialHWND(IN OUT ITrayWindow *iface,
-                              IN HWND hWnd)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-
-    return (hWnd == This->hWnd ||
-            (This->hWndDesktop != NULL && hWnd == This->hWndDesktop));
-}
-
-static BOOL STDMETHODCALLTYPE
-ITrayWindowImpl_IsHorizontal(IN OUT ITrayWindow *iface)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-    return ITrayWindowImpl_IsPosHorizontal(This);
-}
-
-static HFONT STDMETHODCALLTYPE
-ITrayWIndowImpl_GetCaptionFonts(IN OUT ITrayWindow *iface,
-                                OUT HFONT *phBoldCaption  OPTIONAL)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-
-    if (phBoldCaption != NULL)
-        *phBoldCaption = This->hStartBtnFont;
-
-    return This->hCaptionFont;
-}
-
-static DWORD WINAPI
-TrayPropertiesThread(IN OUT PVOID pParam)
-{
-    ITrayWindowImpl *This = pParam;
-    HWND hwnd;
-    RECT posRect;
-
-    GetWindowRect(This->hwndStart, &posRect);
-    hwnd = CreateWindowEx(0,
-                          WC_STATIC,
-                          NULL,
-                          WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
-                          posRect.left,
-                          posRect.top,
-                          posRect.right - posRect.left,
-                          posRect.bottom - posRect.top,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL);
-
-    This->hwndTrayPropertiesOwner = hwnd;
-
-    DisplayTrayProperties(hwnd);
-
-    This->hwndTrayPropertiesOwner = NULL;
-    DestroyWindow(hwnd);
-
-    return 0;
-}
-
-static HWND STDMETHODCALLTYPE
-ITrayWindowImpl_DisplayProperties(IN OUT ITrayWindow *iface)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-    HWND hTrayProp;
-
-    if (This->hwndTrayPropertiesOwner)
-    {
-        hTrayProp = GetLastActivePopup(This->hwndTrayPropertiesOwner);
-        if (hTrayProp != NULL &&
-            hTrayProp != This->hwndTrayPropertiesOwner)
-        {
-            SetForegroundWindow(hTrayProp);
-            return NULL;
-        }
-    }
-
-    CloseHandle(CreateThread(NULL, 0, TrayPropertiesThread, This, 0, NULL));
-    return NULL;
-}
-
-static VOID
-OpenCommonStartMenuDirectory(IN HWND hWndOwner,
-                             IN LPCTSTR lpOperation)
-{
-    TCHAR szDir[MAX_PATH];
-
-    if (SHGetSpecialFolderPath(hWndOwner,
-                               szDir,
-                               CSIDL_COMMON_STARTMENU,
-                               FALSE))
-    {
-        ShellExecute(hWndOwner,
-                     lpOperation,
-                     NULL,
-                     NULL,
-                     szDir,
-                     SW_SHOWNORMAL);
-    }
-}
-
-static VOID
-OpenTaskManager(IN HWND hWndOwner)
-{
-    ShellExecute(hWndOwner,
-                 TEXT("open"),
-                 TEXT("taskmgr.exe"),
-                 NULL,
-                 NULL,
-                 SW_SHOWNORMAL);
-}
-
-static BOOL STDMETHODCALLTYPE
-ITrayWindowImpl_ExecContextMenuCmd(IN OUT ITrayWindow *iface,
-                                   IN UINT uiCmd)
-{
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-    BOOL bHandled = TRUE;
-
-    switch (uiCmd)
-    {
-        case ID_SHELL_CMD_PROPERTIES:
-            ITrayWindow_DisplayProperties(iface);
-            break;
-
-        case ID_SHELL_CMD_OPEN_ALL_USERS:
-            OpenCommonStartMenuDirectory(This->hWnd,
-                                         TEXT("open"));
-            break;
-
-        case ID_SHELL_CMD_EXPLORE_ALL_USERS:
-            OpenCommonStartMenuDirectory(This->hWnd,
-                                         TEXT("explore"));
-            break;
-
-        case ID_LOCKTASKBAR:
-            if (SHRestricted(REST_CLASSICSHELL) == 0)
-            {
-                ITrayWindow_Lock(iface,
-                                 !This->Locked);
-            }
-            break;
-
-        case ID_SHELL_CMD_OPEN_TASKMGR:
-            OpenTaskManager(This->hWnd);
-            break;
-
-        case ID_SHELL_CMD_UNDO_ACTION:
-            break;
-
-        case ID_SHELL_CMD_SHOW_DESKTOP:
-            break;
-
-        case ID_SHELL_CMD_TILE_WND_H:
-             TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL);
-            break;
-
-        case ID_SHELL_CMD_TILE_WND_V:
-             TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL);
-            break;
-
-        case ID_SHELL_CMD_CASCADE_WND:
-             CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL);
-            break;
-
-        case ID_SHELL_CMD_CUST_NOTIF:
-            break;
-
-        case ID_SHELL_CMD_ADJUST_DAT:
-            LaunchCPanel(NULL, TEXT("timedate.cpl"));
-            break;
-
-        default:
-            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
-            bHandled = FALSE;
-            break;
-    }
-
-    return bHandled;
-}
-
-static BOOL STDMETHODCALLTYPE
-ITrayWindowImpl_Lock(IN OUT ITrayWindow *iface,
-                     IN BOOL bLock)
-{
-    BOOL bPrevLock;
-    ITrayWindowImpl *This = impl_from_ITrayWindow(iface);
-
-    bPrevLock = This->Locked;
-    if (This->Locked != bLock)
-    {
-        This->Locked = bLock;
-
-        if (This->TrayBandSite != NULL)
-        {
-            if (!SUCCEEDED(ITrayBandSite_Lock(This->TrayBandSite,
-                                              bLock)))
-            {
-                /* Reset?? */
-                This->Locked = bPrevLock;
-            }
-        }
-    }
-
-    return bPrevLock;
-}
-
-static const ITrayWindowVtbl ITrayWindowImpl_Vtbl =
-{
-    /* IUnknown */
-    ITrayWindowImpl_QueryInterface,
-    ITrayWindowImpl_AddRef,
-    ITrayWindowImpl_Release,
-    /* ITrayWindow */
-    ITrayWindowImpl_Open,
-    ITrayWindowImpl_Close,
-    ITrayWindowImpl_GetHWND,
-    ITrayWindowImpl_IsSpecialHWND,
-    ITrayWindowImpl_IsHorizontal,
-    ITrayWIndowImpl_GetCaptionFonts,
-    ITrayWindowImpl_DisplayProperties,
-    ITrayWindowImpl_ExecContextMenuCmd,
-    ITrayWindowImpl_Lock
-};
-
-static int
-ITrayWindowImpl_DrawBackground(IN ITrayWindowImpl *This,
-                               IN HDC dc)
-{
-    int backoundPart;
-    RECT rect;
-
-    GetClientRect(This->hWnd, &rect);
-    switch (This->Position)
-    {
-        case ABE_LEFT:
-            backoundPart = TBP_BACKGROUNDLEFT;
-            break;
-        case ABE_TOP:
-            backoundPart = TBP_BACKGROUNDTOP;
-            break;
-        case ABE_RIGHT:
-            backoundPart = TBP_BACKGROUNDRIGHT;
-            break;
-        case ABE_BOTTOM:
-        default:
-            backoundPart = TBP_BACKGROUNDBOTTOM;
-            break;
-    }
-    DrawThemeBackground(This->TaskbarTheme, dc, backoundPart, 0, &rect, 0);
-    return 0;
-}
-
-static int
-ITrayWindowImpl_DrawSizer(IN ITrayWindowImpl *This,
-                          IN HRGN hRgn)
-{
-    HDC hdc;
-    RECT rect;
-    int backoundPart;
-
-    GetWindowRect(This->hWnd, &rect);
-    OffsetRect(&rect, -rect.left, -rect.top);
-
-    hdc = GetDCEx(This->hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP);
-
-    switch (This->Position)
-    {
-        case ABE_LEFT:
-            backoundPart = TBP_SIZINGBARLEFT;
-            rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME);
-            break;
-        case ABE_TOP:
-            backoundPart = TBP_SIZINGBARTOP;
-            rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME);
-            break;
-        case ABE_RIGHT:
-            backoundPart = TBP_SIZINGBARRIGHT;
-            rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME);
-            break;
-        case ABE_BOTTOM:
-        default:
-            backoundPart = TBP_SIZINGBARBOTTOM;
-            rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME);
-            break;
-    }
-
-    DrawThemeBackground(This->TaskbarTheme, hdc, backoundPart, 0, &rect, 0);
-
-    ReleaseDC(This->hWnd, hdc);
-    return 0;
-}
-
-static DWORD WINAPI
-RunFileDlgThread(IN OUT PVOID pParam)
-{
-    ITrayWindowImpl *This = pParam;
-    HANDLE hShell32;
-    RUNFILEDLG RunFileDlg;
-    HWND hwnd;
-    RECT posRect;
-
-    GetWindowRect(This->hwndStart,&posRect);
-
-    hwnd = CreateWindowEx(0,
-                          WC_STATIC,
-                          NULL,
-                          WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
-                          posRect.left,
-                          posRect.top,
-                          posRect.right - posRect.left,
-                          posRect.bottom - posRect.top,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL);
-
-    This->hwndRunFileDlgOwner = hwnd;
-
-    hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-    RunFileDlg = (RUNFILEDLG)GetProcAddress(hShell32, (LPCSTR)61);
-
-    RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
-
-    This->hwndRunFileDlgOwner = NULL;
-    DestroyWindow(hwnd);
-
-    return 0;
-}
-
-static void
-ITrayWindowImpl_DisplayRunFileDlg(IN ITrayWindowImpl *This)
-{
-    HWND hRunDlg;
-    if (This->hwndRunFileDlgOwner)
-    {
-        hRunDlg = GetLastActivePopup(This->hwndRunFileDlgOwner);
-        if (hRunDlg != NULL &&
-            hRunDlg != This->hwndRunFileDlgOwner)
-        {
-            SetForegroundWindow(hRunDlg);
-            return;
-        }
-    }
-
-    CloseHandle(CreateThread(NULL, 0, RunFileDlgThread, This, 0, NULL));
-}
-
-static void PopupStartMenu(IN ITrayWindowImpl *This)
-{
-    if (This->StartMenuPopup != NULL)
-    {
-        POINTL pt;
-        RECTL rcExclude;
-        DWORD dwFlags = 0;
-
-        if (GetWindowRect(This->hwndStart,
-            (RECT*) &rcExclude))
-        {
-            switch (This->Position)
-            {
-            case ABE_BOTTOM:
-                pt.x = rcExclude.left;
-                pt.y = rcExclude.top;
-                dwFlags |= MPPF_BOTTOM;
-                break;
-            case ABE_TOP:
-            case ABE_LEFT:
-                pt.x = rcExclude.left;
-                pt.y = rcExclude.bottom;
-                dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT;
-                break;
-            case ABE_RIGHT:
-                pt.x = rcExclude.right;
-                pt.y = rcExclude.bottom;
-                dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT;
-                break;
-            }
-
-            IMenuPopup_Popup(This->StartMenuPopup,
-                &pt,
-                &rcExclude,
-                dwFlags);
-
-            SendMessageW(This->hwndStart, BM_SETSTATE, TRUE, 0);
-        }
-    }
-}
-
-static void
-ProcessMouseTracking(ITrayWindowImpl * This)
-{
-    RECT rcCurrent;
-    POINT pt;
-    BOOL over;
-    UINT state = This->AutoHideState;
-
-    GetCursorPos(&pt);
-    GetWindowRect(This->hWnd, &rcCurrent);
-    over = PtInRect(&rcCurrent, pt);
-
-    if (SendMessage(This->hwndStart, BM_GETSTATE, 0, 0) != BST_UNCHECKED)
-    {
-        over = TRUE;
-    }
-
-    if (over)
-    {
-        if (state == AUTOHIDE_HIDING)
-        {
-            TRACE("AutoHide cancelling hide.\n");
-            This->AutoHideState = AUTOHIDE_SHOWING;
-            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-        }
-        else if (state == AUTOHIDE_HIDDEN)
-        {
-            TRACE("AutoHide starting show.\n");
-            This->AutoHideState = AUTOHIDE_SHOWING;
-            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL);
-        }
-    }
-    else
-    {
-        if (state == AUTOHIDE_SHOWING)
-        {
-            TRACE("AutoHide cancelling show.\n");
-            This->AutoHideState = AUTOHIDE_HIDING;
-            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-        }
-        else if (state == AUTOHIDE_SHOWN)
-        {
-            TRACE("AutoHide starting hide.\n");
-            This->AutoHideState = AUTOHIDE_HIDING;
-            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
-        }
-
-        KillTimer(This->hWnd, TIMER_ID_MOUSETRACK);
-    }
-}
-
-static void
-ProcessAutoHide(ITrayWindowImpl * This)
-{
-    RECT rc = This->rcTrayWnd[This->Position];
-    INT w = This->TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1;
-    INT h = This->TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1;
-
-    TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", This->AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h);
-
-    switch (This->AutoHideState)
-    {
-    case AUTOHIDE_HIDING:
-        switch (This->Position)
-        {
-        case ABE_LEFT:
-            This->AutoHideOffset.cy = 0;
-            This->AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE;
-            if (This->AutoHideOffset.cx < -w)
-                This->AutoHideOffset.cx = -w;
-            break;
-        case ABE_TOP:
-            This->AutoHideOffset.cx = 0;
-            This->AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE;
-            if (This->AutoHideOffset.cy < -h)
-                This->AutoHideOffset.cy = -h;
-            break;
-        case ABE_RIGHT:
-            This->AutoHideOffset.cy = 0;
-            This->AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE;
-            if (This->AutoHideOffset.cx > w)
-                This->AutoHideOffset.cx = w;
-            break;
-        case ABE_BOTTOM:
-            This->AutoHideOffset.cx = 0;
-            This->AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE;
-            if (This->AutoHideOffset.cy > h)
-                This->AutoHideOffset.cy = h;
-            break;
-        }
-
-        if (This->AutoHideOffset.cx != w && This->AutoHideOffset.cy != h)
-        {
-            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-            break;
-        }
-
-        /* fallthrough */
-    case AUTOHIDE_HIDDEN:
-
-        switch (This->Position)
-        {
-        case ABE_LEFT:
-            This->AutoHideOffset.cx = -w;
-            This->AutoHideOffset.cy = 0;
-            break;
-        case ABE_TOP:
-            This->AutoHideOffset.cx = 0;
-            This->AutoHideOffset.cy = -h;
-            break;
-        case ABE_RIGHT:
-            This->AutoHideOffset.cx = w;
-            This->AutoHideOffset.cy = 0;
-            break;
-        case ABE_BOTTOM:
-            This->AutoHideOffset.cx = 0;
-            This->AutoHideOffset.cy = h;
-            break;
-        }
-
-        KillTimer(This->hWnd, TIMER_ID_AUTOHIDE);
-        This->AutoHideState = AUTOHIDE_HIDDEN;
-        break;
-
-    case AUTOHIDE_SHOWING:
-        if (This->AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW)
-        {
-            This->AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW;
-        }
-        else if (This->AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW)
-        {
-            This->AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW;
-        }
-        else
-        {
-            This->AutoHideOffset.cx = 0;
-        }
-
-        if (This->AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW)
-        {
-            This->AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW;
-        }
-        else if (This->AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW)
-        {
-            This->AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW;
-        }
-        else
-        {
-            This->AutoHideOffset.cy = 0;
-        }
-
-        if (This->AutoHideOffset.cx != 0 || This->AutoHideOffset.cy != 0)
-        {
-            SetTimer(This->hWnd, TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
-            break;
-        }
-
-        /* fallthrough */
-    case AUTOHIDE_SHOWN:
-
-        KillTimer(This->hWnd, TIMER_ID_AUTOHIDE);
-        This->AutoHideState = AUTOHIDE_SHOWN;
-        break;
-    }
-
-    rc.left += This->AutoHideOffset.cx;
-    rc.right += This->AutoHideOffset.cx;
-    rc.top += This->AutoHideOffset.cy;
-    rc.bottom += This->AutoHideOffset.cy;
-
-    TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, This->AutoHideState);
-    SetWindowPos(This->hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
-}
-
-static LRESULT CALLBACK
-TrayWndProc(IN HWND hwnd,
-            IN UINT uMsg,
-            IN WPARAM wParam,
-            IN LPARAM lParam)
-{
-    ITrayWindowImpl *This = NULL;
-    LRESULT Ret = FALSE;
-
-    if (uMsg != WM_NCCREATE)
-    {
-        This = (ITrayWindowImpl*)GetWindowLongPtr(hwnd,
-                                                  0);
-    }
-
-    if (This != NULL || uMsg == WM_NCCREATE)
-    {
-        if (This != NULL && This->StartMenuBand != NULL)
-        {
-            MSG Msg;
-            LRESULT lRet;
-
-            Msg.hwnd = hwnd;
-            Msg.message = uMsg;
-            Msg.wParam = wParam;
-            Msg.lParam = lParam;
-
-            if (IMenuBand_TranslateMenuMessage(This->StartMenuBand,
-                                               &Msg,
-                                               &lRet) == S_OK)
-            {
-                return lRet;
-            }
-
-            wParam = Msg.wParam;
-            lParam = Msg.lParam;
-        }
-
-        switch (uMsg)
-        {
-            case WM_DISPLAYCHANGE:
-
-                /* Load the saved tray window settings */
-                ITrayWindowImpl_RegLoadSettings(This);
-
-                /* Move the tray window to the right position and resize it if neccessary */
-                ITrayWindowImpl_CheckTrayWndPosition(This);
-
-                /* Align all controls on the tray window */
-                ITrayWindowImpl_AlignControls(This, NULL);
-
-                break;
-
-            case WM_COPYDATA:
-            {
-                if (This->hwndTrayNotify)
-                {
-                    TrayNotify_NotifyMsg(This->hwndTrayNotify,
-                                         wParam,
-                                         lParam);
-                }
-                return TRUE;
-            }
-            case WM_THEMECHANGED:
-                ITrayWindowImpl_UpdateTheme(This);
-                return 0;
-            case WM_NCPAINT:
-                if (!This->TaskbarTheme)
-                    goto DefHandler;
-                return ITrayWindowImpl_DrawSizer(This,
-                                                 (HRGN)wParam);
-            case WM_ERASEBKGND:
-                if (!This->TaskbarTheme)
-                    goto DefHandler;
-                return ITrayWindowImpl_DrawBackground(This, (HDC)wParam);
-            case WM_CTLCOLORBTN:
-                SetBkMode((HDC)wParam, TRANSPARENT);
-                return (LRESULT)GetStockObject(HOLLOW_BRUSH);
-            case WM_NCHITTEST:
-            {
-                RECT rcClient;
-                POINT pt;
-
-                if (This->Locked)
-                {
-                    /* The user may not be able to resize the tray window.
-                       Pretend like the window is not sizeable when the user
-                       clicks on the border. */
-                    return HTBORDER;
-                }
-
-                SetLastError(ERROR_SUCCESS);
-                if (GetClientRect(hwnd,
-                                  &rcClient) &&
-                    (MapWindowPoints(hwnd,
-                                     NULL,
-                                     (LPPOINT)&rcClient,
-                                     2) != 0 || GetLastError() == ERROR_SUCCESS))
-                {
-                    pt.x = (SHORT)LOWORD(lParam);
-                    pt.y = (SHORT)HIWORD(lParam);
-
-                    if (PtInRect(&rcClient,
-                                 pt))
-                    {
-                        /* The user is trying to drag the tray window */
-                        return HTCAPTION;
-                    }
-
-                    /* Depending on the position of the tray window, allow only
-                       changing the border next to the monitor working area */
-                    switch (This->Position)
-                    {
-                        case ABE_TOP:
-                            if (pt.y > rcClient.bottom)
-                                return HTBOTTOM;
-                            break;
-                        case ABE_LEFT:
-                            if (pt.x > rcClient.right)
-                                return HTRIGHT;
-                            break;
-                        case ABE_RIGHT:
-                            if (pt.x < rcClient.left)
-                                return HTLEFT;
-                            break;
-                        case ABE_BOTTOM:
-                        default:
-                            if (pt.y < rcClient.top)
-                                return HTTOP;
-                            break;
-                    }
-                }
-                return HTBORDER;
-            }
-            case WM_MOVING:
-            {
-                POINT ptCursor;
-                PRECT pRect = (PRECT)lParam;
-
-                /* We need to ensure that an application can not accidently
-                   move the tray window (using SetWindowPos). However, we still
-                   need to be able to move the window in case the user wants to
-                   drag the tray window to another position or in case the user
-                   wants to resize the tray window. */
-                if (!This->Locked && GetCursorPos(&ptCursor))
-                {
-                    This->IsDragging = TRUE;
-                    This->DraggingPosition = ITrayWindowImpl_GetDraggingRectFromPt(This,
-                                                                                   ptCursor,
-                                                                                   pRect,
-                                                                                   &This->DraggingMonitor);
-                }
-                else
-                {
-                    *pRect = This->rcTrayWnd[This->Position];
-
-                    if (This->AutoHide)
-                    {
-                        pRect->left += This->AutoHideOffset.cx;
-                        pRect->right += This->AutoHideOffset.cx;
-                        pRect->top += This->AutoHideOffset.cy;
-                        pRect->bottom += This->AutoHideOffset.cy;
-                    }
-                }
-                return TRUE;
-            }
-
-            case WM_SIZING:
-            {
-                PRECT pRect = (PRECT)lParam;
-
-                if (!This->Locked)
-                {
-                    ITrayWindowImpl_CalculateValidSize(This,
-                                                       This->Position,
-                                                       pRect);
-                }
-                else
-                {
-                    *pRect = This->rcTrayWnd[This->Position];
-                    
-                    if (This->AutoHide)
-                    {
-                        pRect->left += This->AutoHideOffset.cx;
-                        pRect->right += This->AutoHideOffset.cx;
-                        pRect->top += This->AutoHideOffset.cy;
-                        pRect->bottom += This->AutoHideOffset.cy;
-                    }
-                }
-                return TRUE;
-            }
-
-            case WM_WINDOWPOSCHANGING:
-            {
-                ITrayWindowImpl_ChangingWinPos(This,
-                                               (LPWINDOWPOS)lParam);
-                break;
-            }
-
-            case WM_SIZE:
-            {
-                RECT rcClient;
-                InvalidateRect(This->hWnd, NULL, TRUE);
-                if (wParam == SIZE_RESTORED && lParam == 0)
-                {
-                    ITrayWindowImpl_ResizeWorkArea(This);
-                    /* Clip the tray window on multi monitor systems so the edges can't
-                       overlap into another monitor */
-                    ITrayWindowImpl_ApplyClipping(This,
-                                                  TRUE);
-
-                    if (!GetClientRect(This->hWnd,
-                                       &rcClient))
-                    {
-                        break;
-                    }
-                }
-                else
-                {
-                    rcClient.left = rcClient.top = 0;
-                    rcClient.right = LOWORD(lParam);
-                    rcClient.bottom = HIWORD(lParam);
-                }
-
-                ITrayWindowImpl_AlignControls(This,
-                                              &rcClient);
-                break;
-            }
-
-            case WM_ENTERSIZEMOVE:
-                This->InSizeMove = TRUE;
-                This->IsDragging = FALSE;
-                if (!This->Locked)
-                {
-                    /* Remove the clipping on multi monitor systems while dragging around */
-                    ITrayWindowImpl_ApplyClipping(This,
-                                                  FALSE);
-                }
-                break;
-
-            case WM_EXITSIZEMOVE:
-                This->InSizeMove = FALSE;
-                if (!This->Locked)
-                {
-                    /* Apply clipping */
-                    PostMessage(This->hWnd,
-                                WM_SIZE,
-                                SIZE_RESTORED,
-                                0);
-                }
-                break;
-
-            case WM_SYSCHAR:
-                switch (wParam)
-                {
-                    case TEXT(' '):
-                    {
-                        /* The user pressed Alt+Space, this usually brings up the system menu of a window.
-                           The tray window needs to handle this specially, since it normally doesn't have
-                           a system menu. */
-
-                        static const UINT uidDisableItem[] = {
-                            SC_RESTORE,
-                            SC_MOVE,
-                            SC_SIZE,
-                            SC_MAXIMIZE,
-                            SC_MINIMIZE,
-                        };
-                        HMENU hSysMenu;
-                        INT i;
-                        UINT uId;
-
-                        /* temporarily enable the system menu */
-                        SetWindowStyle(hwnd,
-                                       WS_SYSMENU,
-                                       WS_SYSMENU);
-
-                        hSysMenu = GetSystemMenu(hwnd,
-                                                 FALSE);
-                        if (hSysMenu != NULL)
-                        {
-                            /* Disable all items that are not relevant */
-                            for (i = 0; i != sizeof(uidDisableItem) / sizeof(uidDisableItem[0]); i++)
-                            {
-                                EnableMenuItem(hSysMenu,
-                                               uidDisableItem[i],
-                                               MF_BYCOMMAND | MF_GRAYED);
-                            }
-
-                            EnableMenuItem(hSysMenu,
-                                           SC_CLOSE,
-                                           MF_BYCOMMAND |
-                                               (SHRestricted(REST_NOCLOSE) ? MF_GRAYED : MF_ENABLED));
-
-                            /* Display the system menu */
-                            uId = ITrayWindowImpl_TrackMenu(This,
-                                                            hSysMenu,
-                                                            NULL,
-                                                            This->hwndStart,
-                                                            This->Position != ABE_TOP,
-                                                            FALSE);
-                            if (uId != 0)
-                            {
-                                SendMessage(This->hWnd,
-                                            WM_SYSCOMMAND,
-                                            (WPARAM)uId,
-                                            0);
-                            }
-                        }
-
-                        /* revert the system menu window style */
-                        SetWindowStyle(hwnd,
-                                       WS_SYSMENU,
-                                       0);
-                        break;
-                    }
-
-                    default:
-                        goto DefHandler;
-                }
-                break;
-
-            case WM_NCRBUTTONUP:
-                /* We want the user to be able to get a context menu even on the nonclient
-                   area (including the sizing border)! */
-                uMsg = WM_CONTEXTMENU;
-                wParam = (WPARAM)hwnd;
-                /* fall through */
-
-            case WM_CONTEXTMENU:
-            {
-                POINT pt, *ppt = NULL;
-                HWND hWndExclude = NULL;
-
-                /* Check if the administrator has forbidden access to context menus */
-                if (SHRestricted(REST_NOTRAYCONTEXTMENU))
-                    break;
-
-                pt.x = (SHORT)LOWORD(lParam);
-                pt.y = (SHORT)HIWORD(lParam);
-
-                if (pt.x != -1 || pt.y != -1)
-                    ppt = &pt;
-                else
-                    hWndExclude = This->hwndStart;
-
-                if ((HWND)wParam == This->hwndStart)
-                {
-                    /* Make sure we can't track the context menu if the start
-                       menu is currently being shown */
-                    if (!(SendMessage(This->hwndStart,
-                                      BM_GETSTATE,
-                                      0,
-                                      0) & BST_PUSHED))
-                    {
-                        ITrayWindowImpl_TrackCtxMenu(This,
-                                                     &StartMenuBtnCtxMenu,
-                                                     ppt,
-                                                     hWndExclude,
-                                                     This->Position == ABE_BOTTOM,
-                                                     This);
-                    }
-                }
-                else
-                {
-                    /* See if the context menu should be handled by the task band site */
-                    if (ppt != NULL && This->TrayBandSite != NULL)
-                    {
-                        HWND hWndAtPt;
-                        POINT ptClient = *ppt;
-
-                        /* Convert the coordinates to client-coordinates */
-                        MapWindowPoints(NULL,
-                                        This->hWnd,
-                                        &ptClient,
-                                        1);
-
-                        hWndAtPt = ChildWindowFromPoint(This->hWnd,
-                                                        ptClient);
-                        if (hWndAtPt != NULL &&
-                            (hWndAtPt == This->hwndRebar || IsChild(This->hwndRebar,
-                                                                    hWndAtPt)))
-                        {
-                            /* Check if the user clicked on the task switch window */
-                            ptClient = *ppt;
-                            MapWindowPoints(NULL,
-                                            This->hwndRebar,
-                                            &ptClient,
-                                            1);
-
-                            hWndAtPt = ChildWindowFromPointEx(This->hwndRebar,
-                                                              ptClient,
-                                                              CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
-                            if (hWndAtPt == This->hwndTaskSwitch)
-                                goto HandleTrayContextMenu;
-
-                            /* Forward the message to the task band site */
-                            ITrayBandSite_ProcessMessage(This->TrayBandSite,
-                                                         hwnd,
-                                                         uMsg,
-                                                         wParam,
-                                                         lParam,
-                                                         &Ret);
-                        }
-                        else
-                            goto HandleTrayContextMenu;
-                    }
-                    else
-                    {
-HandleTrayContextMenu:
-                        /* Tray the default tray window context menu */
-                        ITrayWindowImpl_TrackCtxMenu(This,
-                                                     &TrayWindowCtxMenu,
-                                                     ppt,
-                                                     NULL,
-                                                     FALSE,
-                                                     This);
-                    }
-                }
-                break;
-            }
-
-            case WM_NOTIFY:
-            {
-                /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
-                          the rebar control! But we shouldn't forward messages that the band
-                          site doesn't handle, such as other controls (start button, tray window */
-                if (This->TrayBandSite == NULL ||
-                    !SUCCEEDED(ITrayBandSite_ProcessMessage(This->TrayBandSite,
-                                                            hwnd,
-                                                            uMsg,
-                                                            wParam,
-                                                            lParam,
-                                                            &Ret)))
-                {
-                    const NMHDR *nmh = (const NMHDR *)lParam;
-
-                    if (nmh->hwndFrom == This->hwndTrayNotify)
-                    {
-                        switch (nmh->code)
-                        {
-                            case NTNWM_REALIGN:
-                                /* Cause all controls to be aligned */
-                                PostMessage(This->hWnd,
-                                            WM_SIZE,
-                                            SIZE_RESTORED,
-                                            0);
-                                break;
-                        }
-                    }
-                }
-                break;
-            }
-
-            case WM_NCLBUTTONDBLCLK:
-            {
-                /* We "handle" this message so users can't cause a weird maximize/restore
-                   window animation when double-clicking the tray window! */
-
-                /* We should forward mouse messages to child windows here.
-                   Right now, this is only clock double-click */
-                RECT rcClock;
-                if (TrayNotify_GetClockRect(This->hwndTrayNotify, &rcClock))
-                {
-                    POINT ptClick;
-                    ptClick.x = MAKEPOINTS(lParam).x;
-                    ptClick.y = MAKEPOINTS(lParam).y;
-                    if (PtInRect(&rcClock, ptClick))
-                        LaunchCPanel(NULL, TEXT("timedate.cpl"));
-                }
-                break;
-            }
-
-            case WM_NCCREATE:
-            {
-                LPCREATESTRUCT CreateStruct = (LPCREATESTRUCT)lParam;
-                This = (ITrayWindowImpl*)CreateStruct->lpCreateParams;
-
-                if (InterlockedCompareExchangePointer((PVOID*)&This->hWnd,
-                                                      (PVOID)hwnd,
-                                                      NULL) != NULL)
-                {
-                    /* Somebody else was faster... */
-                    return FALSE;
-                }
-
-                SetWindowLongPtr(hwnd,
-                                 0,
-                                 (LONG_PTR)This);
-
-                return ITrayWindowImpl_NCCreate(This);
-            }
-
-            case WM_CREATE:
-                ITrayWindowImpl_Create(This);
-                break;
-
-            case WM_NCDESTROY:
-                ITrayWindowImpl_Destroy(This);
-                break;
-
-            case WM_APP_TRAYDESTROY:
-                DestroyWindow(hwnd);
-                break;
-
-            case TWM_OPENSTARTMENU:
-            {
-                HWND hwndStartMenu;
-                HRESULT hr = IUnknown_GetWindow((IUnknown*)This->StartMenuPopup, &hwndStartMenu);
-                if (FAILED(hr))
-                    break;
-
-                if (IsWindowVisible(hwndStartMenu))
-                {
-                    IMenuPopup_OnSelect(This->StartMenuPopup, MPOS_CANCELLEVEL);
-                }
-                else
-                {
-                    SendMessage(This->hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), (LPARAM)This->hwndStart);
-                }
-
-                break;
-            }
-            case WM_COMMAND:
-                if ((HWND)lParam == This->hwndStart)
-                {
-                    PopupStartMenu(This);
-                    break;
-                }
-
-                if (This->TrayBandSite == NULL ||
-                    FAILED(ITrayBandSite_ProcessMessage(This->TrayBandSite,
-                                                            hwnd,
-                                                            uMsg,
-                                                            wParam,
-                                                            lParam,
-                                                            &Ret)))
-                {
-                    switch (LOWORD(wParam))
-                    {
-                        /* FIXME: Handle these commands as well */
-                        case IDM_TASKBARANDSTARTMENU:
-
-                            ITrayWindowImpl_DisplayProperties(ITrayWindow_from_impl(This));
-                            break;
-
-                        case IDM_SEARCH:
-                            break;
-
-                        case IDM_HELPANDSUPPORT:
-                        {
-                            /* TODO: Implement properly */
-
-                            LPCWSTR strSite = L"https://www.reactos.org/";
-
-                            /* TODO: Make localizable */
-                            LPCWSTR strCaption = L"Sorry";
-                            LPCWSTR strMessage = L"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed.";
-                            WCHAR tmpMessage[512];
-
-                            /* TODO: Read from the registry */
-                            LPCWSTR strVerb = NULL; /* default */
-                            LPCWSTR strPath = strSite;
-                            LPCWSTR strParams = NULL;
-
-                            /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */
-                            int result = (int) ShellExecuteW(hwnd, strVerb, strPath, strParams, NULL, SW_SHOWNORMAL);
-                            if (result <= 32)
-                            {
-                                StringCchPrintfW(tmpMessage, 512, strMessage, strSite, result);
-                                MessageBoxExW(hwnd, tmpMessage, strCaption, MB_OK, 0);
-                            }
-                            break;
-                        }
-
-                        case IDM_RUN:
-                        {
-                            ITrayWindowImpl_DisplayRunFileDlg(This);
-                            break;
-                        }
-
-                        /* FIXME: Handle these commands as well */
-                        case IDM_SYNCHRONIZE:
-                        case IDM_LOGOFF:
-                        case IDM_DISCONNECT:
-                        case IDM_UNDOCKCOMPUTER:
-                            break;
-
-                        case IDM_SHUTDOWN:
-                        {
-                            HANDLE hShell32;
-                            EXITWINDLG ExitWinDlg;
-
-                            hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
-                            ExitWinDlg = (EXITWINDLG)GetProcAddress(hShell32, (LPCSTR)60);
-
-                            ExitWinDlg(hwnd);
-                            break;
-                        }
-                    }
-                }
-                break;
-
-            case WM_MOUSEMOVE:
-            case WM_NCMOUSEMOVE:
-
-                if (This->AutoHide)
-                {
-                    SetTimer(This->hWnd, TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL);
-                }
-
-                break;
-            case WM_TIMER:
-                if (wParam == TIMER_ID_MOUSETRACK)
-                {
-                    ProcessMouseTracking(This);
-                }
-                else if (wParam == TIMER_ID_AUTOHIDE)
-                {
-                    ProcessAutoHide(This);
-                }
-
-                goto DefHandler;
-
-            default:
-                goto DefHandler;
-        }
-    }
-    else
-    {
-DefHandler:
-        Ret = DefWindowProc(hwnd,
-                            uMsg,
-                            wParam,
-                            lParam);
-    }
-
-    return Ret;
-}
-
-/*
- * Tray Window Context Menu
- */
-
-static HMENU
-CreateTrayWindowContextMenu(IN HWND hWndOwner,
-                            IN PVOID *ppcmContext,
-                            IN PVOID Context  OPTIONAL)
-{
-    ITrayWindowImpl *This = (ITrayWindowImpl *)Context;
-    IContextMenu *pcm = NULL;
-    HMENU hPopup;
-
-    hPopup = LoadPopupMenu(hExplorerInstance,
-                           MAKEINTRESOURCE(IDM_TRAYWND));
-
-    if (hPopup != NULL)
-    {
-        if (SHRestricted(REST_CLASSICSHELL) != 0)
-        {
-            DeleteMenu(hPopup,
-                       ID_LOCKTASKBAR,
-                       MF_BYCOMMAND);
-        }
-
-        CheckMenuItem(hPopup,
-                      ID_LOCKTASKBAR,
-                      MF_BYCOMMAND | (This->Locked ? MF_CHECKED : MF_UNCHECKED));
-
-        if (This->TrayBandSite != NULL)
-        {
-            if (SUCCEEDED(ITrayBandSite_AddContextMenus(This->TrayBandSite,
-                                                        hPopup,
-                                                        0,
-                                                        ID_SHELL_CMD_FIRST,
-                                                        ID_SHELL_CMD_LAST,
-                                                        CMF_NORMAL,
-                                                        &pcm)))
-            {
-                TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
-                *(IContextMenu **)ppcmContext = pcm;
-            }
-        }
-    }
-
-    return hPopup;
-}
-
-static VOID
-OnTrayWindowContextMenuCommand(IN HWND hWndOwner,
-                               IN UINT uiCmdId,
-                               IN PVOID pcmContext  OPTIONAL,
-                               IN PVOID Context  OPTIONAL)
-{
-    ITrayWindowImpl *This = (ITrayWindowImpl *)Context;
-    IContextMenu *pcm = (IContextMenu *)pcmContext;
-
-    if (uiCmdId != 0)
-    {
-        if (uiCmdId >= ID_SHELL_CMD_FIRST && uiCmdId <= ID_SHELL_CMD_LAST)
-        {
-            CMINVOKECOMMANDINFO cmici = {0};
-
-            if (pcm != NULL)
-            {
-                /* 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;
-
-                IContextMenu_InvokeCommand(pcm,
-                                           &cmici);
-            }
-        }
-        else
-        {
-            ITrayWindow_ExecContextMenuCmd(ITrayWindow_from_impl(This),
-                                           uiCmdId);
-        }
-    }
-
-    if (pcm != NULL)
-        IContextMenu_Release(pcm);
-}
-
-static const TRAYWINDOW_CTXMENU TrayWindowCtxMenu = {
-    CreateTrayWindowContextMenu,
-    OnTrayWindowContextMenuCommand
-};
-
-/*****************************************************************************/
-
-BOOL
-RegisterTrayWindowClass(VOID)
-{
-    WNDCLASS wcTrayWnd;
-    BOOL Ret;
-
-    if (!RegisterTrayNotifyWndClass())
-        return FALSE;
-
-    wcTrayWnd.style = CS_DBLCLKS;
-    wcTrayWnd.lpfnWndProc = TrayWndProc;
-    wcTrayWnd.cbClsExtra = 0;
-    wcTrayWnd.cbWndExtra = sizeof(ITrayWindowImpl *);
-    wcTrayWnd.hInstance = hExplorerInstance;
-    wcTrayWnd.hIcon = NULL;
-    wcTrayWnd.hCursor = LoadCursor(NULL,
-                                   IDC_ARROW);
-    wcTrayWnd.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
-    wcTrayWnd.lpszMenuName = NULL;
-    wcTrayWnd.lpszClassName = szTrayWndClass;
-
-    Ret = RegisterClass(&wcTrayWnd) != 0;
-
-    if (!Ret)
-        UnregisterTrayNotifyWndClass();
-
-    return Ret;
-}
-
-VOID
-UnregisterTrayWindowClass(VOID)
-{
-    UnregisterTrayNotifyWndClass();
-
-    UnregisterClass(szTrayWndClass,
-                    hExplorerInstance);
-}
-
-ITrayWindow *
-CreateTrayWindow(VOID)
-{
-    ITrayWindowImpl *This;
-    ITrayWindow *TrayWindow;
-
-    This = ITrayWindowImpl_Construct();
-    if (This != NULL)
-    {
-        TrayWindow = ITrayWindow_from_impl(This);
-
-        ITrayWindowImpl_Open(TrayWindow);
-
-        g_TrayWindow = This;
-
-        return TrayWindow;
-    }
-
-    return NULL;
-}
-
-VOID
-TrayProcessMessages(IN OUT ITrayWindow *Tray)
-{
-    ITrayWindowImpl *This;
-    MSG Msg;
-
-    This = impl_from_ITrayWindow(Tray);
-
-    /* FIXME: We should keep a reference here... */
-
-    while (PeekMessage(&Msg,
-                       NULL,
-                       0,
-                       0,
-                       PM_REMOVE))
-    {
-        if (Msg.message == WM_QUIT)
-            break;
-
-        if (This->StartMenuBand == NULL ||
-            IMenuBand_IsMenuMessage(This->StartMenuBand,
-                                    &Msg) != S_OK)
-        {
-            TranslateMessage(&Msg);
-            DispatchMessage(&Msg);
-        }
-    }
-}
-
-VOID
-TrayMessageLoop(IN OUT ITrayWindow *Tray)
-{
-    ITrayWindowImpl *This;
-    MSG Msg;
-    BOOL Ret;
-
-    This = impl_from_ITrayWindow(Tray);
-
-    /* FIXME: We should keep a reference here... */
-
-    while (1)
-    {
-        Ret = GetMessage(&Msg,
-                         NULL,
-                         0,
-                         0);
-
-        if (!Ret || Ret == -1)
-            break;
-
-        if (Msg.message == WM_HOTKEY)
-        {
-            switch (Msg.wParam)
-            {
-                case IDHK_RUN: /* Win+R */
-                    ITrayWindowImpl_DisplayRunFileDlg(This);
-                    break;
-            }
-        }
-
-        if (This->StartMenuBand == NULL ||
-            IMenuBand_IsMenuMessage(This->StartMenuBand,
-                                    &Msg) != S_OK)
-        {
-            TranslateMessage(&Msg);
-            DispatchMessage(&Msg);
-        }
-    }
-}
-
-/*
- * IShellDesktopTray
- *
- * NOTE: This is a very windows-specific COM interface used by SHCreateDesktop()!
- *       These are the calls I observed, it may be wrong/incomplete/buggy!!!
- *       The reason we implement it is because we have to use SHCreateDesktop() so
- *       that the shell provides the desktop window and all the features that come
- *       with it (especially positioning of desktop icons)
- */
-
-static HRESULT STDMETHODCALLTYPE
-ITrayWindowImpl_IShellDesktopTray_QueryInterface(IN OUT IShellDesktopTray *iface,
-                                                 IN REFIID riid,
-                                                 OUT LPVOID *ppvObj)
-{
-    ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    ITrayWindow *tray = ITrayWindow_from_impl(This);
-
-    TRACE("IShellDesktopTray::QueryInterface(0x%p, 0x%p)\n", riid, ppvObj);
-    return ITrayWindowImpl_QueryInterface(tray,
-                                          riid,
-                                          ppvObj);
-}
-
-static ULONG STDMETHODCALLTYPE
-ITrayWindowImpl_IShellDesktopTray_Release(IN OUT IShellDesktopTray *iface)
-{
-    ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    ITrayWindow *tray = ITrayWindow_from_impl(This);
-
-    TRACE("IShellDesktopTray::Release()\n");
-    return ITrayWindowImpl_Release(tray);
-}
-
-static ULONG STDMETHODCALLTYPE
-ITrayWindowImpl_IShellDesktopTray_AddRef(IN OUT IShellDesktopTray *iface)
-{
-    ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    ITrayWindow *tray = ITrayWindow_from_impl(This);
-
-    TRACE("IShellDesktopTray::AddRef()\n");
-    return ITrayWindowImpl_AddRef(tray);
-}
-
-static ULONG STDMETHODCALLTYPE
-ITrayWindowImpl_IShellDesktopTray_GetState(IN OUT IShellDesktopTray *iface)
-{
-    /* FIXME: Return ABS_ flags? */
-    TRACE("IShellDesktopTray::GetState() unimplemented!\n");
-    return 0;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayWindowImpl_IShellDesktopTray_GetTrayWindow(IN OUT IShellDesktopTray *iface,
-                                                OUT HWND *phWndTray)
-{
-    ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
-    *phWndTray = This->hWnd;
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow(IN OUT IShellDesktopTray *iface,
-                                                        IN HWND hWndDesktop)
-{
-    ITrayWindowImpl *This = impl_from_IShellDesktopTray(iface);
-    TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
-
-    This->hWndDesktop = hWndDesktop;
-    return S_OK;
-}
-
-static HRESULT STDMETHODCALLTYPE
-ITrayWindowImpl_IShellDesktopTray_Unknown(IN OUT IShellDesktopTray *iface,
-                                          IN DWORD dwUnknown1,
-                                          IN DWORD dwUnknown2)
-{
-    TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
-    return S_OK;
-}
-
-static const IShellDesktopTrayVtbl IShellDesktopTrayImpl_Vtbl =
-{
-    /*** IUnknown ***/
-    ITrayWindowImpl_IShellDesktopTray_QueryInterface,
-    ITrayWindowImpl_IShellDesktopTray_AddRef,
-    ITrayWindowImpl_IShellDesktopTray_Release,
-    /*** IShellDesktopTray ***/
-    ITrayWindowImpl_IShellDesktopTray_GetState,
-    ITrayWindowImpl_IShellDesktopTray_GetTrayWindow,
-    ITrayWindowImpl_IShellDesktopTray_RegisterDesktopWindow,
-    ITrayWindowImpl_IShellDesktopTray_Unknown
-};
-
-HRESULT
-ITrayWindowImpl_RaiseStartButton(ITrayWindowImpl * This)
-{
-    SendMessageW(This->hwndStart, BM_SETSTATE, FALSE, 0);
-    return S_OK;
-}
-
-HRESULT
-Tray_OnStartMenuDismissed()
-{
-    return ITrayWindowImpl_RaiseStartButton(g_TrayWindow);
-}
\ No newline at end of file
diff --git a/base/shell/explorer-new/traywnd.cpp b/base/shell/explorer-new/traywnd.cpp
new file mode 100644 (file)
index 0000000..9e8edd5
--- /dev/null
@@ -0,0 +1,3084 @@
+/*
+ * 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>
+
+extern HRESULT InitShellServices(HDPA * phdpa);
+extern HRESULT ShutdownShellServices(HDPA hdpa);
+
+extern const TRAYWINDOW_CTXMENU TrayWindowCtxMenu;
+
+#define WM_APP_TRAYDESTROY  (WM_APP + 0x100)
+
+#define TIMER_ID_AUTOHIDE 1
+#define TIMER_ID_MOUSETRACK 2
+#define MOUSETRACK_INTERVAL 100
+#define AUTOHIDE_DELAY_HIDE 2000
+#define AUTOHIDE_DELAY_SHOW 50
+#define AUTOHIDE_INTERVAL_ANIMATING 10
+
+#define AUTOHIDE_SPEED_SHOW 10
+#define AUTOHIDE_SPEED_HIDE 1
+
+#define AUTOHIDE_HIDDEN 0
+#define AUTOHIDE_SHOWING 1
+#define AUTOHIDE_SHOWN 2
+#define AUTOHIDE_HIDING 3
+
+static LONG TrayWndCount = 0;
+
+static const WCHAR szTrayWndClass [] = TEXT("Shell_TrayWnd");
+
+/*
+ * ITrayWindow
+ */
+
+const GUID IID_IShellDesktopTray = { 0x213e2df9, 0x9a14, 0x4328, { 0x99, 0xb1, 0x69, 0x61, 0xf9, 0x14, 0x3c, 0xe9 } };
+
+class ITrayWindowImpl :
+    public CComCoClass<ITrayWindowImpl>,
+    public CComObjectRootEx<CComMultiThreadModelNoCS>,
+    public CWindowImpl < ITrayWindowImpl, CWindow, CControlWinTraits >,
+    public ITrayWindow,
+    public IShellDesktopTray
+{
+    HTHEME TaskbarTheme;
+    HWND hWndDesktop;
+
+    HWND hwndStart;
+
+    IImageList * himlStartBtn;
+    SIZE StartBtnSize;
+    HFONT hStartBtnFont;
+    HFONT hCaptionFont;
+
+    CComPtr<ITrayBandSite> TrayBandSite;
+    HWND hwndRebar;
+    HWND hwndTaskSwitch;
+    HWND hwndTrayNotify;
+
+    DWORD Position;
+    HMONITOR Monitor;
+    HMONITOR PreviousMonitor;
+    DWORD DraggingPosition;
+    HMONITOR DraggingMonitor;
+
+    RECT rcTrayWnd[4];
+    RECT rcNewPosSize;
+    SIZE TraySize;
+    union
+    {
+        DWORD Flags;
+        struct
+        {
+            DWORD AutoHide : 1;
+            DWORD AlwaysOnTop : 1;
+            DWORD SmSmallIcons : 1;
+            DWORD HideClock : 1;
+            DWORD Locked : 1;
+
+            /* UI Status */
+            DWORD InSizeMove : 1;
+            DWORD IsDragging : 1;
+            DWORD NewPosSize : 1;
+        };
+    };
+
+    NONCLIENTMETRICS ncm;
+    HFONT hFont;
+
+    CComPtr<IMenuBand> StartMenuBand;
+    CComPtr<IMenuPopup> StartMenuPopup;
+    HBITMAP hbmStartMenu;
+
+    HWND hwndTrayPropertiesOwner;
+    HWND hwndRunFileDlgOwner;
+
+    UINT AutoHideState;
+    SIZE AutoHideOffset;
+    TRACKMOUSEEVENT MouseTrackingInfo;
+
+    HDPA hdpaShellServices;
+
+public:
+    ITrayWindowImpl() :
+        TaskbarTheme(NULL),
+        hWndDesktop(NULL),
+        hwndStart(NULL),
+        himlStartBtn(NULL),
+        hStartBtnFont(NULL),
+        hCaptionFont(NULL),
+        hwndRebar(NULL),
+        hwndTaskSwitch(NULL),
+        hwndTrayNotify(NULL),
+        Position(0),
+        Monitor(NULL),
+        PreviousMonitor(NULL),
+        DraggingPosition(0),
+        DraggingMonitor(NULL),
+        Flags(0),
+        hFont(NULL),
+        hbmStartMenu(NULL),
+        hwndTrayPropertiesOwner(NULL),
+        hwndRunFileDlgOwner(NULL),
+        AutoHideState(NULL),
+        hdpaShellServices(NULL)
+    {
+        ZeroMemory(&StartBtnSize, sizeof(StartBtnSize));
+        ZeroMemory(&rcTrayWnd, sizeof(rcTrayWnd));
+        ZeroMemory(&rcNewPosSize, sizeof(rcNewPosSize));
+        ZeroMemory(&TraySize, sizeof(TraySize));
+        ZeroMemory(&ncm, sizeof(ncm));
+        ZeroMemory(&AutoHideOffset, sizeof(AutoHideOffset));
+        ZeroMemory(&MouseTrackingInfo, sizeof(MouseTrackingInfo));
+    }
+
+    virtual ~ITrayWindowImpl()
+    {
+        (void) InterlockedExchangePointer((PVOID*) &m_hWnd, NULL);
+
+
+        if (hdpaShellServices != NULL)
+        {
+            ShutdownShellServices(hdpaShellServices);
+            hdpaShellServices = NULL;
+        }
+
+        if (himlStartBtn != NULL)
+        {
+            himlStartBtn->Release();
+            himlStartBtn = NULL;
+        }
+
+        if (hCaptionFont != NULL)
+        {
+            DeleteObject(hCaptionFont);
+            hCaptionFont = NULL;
+        }
+
+        if (hStartBtnFont != NULL)
+        {
+            DeleteObject(hStartBtnFont);
+            hStartBtnFont = NULL;
+        }
+
+        if (hFont != NULL)
+        {
+            DeleteObject(hFont);
+            hFont = NULL;
+        }
+
+        if (hbmStartMenu != NULL)
+        {
+            DeleteObject(hbmStartMenu);
+            hbmStartMenu = NULL;
+        }
+
+        if (TaskbarTheme)
+        {
+            CloseThemeData(TaskbarTheme);
+            TaskbarTheme = NULL;
+        }
+
+        if (InterlockedDecrement(&TrayWndCount) == 0)
+            PostQuitMessage(0);
+    }
+
+    BOOL LaunchCPanel(HWND hwnd, LPCTSTR applet)
+    {
+        WCHAR szParams[MAX_PATH];
+
+        StringCbCopy(szParams, sizeof(szParams),
+                     TEXT("shell32.dll,Control_RunDLL "));
+        if (FAILED_UNEXPECTEDLY(StringCbCat(szParams, sizeof(szParams),
+            applet)))
+            return FALSE;
+
+        return (ShellExecute(hwnd, TEXT("open"), TEXT("rundll32.exe"), szParams, NULL, SW_SHOWDEFAULT) > (HINSTANCE) 32);
+    }
+
+    /*
+     * ITrayWindow
+     */
+
+    BOOL UpdateNonClientMetrics()
+    {
+        ncm.cbSize = sizeof(ncm);
+        if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+        {
+            if (hFont != NULL)
+                DeleteObject(hFont);
+
+            hFont = CreateFontIndirect(&ncm.lfMessageFont);
+            return TRUE;
+        }
+
+        return FALSE;
+    }
+
+    VOID SetWindowsFont()
+    {
+        if (hwndTrayNotify != NULL)
+        {
+            SendMessage(hwndTrayNotify, WM_SETFONT, (WPARAM) hFont, TRUE);
+        }
+    }
+
+    HMONITOR GetScreenRectFromRect(
+        IN OUT RECT *pRect,
+        IN DWORD dwFlags)
+    {
+        MONITORINFO mi;
+        HMONITOR hMon;
+
+        mi.cbSize = sizeof(mi);
+        hMon = MonitorFromRect(pRect,
+                               dwFlags);
+        if (hMon != NULL &&
+            GetMonitorInfo(hMon,
+            &mi))
+        {
+            *pRect = mi.rcMonitor;
+        }
+        else
+        {
+            pRect->left = 0;
+            pRect->top = 0;
+            pRect->right = GetSystemMetrics(SM_CXSCREEN);
+            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
+
+            hMon = NULL;
+        }
+
+        return hMon;
+    }
+
+    HMONITOR GetMonitorFromRect(
+        IN const RECT *pRect)
+    {
+        HMONITOR hMon;
+
+        /* In case the monitor sizes or saved sizes differ a bit (probably
+           not a lot, only so the tray window overlaps into another monitor
+           now), minimize the risk that we determine a wrong monitor by
+           using the center point of the tray window if we can't determine
+           it using the rectangle. */
+        hMon = MonitorFromRect(pRect,
+                               MONITOR_DEFAULTTONULL);
+        if (hMon == NULL)
+        {
+            POINT pt;
+
+            pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
+            pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
+
+            /* be less error-prone, find the nearest monitor */
+            hMon = MonitorFromPoint(pt,
+                                    MONITOR_DEFAULTTONEAREST);
+        }
+
+        return hMon;
+    }
+
+    HMONITOR GetScreenRect(
+        IN HMONITOR hMonitor,
+        IN OUT RECT *pRect)
+    {
+        HMONITOR hMon = NULL;
+
+        if (hMonitor != NULL)
+        {
+            MONITORINFO mi;
+
+            mi.cbSize = sizeof(mi);
+            if (!GetMonitorInfo(hMonitor,
+                &mi))
+            {
+                /* Hm, the monitor is gone? Try to find a monitor where it
+                   could be located now */
+                hMon = GetMonitorFromRect(
+                    pRect);
+                if (hMon == NULL ||
+                    !GetMonitorInfo(hMon,
+                    &mi))
+                {
+                    hMon = NULL;
+                    goto GetPrimaryRect;
+                }
+            }
+
+            *pRect = mi.rcMonitor;
+        }
+        else
+        {
+GetPrimaryRect:
+            pRect->left = 0;
+            pRect->top = 0;
+            pRect->right = GetSystemMetrics(SM_CXSCREEN);
+            pRect->bottom = GetSystemMetrics(SM_CYSCREEN);
+        }
+
+        return hMon;
+    }
+
+    VOID MakeTrayRectWithSize(IN DWORD Position,
+                              IN const SIZE *pTraySize,
+                              IN OUT RECT *pRect)
+    {
+        switch (Position)
+        {
+        case ABE_LEFT:
+            pRect->right = pRect->left + pTraySize->cx;
+            break;
+
+        case ABE_TOP:
+            pRect->bottom = pRect->top + pTraySize->cy;
+            break;
+
+        case ABE_RIGHT:
+            pRect->left = pRect->right - pTraySize->cx;
+            break;
+
+        case ABE_BOTTOM:
+        default:
+            pRect->top = pRect->bottom - pTraySize->cy;
+            break;
+        }
+    }
+
+    VOID GetTrayRectFromScreenRect(IN DWORD Position,
+                                   IN const RECT *pScreen,
+                                   IN const SIZE *pTraySize OPTIONAL,
+                                   OUT RECT *pRect)
+    {
+        if (pTraySize == NULL)
+            pTraySize = &TraySize;
+
+        *pRect = *pScreen;
+
+        /* Move the border outside of the screen */
+        InflateRect(pRect,
+                    GetSystemMetrics(SM_CXEDGE),
+                    GetSystemMetrics(SM_CYEDGE));
+
+        MakeTrayRectWithSize(Position, pTraySize, pRect);
+    }
+
+    BOOL
+        IsPosHorizontal()
+    {
+        return Position == ABE_TOP || Position == ABE_BOTTOM;
+    }
+
+    HMONITOR
+        CalculateValidSize(
+        IN DWORD Position,
+        IN OUT RECT *pRect)
+    {
+        RECT rcScreen;
+        //BOOL Horizontal;
+        HMONITOR hMon;
+        SIZE szMax, szWnd;
+
+        //Horizontal = IsPosHorizontal();
+
+        szWnd.cx = pRect->right - pRect->left;
+        szWnd.cy = pRect->bottom - pRect->top;
+
+        rcScreen = *pRect;
+        hMon = GetScreenRectFromRect(
+            &rcScreen,
+            MONITOR_DEFAULTTONEAREST);
+
+        /* Calculate the maximum size of the tray window and limit the window
+           size to half of the screen's size. */
+        szMax.cx = (rcScreen.right - rcScreen.left) / 2;
+        szMax.cy = (rcScreen.bottom - rcScreen.top) / 2;
+        if (szWnd.cx > szMax.cx)
+            szWnd.cx = szMax.cx;
+        if (szWnd.cy > szMax.cy)
+            szWnd.cy = szMax.cy;
+
+        /* FIXME - calculate */
+
+        GetTrayRectFromScreenRect(
+            Position,
+            &rcScreen,
+            &szWnd,
+            pRect);
+
+        return hMon;
+    }
+
+#if 0
+    VOID
+        GetMinimumWindowSize(
+        OUT RECT *pRect)
+    {
+        RECT rcMin = {0};
+
+        AdjustWindowRectEx(&rcMin,
+                           GetWindowLong(m_hWnd,
+                           GWL_STYLE),
+                           FALSE,
+                           GetWindowLong(m_hWnd,
+                           GWL_EXSTYLE));
+
+        *pRect = rcMin;
+    }
+#endif
+
+
+    DWORD
+        GetDraggingRectFromPt(
+        IN POINT pt,
+        OUT RECT *pRect,
+        OUT HMONITOR *phMonitor)
+    {
+        HMONITOR hMon, hMonNew;
+        DWORD PosH, PosV, Pos;
+        SIZE DeltaPt, ScreenOffset;
+        RECT rcScreen;
+
+        rcScreen.left = 0;
+        rcScreen.top = 0;
+
+        /* Determine the screen rectangle */
+        hMon = MonitorFromPoint(pt,
+                                MONITOR_DEFAULTTONULL);
+
+        if (hMon != NULL)
+        {
+            MONITORINFO mi;
+
+            mi.cbSize = sizeof(mi);
+            if (!GetMonitorInfo(hMon,
+                &mi))
+            {
+                hMon = NULL;
+                goto GetPrimaryScreenRect;
+            }
+
+            /* make left top corner of the screen zero based to
+               make calculations easier */
+            pt.x -= mi.rcMonitor.left;
+            pt.y -= mi.rcMonitor.top;
+
+            ScreenOffset.cx = mi.rcMonitor.left;
+            ScreenOffset.cy = mi.rcMonitor.top;
+            rcScreen.right = mi.rcMonitor.right - mi.rcMonitor.left;
+            rcScreen.bottom = mi.rcMonitor.bottom - mi.rcMonitor.top;
+        }
+        else
+        {
+GetPrimaryScreenRect:
+            ScreenOffset.cx = 0;
+            ScreenOffset.cy = 0;
+            rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
+            rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
+        }
+
+        /* Calculate the nearest screen border */
+        if (pt.x < rcScreen.right / 2)
+        {
+            DeltaPt.cx = pt.x;
+            PosH = ABE_LEFT;
+        }
+        else
+        {
+            DeltaPt.cx = rcScreen.right - pt.x;
+            PosH = ABE_RIGHT;
+        }
+
+        if (pt.y < rcScreen.bottom / 2)
+        {
+            DeltaPt.cy = pt.y;
+            PosV = ABE_TOP;
+        }
+        else
+        {
+            DeltaPt.cy = rcScreen.bottom - pt.y;
+            PosV = ABE_BOTTOM;
+        }
+
+        Pos = (DeltaPt.cx * rcScreen.bottom < DeltaPt.cy * rcScreen.right) ? PosH : PosV;
+
+        /* Fix the screen origin to be relative to the primary monitor again */
+        OffsetRect(&rcScreen,
+                   ScreenOffset.cx,
+                   ScreenOffset.cy);
+
+        hMonNew = GetMonitorFromRect(
+            &rcTrayWnd[Pos]);
+        if (hMon != hMonNew)
+        {
+            SIZE szTray;
+
+            /* Recalculate the rectangle, we're dragging to another monitor.
+               We don't need to recalculate the rect on single monitor systems. */
+            szTray.cx = rcTrayWnd[Pos].right - rcTrayWnd[Pos].left;
+            szTray.cy = rcTrayWnd[Pos].bottom - rcTrayWnd[Pos].top;
+
+            GetTrayRectFromScreenRect(
+                Pos,
+                &rcScreen,
+                &szTray,
+                pRect);
+            if (AutoHide)
+            {
+                pRect->left += AutoHideOffset.cx;
+                pRect->right += AutoHideOffset.cx;
+                pRect->top += AutoHideOffset.cy;
+                pRect->bottom += AutoHideOffset.cy;
+            }
+            hMon = hMonNew;
+        }
+        else
+        {
+            /* The user is dragging the tray window on the same monitor. We don't need
+               to recalculate the rectangle */
+            *pRect = rcTrayWnd[Pos];
+            if (AutoHide)
+            {
+                pRect->left += AutoHideOffset.cx;
+                pRect->right += AutoHideOffset.cx;
+                pRect->top += AutoHideOffset.cy;
+                pRect->bottom += AutoHideOffset.cy;
+            }
+        }
+
+        *phMonitor = hMon;
+
+        return Pos;
+    }
+
+    DWORD
+        GetDraggingRectFromRect(
+        IN OUT RECT *pRect,
+        OUT HMONITOR *phMonitor)
+    {
+        POINT pt;
+
+        /* Calculate the center of the rectangle. We call
+           GetDraggingRectFromPt to calculate a valid
+           dragging rectangle */
+        pt.x = pRect->left + ((pRect->right - pRect->left) / 2);
+        pt.y = pRect->top + ((pRect->bottom - pRect->top) / 2);
+
+        return GetDraggingRectFromPt(
+            pt,
+            pRect,
+            phMonitor);
+    }
+
+    VOID
+        ChangingWinPos(
+        IN OUT LPWINDOWPOS pwp)
+    {
+        RECT rcTray;
+
+        if (IsDragging)
+        {
+            rcTray.left = pwp->x;
+            rcTray.top = pwp->y;
+            rcTray.right = rcTray.left + pwp->cx;
+            rcTray.bottom = rcTray.top + pwp->cy;
+            if (AutoHide)
+            {
+                rcTray.left -= AutoHideOffset.cx;
+                rcTray.right -= AutoHideOffset.cx;
+                rcTray.top -= AutoHideOffset.cy;
+                rcTray.bottom -= AutoHideOffset.cy;
+            }
+
+            if (!EqualRect(&rcTray,
+                &rcTrayWnd[DraggingPosition]))
+            {
+                /* Recalculate the rectangle, the user dragged the tray
+                   window to another monitor or the window was somehow else
+                   moved or resized */
+                DraggingPosition = GetDraggingRectFromRect(
+                    &rcTray,
+                    &DraggingMonitor);
+                //rcTrayWnd[DraggingPosition] = rcTray;
+            }
+
+            //Monitor = CalculateValidSize(
+            //                                                   DraggingPosition,
+            //                                                   &rcTray);
+
+            Monitor = DraggingMonitor;
+            Position = DraggingPosition;
+            IsDragging = FALSE;
+
+            rcTrayWnd[Position] = rcTray;
+            goto ChangePos;
+        }
+        else if (GetWindowRect(m_hWnd, &rcTray))
+        {
+            if (InSizeMove)
+            {
+                if (!(pwp->flags & SWP_NOMOVE))
+                {
+                    rcTray.left = pwp->x;
+                    rcTray.top = pwp->y;
+                }
+
+                if (!(pwp->flags & SWP_NOSIZE))
+                {
+                    rcTray.right = rcTray.left + pwp->cx;
+                    rcTray.bottom = rcTray.top + pwp->cy;
+                }
+
+                Position = GetDraggingRectFromRect(
+                    &rcTray,
+                    &Monitor);
+
+                if (!(pwp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
+                {
+                    SIZE szWnd;
+
+                    szWnd.cx = pwp->cx;
+                    szWnd.cy = pwp->cy;
+
+                    MakeTrayRectWithSize(Position, &szWnd, &rcTray);
+                }
+
+                if (AutoHide)
+                {
+                    rcTray.left -= AutoHideOffset.cx;
+                    rcTray.right -= AutoHideOffset.cx;
+                    rcTray.top -= AutoHideOffset.cy;
+                    rcTray.bottom -= AutoHideOffset.cy;
+                }
+                rcTrayWnd[Position] = rcTray;
+            }
+            else
+            {
+                /* If the user isn't resizing the tray window we need to make sure the
+                   new size or position is valid. this is to prevent changes to the window
+                   without user interaction. */
+                rcTray = rcTrayWnd[Position];
+            }
+
+ChangePos:
+            TraySize.cx = rcTray.right - rcTray.left;
+            TraySize.cy = rcTray.bottom - rcTray.top;
+
+            if (AutoHide)
+            {
+                rcTray.left += AutoHideOffset.cx;
+                rcTray.right += AutoHideOffset.cx;
+                rcTray.top += AutoHideOffset.cy;
+                rcTray.bottom += AutoHideOffset.cy;
+            }
+
+            pwp->flags &= ~(SWP_NOMOVE | SWP_NOSIZE);
+            pwp->x = rcTray.left;
+            pwp->y = rcTray.top;
+            pwp->cx = TraySize.cx;
+            pwp->cy = TraySize.cy;
+        }
+    }
+
+    VOID
+        ApplyClipping(IN BOOL Clip)
+    {
+        RECT rcClip, rcWindow;
+        HRGN hClipRgn;
+
+        if (GetWindowRect(m_hWnd, &rcWindow))
+        {
+            /* Disable clipping on systems with only one monitor */
+            if (GetSystemMetrics(SM_CMONITORS) <= 1)
+                Clip = FALSE;
+
+            if (Clip)
+            {
+                rcClip = rcWindow;
+
+                GetScreenRect(Monitor, &rcClip);
+
+                if (!IntersectRect(&rcClip, &rcClip, &rcWindow))
+                {
+                    rcClip = rcWindow;
+                }
+
+                OffsetRect(&rcClip,
+                           -rcWindow.left,
+                           -rcWindow.top);
+
+                hClipRgn = CreateRectRgnIndirect(&rcClip);
+            }
+            else
+                hClipRgn = NULL;
+
+            /* Set the clipping region or make sure the window isn't clipped
+               by disabling it explicitly. */
+            SetWindowRgn(m_hWnd, hClipRgn, TRUE);
+        }
+    }
+
+    VOID ResizeWorkArea()
+    {
+#if !WIN7_COMPAT_MODE
+        RECT rcTray, rcWorkArea;
+
+        /* If monitor has changed then fix the previous monitors work area */
+        if (PreviousMonitor != Monitor)
+        {
+            GetScreenRect(
+                PreviousMonitor,
+                &rcWorkArea);
+            SystemParametersInfo(SPI_SETWORKAREA,
+                                 1,
+                                 &rcWorkArea,
+                                 SPIF_SENDCHANGE);
+        }
+
+        rcTray = rcTrayWnd[Position];
+
+        GetScreenRect(
+            Monitor,
+            &rcWorkArea);
+        PreviousMonitor = Monitor;
+
+        /* If AutoHide is false then change the workarea to exclude the area that
+           the taskbar covers. */
+        if (!AutoHide)
+        {
+            switch (Position)
+            {
+            case ABE_TOP:
+                rcWorkArea.top = rcTray.bottom;
+                break;
+            case ABE_LEFT:
+                rcWorkArea.left = rcTray.right;
+                break;
+            case ABE_RIGHT:
+                rcWorkArea.right = rcTray.left;
+                break;
+            case ABE_BOTTOM:
+                rcWorkArea.bottom = rcTray.top;
+                break;
+            }
+        }
+
+        SystemParametersInfo(SPI_SETWORKAREA,
+                             1,
+                             &rcWorkArea,
+                             SPIF_SENDCHANGE);
+#endif
+    }
+
+    VOID CheckTrayWndPosition()
+    {
+        RECT rcTray;
+
+        rcTray = rcTrayWnd[Position];
+
+        if (AutoHide)
+        {
+            rcTray.left += AutoHideOffset.cx;
+            rcTray.right += AutoHideOffset.cx;
+            rcTray.top += AutoHideOffset.cy;
+            rcTray.bottom += AutoHideOffset.cy;
+        }
+
+        //    TRACE("CheckTray: %d: %d,%d,%d,%d\n", Position, rcTray.left, rcTray.top, rcTray.right, rcTray.bottom);
+
+        /* Move the tray window */
+        SetWindowPos(NULL,
+                     rcTray.left,
+                     rcTray.top,
+                     rcTray.right - rcTray.left,
+                     rcTray.bottom - rcTray.top,
+                     SWP_NOZORDER);
+
+        ResizeWorkArea();
+
+        ApplyClipping(
+            TRUE);
+    }
+
+    typedef struct _TW_STUCKRECTS2
+    {
+        DWORD cbSize;
+        LONG Unknown;
+        DWORD dwFlags;
+        DWORD Position;
+        SIZE Size;
+        RECT Rect;
+    } TW_STRUCKRECTS2, *PTW_STUCKRECTS2;
+
+    VOID
+        RegLoadSettings()
+    {
+        DWORD Pos;
+        TW_STRUCKRECTS2 sr;
+        RECT rcScreen;
+        SIZE WndSize, EdgeSize, DlgFrameSize;
+        DWORD cbSize = sizeof(sr);
+
+        EdgeSize.cx = GetSystemMetrics(SM_CXEDGE);
+        EdgeSize.cy = GetSystemMetrics(SM_CYEDGE);
+        DlgFrameSize.cx = GetSystemMetrics(SM_CXDLGFRAME);
+        DlgFrameSize.cy = GetSystemMetrics(SM_CYDLGFRAME);
+
+        if (SHGetValue(hkExplorer,
+            TEXT("StuckRects2"),
+            TEXT("Settings"),
+            NULL,
+            &sr,
+            &cbSize) == ERROR_SUCCESS &&
+            sr.cbSize == sizeof(sr))
+        {
+            AutoHide = (sr.dwFlags & ABS_AUTOHIDE) != 0;
+            AlwaysOnTop = (sr.dwFlags & ABS_ALWAYSONTOP) != 0;
+            SmSmallIcons = (sr.dwFlags & 0x4) != 0;
+            HideClock = (sr.dwFlags & 0x8) != 0;
+
+            /* FIXME: Are there more flags? */
+
+#if WIN7_COMPAT_MODE
+            Position = ABE_LEFT;
+#else
+            if (sr.Position > ABE_BOTTOM)
+                Position = ABE_BOTTOM;
+            else
+                Position = sr.Position;
+#endif
+
+            /* Try to find out which monitor the tray window was located on last.
+               Here we're only interested in the monitor screen that we think
+               is the last one used. We're going to determine on which monitor
+               we really are after calculating the docked position. */
+            rcScreen = sr.Rect;
+            GetScreenRectFromRect(
+                &rcScreen,
+                MONITOR_DEFAULTTONEAREST);
+        }
+        else
+        {
+            Position = ABE_BOTTOM;
+            AlwaysOnTop = TRUE;
+
+            /* Use the minimum size of the taskbar, we'll use the start
+               button as a minimum for now. Make sure we calculate the
+               entire window size, not just the client size. However, we
+               use a thinner border than a standard thick border, so that
+               the start button and bands are not stuck to the screen border. */
+            sr.Size.cx = StartBtnSize.cx + (2 * (EdgeSize.cx + DlgFrameSize.cx));
+            sr.Size.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
+
+            /* Use the primary screen by default */
+            rcScreen.left = 0;
+            rcScreen.top = 0;
+            rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
+            rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
+            GetScreenRectFromRect(
+                &rcScreen,
+                MONITOR_DEFAULTTOPRIMARY);
+        }
+
+        if (m_hWnd != NULL)
+            SetWindowPos(
+            AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
+            0,
+            0,
+            0,
+            0,
+            SWP_NOMOVE | SWP_NOSIZE);
+
+        /* Determine a minimum tray window rectangle. The "client" height is
+           zero here since we cannot determine an optimal minimum width when
+           loaded as a vertical tray window. We just need to make sure the values
+           loaded from the registry are at least. The windows explorer behaves
+           the same way, it allows the user to save a zero width vertical tray
+           window, but not a zero height horizontal tray window. */
+        WndSize.cx = 2 * (EdgeSize.cx + DlgFrameSize.cx);
+        WndSize.cy = StartBtnSize.cy + (2 * (EdgeSize.cy + DlgFrameSize.cy));
+
+        if (WndSize.cx < sr.Size.cx)
+            WndSize.cx = sr.Size.cx;
+        if (WndSize.cy < sr.Size.cy)
+            WndSize.cy = sr.Size.cy;
+
+        /* Save the calculated size */
+        TraySize = WndSize;
+
+        /* Calculate all docking rectangles. We need to do this here so they're
+           initialized and dragging the tray window to another position gives
+           usable results */
+        for (Pos = ABE_LEFT;
+             Pos <= ABE_BOTTOM;
+             Pos++)
+        {
+            GetTrayRectFromScreenRect(
+                Pos,
+                &rcScreen,
+                &TraySize,
+                &rcTrayWnd[Pos]);
+            //        TRACE("rcTrayWnd[%d(%d)]: %d,%d,%d,%d\n", Pos, Position, rcTrayWnd[Pos].left, rcTrayWnd[Pos].top, rcTrayWnd[Pos].right, rcTrayWnd[Pos].bottom);
+        }
+
+        /* Determine which monitor we are on. It shouldn't matter which docked
+           position rectangle we use */
+        Monitor = GetMonitorFromRect(
+            &rcTrayWnd[ABE_LEFT]);
+    }
+
+    UINT
+        TrackMenu(
+        IN HMENU hMenu,
+        IN POINT *ppt OPTIONAL,
+        IN HWND hwndExclude OPTIONAL,
+        IN BOOL TrackUp,
+        IN BOOL IsContextMenu)
+    {
+        TPMPARAMS tmp, *ptmp = NULL;
+        POINT pt;
+        UINT cmdId;
+        UINT fuFlags;
+
+        if (hwndExclude != NULL)
+        {
+            /* Get the client rectangle and map it to screen coordinates */
+            if (::GetClientRect(hwndExclude,
+                &tmp.rcExclude) &&
+                MapWindowPoints(hwndExclude,
+                NULL,
+                (LPPOINT) &tmp.rcExclude,
+                2) != 0)
+            {
+                ptmp = &tmp;
+            }
+        }
+
+        if (ppt == NULL)
+        {
+            if (ptmp == NULL &&
+                GetClientRect(&tmp.rcExclude) &&
+                MapWindowPoints(m_hWnd,
+                NULL,
+                (LPPOINT) &tmp.rcExclude,
+                2) != 0)
+            {
+                ptmp = &tmp;
+            }
+
+            if (ptmp != NULL)
+            {
+                /* NOTE: TrackPopupMenuEx will eventually align the track position
+                         for us, no need to take care of it here as long as the
+                         coordinates are somewhere within the exclusion rectangle */
+                pt.x = ptmp->rcExclude.left;
+                pt.y = ptmp->rcExclude.top;
+            }
+            else
+                pt.x = pt.y = 0;
+        }
+        else
+            pt = *ppt;
+
+        tmp.cbSize = sizeof(tmp);
+
+        fuFlags = TPM_RETURNCMD | TPM_VERTICAL;
+        fuFlags |= (TrackUp ? TPM_BOTTOMALIGN : TPM_TOPALIGN);
+        if (IsContextMenu)
+            fuFlags |= TPM_RIGHTBUTTON;
+        else
+            fuFlags |= (TrackUp ? TPM_VERNEGANIMATION : TPM_VERPOSANIMATION);
+
+        cmdId = TrackPopupMenuEx(hMenu,
+                                 fuFlags,
+                                 pt.x,
+                                 pt.y,
+                                 m_hWnd,
+                                 ptmp);
+
+        return cmdId;
+    }
+
+    UINT TrackCtxMenu(
+        IN const TRAYWINDOW_CTXMENU *pMenu,
+        IN POINT *ppt OPTIONAL,
+        IN HWND hwndExclude OPTIONAL,
+        IN BOOL TrackUp,
+        IN PVOID Context OPTIONAL)
+    {
+        HMENU hPopup;
+        UINT cmdId = 0;
+        PVOID pcmContext = NULL;
+
+        hPopup = pMenu->CreateCtxMenu(m_hWnd,
+                                      &pcmContext,
+                                      Context);
+        if (hPopup != NULL)
+        {
+            cmdId = TrackMenu(
+                hPopup,
+                ppt,
+                hwndExclude,
+                TrackUp,
+                TRUE);
+
+            pMenu->CtxMenuCommand(m_hWnd,
+                                  cmdId,
+                                  pcmContext,
+                                  Context);
+
+            DestroyMenu(hPopup);
+        }
+
+        return cmdId;
+    }
+
+
+    VOID UpdateStartButton(IN HBITMAP hbmStart OPTIONAL)
+    {
+        SIZE Size = { 0, 0 };
+
+        if (himlStartBtn == NULL ||
+            !SendMessage(hwndStart,
+            BCM_GETIDEALSIZE,
+            0,
+            (LPARAM) &Size))
+        {
+            Size.cx = GetSystemMetrics(SM_CXEDGE);
+            Size.cy = GetSystemMetrics(SM_CYEDGE);
+
+            if (hbmStart == NULL)
+            {
+                hbmStart = (HBITMAP) SendMessage(hwndStart,
+                                                 BM_GETIMAGE,
+                                                 IMAGE_BITMAP,
+                                                 0);
+            }
+
+            if (hbmStart != NULL)
+            {
+                BITMAP bmp;
+
+                if (GetObject(hbmStart,
+                    sizeof(bmp),
+                    &bmp) != 0)
+                {
+                    Size.cx += bmp.bmWidth;
+                    Size.cy += max(bmp.bmHeight,
+                                   GetSystemMetrics(SM_CYCAPTION));
+                }
+                else
+                {
+                    /* Huh?! Shouldn't happen... */
+                    goto DefSize;
+                }
+            }
+            else
+            {
+DefSize:
+                Size.cx += GetSystemMetrics(SM_CXMINIMIZED);
+                Size.cy += GetSystemMetrics(SM_CYCAPTION);
+            }
+        }
+
+        /* Save the size of the start button */
+        StartBtnSize = Size;
+    }
+
+    VOID
+        AlignControls(IN PRECT prcClient OPTIONAL)
+    {
+        RECT rcClient;
+        SIZE TraySize, StartSize;
+        POINT ptTrayNotify = { 0, 0 };
+        BOOL Horizontal;
+        HDWP dwp;
+
+        UpdateStartButton(NULL);
+        if (prcClient != NULL)
+        {
+            rcClient = *prcClient;
+        }
+        else
+        {
+            if (!GetClientRect(&rcClient))
+            {
+                return;
+            }
+        }
+
+        Horizontal = IsPosHorizontal();
+
+        /* We're about to resize/move the start button, the rebar control and
+           the tray notification control */
+        dwp = BeginDeferWindowPos(3);
+        if (dwp == NULL)
+            return;
+
+        /* Limit the Start button width to the client width, if neccessary */
+        StartSize = StartBtnSize;
+        if (StartSize.cx > rcClient.right)
+            StartSize.cx = rcClient.right;
+
+        if (hwndStart != NULL)
+        {
+            /* Resize and reposition the button */
+            dwp = DeferWindowPos(dwp,
+                                 hwndStart,
+                                 NULL,
+                                 0,
+                                 0,
+                                 StartSize.cx,
+                                 StartSize.cy,
+                                 SWP_NOZORDER | SWP_NOACTIVATE);
+            if (dwp == NULL)
+                return;
+        }
+
+        /* Determine the size that the tray notification window needs */
+        if (Horizontal)
+        {
+            TraySize.cx = 0;
+            TraySize.cy = rcClient.bottom;
+        }
+        else
+        {
+            TraySize.cx = rcClient.right;
+            TraySize.cy = 0;
+        }
+
+        if (hwndTrayNotify != NULL &&
+            SendMessage(hwndTrayNotify,
+            TNWM_GETMINIMUMSIZE,
+            (WPARAM) Horizontal,
+            (LPARAM) &TraySize))
+        {
+            /* Move the tray notification window to the desired location */
+            if (Horizontal)
+                ptTrayNotify.x = rcClient.right - TraySize.cx;
+            else
+                ptTrayNotify.y = rcClient.bottom - TraySize.cy;
+
+            dwp = DeferWindowPos(dwp,
+                                 hwndTrayNotify,
+                                 NULL,
+                                 ptTrayNotify.x,
+                                 ptTrayNotify.y,
+                                 TraySize.cx,
+                                 TraySize.cy,
+                                 SWP_NOZORDER | SWP_NOACTIVATE);
+            if (dwp == NULL)
+                return;
+        }
+
+        /* Resize/Move the rebar control */
+        if (hwndRebar != NULL)
+        {
+            POINT ptRebar = { 0, 0 };
+            SIZE szRebar;
+
+            SetWindowStyle(hwndRebar, CCS_VERT, Horizontal ? 0 : CCS_VERT);
+
+            if (Horizontal)
+            {
+                ptRebar.x = StartSize.cx + GetSystemMetrics(SM_CXSIZEFRAME);
+                szRebar.cx = ptTrayNotify.x - ptRebar.x;
+                szRebar.cy = rcClient.bottom;
+            }
+            else
+            {
+                ptRebar.y = StartSize.cy + GetSystemMetrics(SM_CYSIZEFRAME);
+                szRebar.cx = rcClient.right;
+                szRebar.cy = ptTrayNotify.y - ptRebar.y;
+            }
+
+            dwp = DeferWindowPos(dwp,
+                                 hwndRebar,
+                                 NULL,
+                                 ptRebar.x,
+                                 ptRebar.y,
+                                 szRebar.cx,
+                                 szRebar.cy,
+                                 SWP_NOZORDER | SWP_NOACTIVATE);
+        }
+
+        if (dwp != NULL)
+            EndDeferWindowPos(dwp);
+
+        if (hwndTaskSwitch != NULL)
+        {
+            /* Update the task switch window configuration */
+            SendMessage(hwndTaskSwitch,
+                        TSWM_UPDATETASKBARPOS,
+                        0,
+                        0);
+        }
+    }
+
+    BOOL
+        CreateStartBtnImageList()
+    {
+        HICON hIconStart;
+        SIZE IconSize;
+
+        if (himlStartBtn != NULL)
+            return TRUE;
+
+        IconSize.cx = GetSystemMetrics(SM_CXSMICON);
+        IconSize.cy = GetSystemMetrics(SM_CYSMICON);
+
+        /* Load the start button icon and create a image list for it */
+        hIconStart = (HICON) LoadImage(hExplorerInstance,
+                                       MAKEINTRESOURCE(IDI_START),
+                                       IMAGE_ICON,
+                                       IconSize.cx,
+                                       IconSize.cy,
+                                       LR_SHARED | LR_DEFAULTCOLOR);
+
+        if (hIconStart != NULL)
+        {
+            himlStartBtn = (IImageList*) ImageList_Create(IconSize.cx,
+                                                          IconSize.cy,
+                                                          ILC_COLOR32 | ILC_MASK,
+                                                          1,
+                                                          1);
+            if (himlStartBtn != NULL)
+            {
+                int s;
+                himlStartBtn->ReplaceIcon(-1, hIconStart, &s);
+                if (s >= 0)
+                {
+                    return TRUE;
+                }
+
+                /* Failed to add the icon! */
+                himlStartBtn->Release();
+                himlStartBtn = NULL;
+            }
+        }
+
+        return FALSE;
+    }
+
+    HBITMAP CreateStartButtonBitmap()
+    {
+        WCHAR szStartCaption[32];
+        HFONT hFontOld;
+        HDC hDC = NULL;
+        HDC hDCScreen = NULL;
+        SIZE Size, SmallIcon;
+        HBITMAP hbmpOld, hbmp = NULL;
+        HBITMAP hBitmap = NULL;
+        HICON hIconStart;
+        BOOL Ret;
+        UINT Flags;
+        RECT rcButton;
+
+        /* NOTE: this is the backwards compatibility code that is used if the
+                 Common Controls Version 6.0 are not available! */
+
+        if (!LoadString(hExplorerInstance,
+            IDS_START,
+            szStartCaption,
+            sizeof(szStartCaption) / sizeof(szStartCaption[0])))
+        {
+            return NULL;
+        }
+
+        /* Load the start button icon */
+        SmallIcon.cx = GetSystemMetrics(SM_CXSMICON);
+        SmallIcon.cy = GetSystemMetrics(SM_CYSMICON);
+        hIconStart = (HICON) LoadImage(hExplorerInstance,
+                                       MAKEINTRESOURCE(IDI_START),
+                                       IMAGE_ICON,
+                                       SmallIcon.cx,
+                                       SmallIcon.cy,
+                                       LR_SHARED | LR_DEFAULTCOLOR);
+
+        hDCScreen = GetDC(NULL);
+        if (hDCScreen == NULL)
+            goto Cleanup;
+
+        hDC = CreateCompatibleDC(hDCScreen);
+        if (hDC == NULL)
+            goto Cleanup;
+
+        hFontOld = (HFONT) SelectObject(hDC, hStartBtnFont);
+
+        Ret = GetTextExtentPoint32(hDC,
+                                   szStartCaption,
+                                   _tcslen(szStartCaption),
+                                   &Size);
+
+        SelectObject(hDC,
+                     hFontOld);
+        if (!Ret)
+            goto Cleanup;
+
+        /* Make sure the height is at least the size of a caption icon. */
+        if (hIconStart != NULL)
+            Size.cx += SmallIcon.cx + 4;
+        Size.cy = max(Size.cy,
+                      SmallIcon.cy);
+
+        /* Create the bitmap */
+        hbmp = CreateCompatibleBitmap(hDCScreen,
+                                      Size.cx,
+                                      Size.cy);
+        if (hbmp == NULL)
+            goto Cleanup;
+
+        /* Caluclate the button rect */
+        rcButton.left = 0;
+        rcButton.top = 0;
+        rcButton.right = Size.cx;
+        rcButton.bottom = Size.cy;
+
+        /* Draw the button */
+        hbmpOld = (HBITMAP) SelectObject(hDC, hbmp);
+
+        Flags = DC_TEXT | DC_INBUTTON;
+        if (hIconStart != NULL)
+            Flags |= DC_ICON;
+
+        if (DrawCapTemp != NULL)
+        {
+            Ret = DrawCapTemp(NULL,
+                              hDC,
+                              &rcButton,
+                              hStartBtnFont,
+                              hIconStart,
+                              szStartCaption,
+                              Flags);
+        }
+
+        SelectObject(hDC,
+                     hbmpOld);
+
+        if (!Ret)
+            goto Cleanup;
+
+        /* We successfully created the bitmap! */
+        hBitmap = hbmp;
+        hbmp = NULL;
+
+Cleanup:
+        if (hDCScreen != NULL)
+        {
+            ReleaseDC(NULL,
+                      hDCScreen);
+        }
+
+        if (hbmp != NULL)
+            DeleteObject(hbmp);
+
+        if (hDC != NULL)
+            DeleteDC(hDC);
+
+        return hBitmap;
+    }
+
+    LRESULT OnThemeChanged()
+    {
+        if (TaskbarTheme)
+            CloseThemeData(TaskbarTheme);
+
+        if (IsThemeActive())
+            TaskbarTheme = OpenThemeData(m_hWnd, L"TaskBar");
+        else
+            TaskbarTheme = 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)
+    {
+        WCHAR szStartCaption[32];
+
+        ((ITrayWindow*)this)->AddRef();
+
+        SetWindowTheme(m_hWnd, L"TaskBar", NULL);
+        OnThemeChanged();
+
+        InterlockedIncrement(&TrayWndCount);
+
+        if (!LoadString(hExplorerInstance,
+            IDS_START,
+            szStartCaption,
+            sizeof(szStartCaption) / sizeof(szStartCaption[0])))
+        {
+            szStartCaption[0] = TEXT('\0');
+        }
+
+        if (hStartBtnFont == NULL || hCaptionFont == NULL)
+        {
+            NONCLIENTMETRICS ncm;
+
+            /* Get the system fonts, we use the caption font,
+               always bold, though. */
+            ncm.cbSize = sizeof(ncm);
+            if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS,
+                sizeof(ncm),
+                &ncm,
+                FALSE))
+            {
+                if (hCaptionFont == NULL)
+                {
+                    ncm.lfCaptionFont.lfWeight = FW_NORMAL;
+                    hCaptionFont = CreateFontIndirect(&ncm.lfCaptionFont);
+                }
+
+                if (hStartBtnFont == NULL)
+                {
+                    ncm.lfCaptionFont.lfWeight = FW_BOLD;
+                    hStartBtnFont = CreateFontIndirect(&ncm.lfCaptionFont);
+                }
+            }
+        }
+
+        /* Create the Start button */
+        hwndStart = CreateWindowEx(0,
+                                   WC_BUTTON,
+                                   szStartCaption,
+                                   WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS |
+                                   BS_PUSHBUTTON | BS_CENTER | BS_VCENTER | BS_BITMAP,
+                                   0,
+                                   0,
+                                   0,
+                                   0,
+                                   m_hWnd,
+                                   (HMENU) IDC_STARTBTN,
+                                   hExplorerInstance,
+                                   NULL);
+        if (hwndStart)
+        {
+            SetWindowTheme(hwndStart, L"Start", NULL);
+            SendMessage(hwndStart,
+                        WM_SETFONT,
+                        (WPARAM) hStartBtnFont,
+                        FALSE);
+
+            if (CreateStartBtnImageList())
+            {
+                BUTTON_IMAGELIST bil;
+
+                /* Try to set the start button image. this requires the Common
+                   Controls 6.0 to be present (XP and later) */
+                bil.himl = (HIMAGELIST) himlStartBtn;
+                bil.margin.left = bil.margin.right = 1;
+                bil.margin.top = bil.margin.bottom = 1;
+                bil.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
+
+                if (!SendMessage(hwndStart,
+                    BCM_SETIMAGELIST,
+                    0,
+                    (LPARAM) &bil))
+                {
+                    /* Fall back to the deprecated method on older systems that don't
+                       support Common Controls 6.0 */
+                    himlStartBtn->Release();
+                    himlStartBtn = NULL;
+
+                    goto SetStartBtnImage;
+                }
+
+                /* We're using the image list, remove the BS_BITMAP style and
+                   don't center it horizontally */
+                SetWindowStyle(hwndStart,
+                               BS_BITMAP | BS_RIGHT,
+                               0);
+
+                UpdateStartButton(
+                    NULL);
+            }
+            else
+            {
+                HBITMAP hbmStart, hbmOld;
+
+SetStartBtnImage:
+                hbmStart = CreateStartButtonBitmap();
+                if (hbmStart != NULL)
+                {
+                    UpdateStartButton(
+                        hbmStart);
+
+                    hbmOld = (HBITMAP) SendMessage(hwndStart,
+                                                   BM_SETIMAGE,
+                                                   IMAGE_BITMAP,
+                                                   (LPARAM) hbmStart);
+
+                    if (hbmOld != NULL)
+                        DeleteObject(hbmOld);
+                }
+            }
+        }
+
+        /* Load the saved tray window settings */
+        RegLoadSettings();
+
+        /* Create and initialize the start menu */
+        hbmStartMenu = LoadBitmap(hExplorerInstance,
+                                  MAKEINTRESOURCE(IDB_STARTMENU));
+        StartMenuPopup = CreateStartMenu(this, &StartMenuBand, hbmStartMenu, 0);
+
+        /* Load the tray band site */
+        if (TrayBandSite != NULL)
+        {
+            TrayBandSite.Release();
+        }
+
+        TrayBandSite = CreateTrayBandSite(this, &hwndRebar, &hwndTaskSwitch);
+        SetWindowTheme(hwndRebar, L"TaskBar", NULL);
+
+        /* Create the tray notification window */
+        hwndTrayNotify = CreateTrayNotifyWnd(this, HideClock);
+
+        if (UpdateNonClientMetrics())
+        {
+            SetWindowsFont();
+        }
+
+        /* Move the tray window to the right position and resize it if neccessary */
+        CheckTrayWndPosition();
+
+        /* Align all controls on the tray window */
+        AlignControls(
+            NULL);
+
+        InitShellServices(&(hdpaShellServices));
+
+        if (AutoHide)
+        {
+            AutoHideState = AUTOHIDE_HIDING;
+            SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+        }
+        return TRUE;
+    }
+
+    HRESULT STDMETHODCALLTYPE Open()
+    {
+        RECT rcWnd;
+
+        /* Check if there's already a window created and try to show it.
+           If it was somehow destroyed just create a new tray window. */
+        if (m_hWnd != NULL && IsWindow())
+        {
+            if (!IsWindowVisible(m_hWnd))
+            {
+                CheckTrayWndPosition();
+
+                ShowWindow(SW_SHOW);
+            }
+
+            return S_OK;
+        }
+
+        DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE;
+        if (AlwaysOnTop)
+            dwExStyle |= WS_EX_TOPMOST;
+
+        DWORD dwStyle = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
+            WS_BORDER | WS_THICKFRAME;
+
+        ZeroMemory(&rcWnd, sizeof(rcWnd));
+        if (Position != (DWORD) -1)
+            rcWnd = rcTrayWnd[Position];
+
+        if (!Create(NULL, rcWnd, NULL, dwStyle, dwExStyle))
+            return E_FAIL;
+
+        return S_OK;
+    }
+
+    HRESULT STDMETHODCALLTYPE Close()
+    {
+        if (m_hWnd != NULL)
+        {
+            SendMessage(m_hWnd,
+                        WM_APP_TRAYDESTROY,
+                        0,
+                        0);
+        }
+
+        return S_OK;
+    }
+
+    HWND STDMETHODCALLTYPE GetHWND()
+    {
+        return m_hWnd;
+    }
+
+    BOOL STDMETHODCALLTYPE IsSpecialHWND(IN HWND hWnd)
+    {
+        return (m_hWnd == hWnd ||
+                (hWndDesktop != NULL && m_hWnd == hWndDesktop));
+    }
+
+    BOOL STDMETHODCALLTYPE
+        IsHorizontal()
+    {
+        return IsPosHorizontal();
+    }
+
+    HFONT STDMETHODCALLTYPE GetCaptionFonts(OUT HFONT *phBoldCaption OPTIONAL)
+    {
+        if (phBoldCaption != NULL)
+            *phBoldCaption = hStartBtnFont;
+
+        return hCaptionFont;
+    }
+
+    DWORD WINAPI TrayPropertiesThread()
+    {
+        HWND hwnd;
+        RECT posRect;
+
+        GetWindowRect(hwndStart, &posRect);
+        hwnd = CreateWindowEx(0,
+                              WC_STATIC,
+                              NULL,
+                              WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
+                              posRect.left,
+                              posRect.top,
+                              posRect.right - posRect.left,
+                              posRect.bottom - posRect.top,
+                              NULL,
+                              NULL,
+                              NULL,
+                              NULL);
+
+        hwndTrayPropertiesOwner = hwnd;
+
+        DisplayTrayProperties(hwnd);
+
+        hwndTrayPropertiesOwner = NULL;
+        DestroyWindow();
+
+        return 0;
+    }
+
+    static DWORD WINAPI s_TrayPropertiesThread(IN OUT PVOID pParam)
+    {
+        ITrayWindowImpl *This = (ITrayWindowImpl*) pParam;
+
+        return This->TrayPropertiesThread();
+    }
+
+    HWND STDMETHODCALLTYPE DisplayProperties()
+    {
+        HWND hTrayProp;
+
+        if (hwndTrayPropertiesOwner)
+        {
+            hTrayProp = GetLastActivePopup(hwndTrayPropertiesOwner);
+            if (hTrayProp != NULL &&
+                hTrayProp != hwndTrayPropertiesOwner)
+            {
+                SetForegroundWindow(hTrayProp);
+                return NULL;
+            }
+        }
+
+        CloseHandle(CreateThread(NULL, 0, s_TrayPropertiesThread, this, 0, NULL));
+        return NULL;
+    }
+
+    VOID OpenCommonStartMenuDirectory(IN HWND hWndOwner, IN LPCTSTR lpOperation)
+    {
+        WCHAR szDir[MAX_PATH];
+
+        if (SHGetSpecialFolderPath(hWndOwner,
+            szDir,
+            CSIDL_COMMON_STARTMENU,
+            FALSE))
+        {
+            ShellExecute(hWndOwner,
+                         lpOperation,
+                         NULL,
+                         NULL,
+                         szDir,
+                         SW_SHOWNORMAL);
+        }
+    }
+
+    VOID OpenTaskManager(IN HWND hWndOwner)
+    {
+        ShellExecute(hWndOwner,
+                     TEXT("open"),
+                     TEXT("taskmgr.exe"),
+                     NULL,
+                     NULL,
+                     SW_SHOWNORMAL);
+    }
+
+    BOOL STDMETHODCALLTYPE ExecContextMenuCmd(IN UINT uiCmd)
+    {
+        BOOL bHandled = TRUE;
+
+        switch (uiCmd)
+        {
+        case ID_SHELL_CMD_PROPERTIES:
+            DisplayProperties();
+            break;
+
+        case ID_SHELL_CMD_OPEN_ALL_USERS:
+            OpenCommonStartMenuDirectory(m_hWnd,
+                                         TEXT("open"));
+            break;
+
+        case ID_SHELL_CMD_EXPLORE_ALL_USERS:
+            OpenCommonStartMenuDirectory(m_hWnd,
+                                         TEXT("explore"));
+            break;
+
+        case ID_LOCKTASKBAR:
+            if (SHRestricted(REST_CLASSICSHELL) == 0)
+            {
+                Lock(!Locked);
+            }
+            break;
+
+        case ID_SHELL_CMD_OPEN_TASKMGR:
+            OpenTaskManager(m_hWnd);
+            break;
+
+        case ID_SHELL_CMD_UNDO_ACTION:
+            break;
+
+        case ID_SHELL_CMD_SHOW_DESKTOP:
+            break;
+
+        case ID_SHELL_CMD_TILE_WND_H:
+            TileWindows(NULL, MDITILE_HORIZONTAL, NULL, 0, NULL);
+            break;
+
+        case ID_SHELL_CMD_TILE_WND_V:
+            TileWindows(NULL, MDITILE_VERTICAL, NULL, 0, NULL);
+            break;
+
+        case ID_SHELL_CMD_CASCADE_WND:
+            CascadeWindows(NULL, MDITILE_SKIPDISABLED, NULL, 0, NULL);
+            break;
+
+        case ID_SHELL_CMD_CUST_NOTIF:
+            break;
+
+        case ID_SHELL_CMD_ADJUST_DAT:
+            LaunchCPanel(NULL, TEXT("timedate.cpl"));
+            break;
+
+        default:
+            TRACE("ITrayWindow::ExecContextMenuCmd(%u): Unhandled Command ID!\n", uiCmd);
+            bHandled = FALSE;
+            break;
+        }
+
+        return bHandled;
+    }
+
+    BOOL STDMETHODCALLTYPE Lock(IN BOOL bLock)
+    {
+        BOOL bPrevLock;
+
+        bPrevLock = Locked;
+        if (Locked != bLock)
+        {
+            Locked = bLock;
+
+            if (TrayBandSite != NULL)
+            {
+                if (!SUCCEEDED(TrayBandSite->Lock(
+                    bLock)))
+                {
+                    /* Reset?? */
+                    Locked = bPrevLock;
+                }
+            }
+        }
+
+        return bPrevLock;
+    }
+
+
+    LRESULT DrawBackground(HDC hdc)
+    {
+        RECT rect;
+        int partId;
+
+        GetClientRect(&rect);
+
+        if (TaskbarTheme)
+        {
+            GetClientRect(&rect);
+            switch (Position)
+            {
+            case ABE_LEFT:
+                partId = TBP_BACKGROUNDLEFT;
+                break;
+            case ABE_TOP:
+                partId = TBP_BACKGROUNDTOP;
+                break;
+            case ABE_RIGHT:
+                partId = TBP_BACKGROUNDRIGHT;
+                break;
+            case ABE_BOTTOM:
+            default:
+                partId = TBP_BACKGROUNDBOTTOM;
+                break;
+            }
+
+            if (IsThemeBackgroundPartiallyTransparent(TaskbarTheme, partId, 0))
+            {
+                DrawThemeParentBackground(m_hWnd, hdc, &rect);
+            }
+
+            DrawThemeBackground(TaskbarTheme, hdc, partId, 0, &rect, 0);
+        }
+
+        return TRUE;
+    }
+
+    LRESULT OnEraseBackground(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HDC hdc = (HDC) wParam;
+
+        if (!TaskbarTheme)
+        {
+            bHandled = FALSE;
+            return 0;
+        }
+
+        return DrawBackground(hdc);
+    }
+
+    int DrawSizer(IN HRGN hRgn)
+    {
+        HDC hdc;
+        RECT rect;
+        int backoundPart;
+
+        GetWindowRect(m_hWnd, &rect);
+        OffsetRect(&rect, -rect.left, -rect.top);
+
+        hdc = GetDCEx(m_hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_PARENTCLIP);
+
+        switch (Position)
+        {
+        case ABE_LEFT:
+            backoundPart = TBP_SIZINGBARLEFT;
+            rect.left = rect.right - GetSystemMetrics(SM_CXSIZEFRAME);
+            break;
+        case ABE_TOP:
+            backoundPart = TBP_SIZINGBARTOP;
+            rect.top = rect.bottom - GetSystemMetrics(SM_CYSIZEFRAME);
+            break;
+        case ABE_RIGHT:
+            backoundPart = TBP_SIZINGBARRIGHT;
+            rect.right = rect.left + GetSystemMetrics(SM_CXSIZEFRAME);
+            break;
+        case ABE_BOTTOM:
+        default:
+            backoundPart = TBP_SIZINGBARBOTTOM;
+            rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZEFRAME);
+            break;
+        }
+
+        DrawThemeBackground(TaskbarTheme, hdc, backoundPart, 0, &rect, 0);
+
+        ReleaseDC(m_hWnd, hdc);
+        return 0;
+    }
+
+    DWORD WINAPI RunFileDlgThread()
+    {
+        HINSTANCE hShell32;
+        RUNFILEDLG RunFileDlg;
+        HWND hwnd;
+        RECT posRect;
+
+        GetWindowRect(hwndStart, &posRect);
+
+        hwnd = CreateWindowEx(0,
+                              WC_STATIC,
+                              NULL,
+                              WS_OVERLAPPED | WS_DISABLED | WS_CLIPSIBLINGS | WS_BORDER | SS_LEFT,
+                              posRect.left,
+                              posRect.top,
+                              posRect.right - posRect.left,
+                              posRect.bottom - posRect.top,
+                              NULL,
+                              NULL,
+                              NULL,
+                              NULL);
+
+        hwndRunFileDlgOwner = hwnd;
+
+        hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
+        RunFileDlg = (RUNFILEDLG) GetProcAddress(hShell32, (LPCSTR) 61);
+
+        RunFileDlg(hwnd, NULL, NULL, NULL, NULL, RFF_CALCDIRECTORY);
+
+        hwndRunFileDlgOwner = NULL;
+        ::DestroyWindow(hwnd);
+
+        return 0;
+    }
+
+    static DWORD WINAPI s_RunFileDlgThread(IN OUT PVOID pParam)
+    {
+        ITrayWindowImpl * This = (ITrayWindowImpl*) pParam;
+        return This->RunFileDlgThread();
+    }
+
+    void DisplayRunFileDlg()
+    {
+        HWND hRunDlg;
+        if (hwndRunFileDlgOwner)
+        {
+            hRunDlg = GetLastActivePopup(hwndRunFileDlgOwner);
+            if (hRunDlg != NULL &&
+                hRunDlg != hwndRunFileDlgOwner)
+            {
+                SetForegroundWindow(hRunDlg);
+                return;
+            }
+        }
+
+        CloseHandle(CreateThread(NULL, 0, s_RunFileDlgThread, this, 0, NULL));
+    }
+
+    void PopupStartMenu()
+    {
+        if (StartMenuPopup != NULL)
+        {
+            POINTL pt;
+            RECTL rcExclude;
+            DWORD dwFlags = 0;
+
+            if (GetWindowRect(hwndStart,
+                (RECT*) &rcExclude))
+            {
+                switch (Position)
+                {
+                case ABE_BOTTOM:
+                    pt.x = rcExclude.left;
+                    pt.y = rcExclude.top;
+                    dwFlags |= MPPF_BOTTOM;
+                    break;
+                case ABE_TOP:
+                case ABE_LEFT:
+                    pt.x = rcExclude.left;
+                    pt.y = rcExclude.bottom;
+                    dwFlags |= MPPF_TOP | MPPF_ALIGN_RIGHT;
+                    break;
+                case ABE_RIGHT:
+                    pt.x = rcExclude.right;
+                    pt.y = rcExclude.bottom;
+                    dwFlags |= MPPF_TOP | MPPF_ALIGN_LEFT;
+                    break;
+                }
+
+                StartMenuPopup->Popup(
+                    &pt,
+                    &rcExclude,
+                    dwFlags);
+
+                SendMessageW(hwndStart, BM_SETSTATE, TRUE, 0);
+            }
+        }
+    }
+
+    void ProcessMouseTracking()
+    {
+        RECT rcCurrent;
+        POINT pt;
+        BOOL over;
+        UINT state = AutoHideState;
+
+        GetCursorPos(&pt);
+        GetWindowRect(m_hWnd, &rcCurrent);
+        over = PtInRect(&rcCurrent, pt);
+
+        if (SendMessage(hwndStart, BM_GETSTATE, 0, 0) != BST_UNCHECKED)
+        {
+            over = TRUE;
+        }
+
+        if (over)
+        {
+            if (state == AUTOHIDE_HIDING)
+            {
+                TRACE("AutoHide cancelling hide.\n");
+                AutoHideState = AUTOHIDE_SHOWING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+            }
+            else if (state == AUTOHIDE_HIDDEN)
+            {
+                TRACE("AutoHide starting show.\n");
+                AutoHideState = AUTOHIDE_SHOWING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_SHOW, NULL);
+            }
+        }
+        else
+        {
+            if (state == AUTOHIDE_SHOWING)
+            {
+                TRACE("AutoHide cancelling show.\n");
+                AutoHideState = AUTOHIDE_HIDING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+            }
+            else if (state == AUTOHIDE_SHOWN)
+            {
+                TRACE("AutoHide starting hide.\n");
+                AutoHideState = AUTOHIDE_HIDING;
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_DELAY_HIDE, NULL);
+            }
+
+            KillTimer(TIMER_ID_MOUSETRACK);
+        }
+    }
+
+    void ProcessAutoHide()
+    {
+        RECT rc = rcTrayWnd[Position];
+        INT w = TraySize.cx - GetSystemMetrics(SM_CXBORDER) * 2 - 1;
+        INT h = TraySize.cy - GetSystemMetrics(SM_CYBORDER) * 2 - 1;
+
+        TRACE("AutoHide Timer received for %u, rc=(%d, %d, %d, %d), w=%d, h=%d.\n", AutoHideState, rc.left, rc.top, rc.right, rc.bottom, w, h);
+
+        switch (AutoHideState)
+        {
+        case AUTOHIDE_HIDING:
+            switch (Position)
+            {
+            case ABE_LEFT:
+                AutoHideOffset.cy = 0;
+                AutoHideOffset.cx -= AUTOHIDE_SPEED_HIDE;
+                if (AutoHideOffset.cx < -w)
+                    AutoHideOffset.cx = -w;
+                break;
+            case ABE_TOP:
+                AutoHideOffset.cx = 0;
+                AutoHideOffset.cy -= AUTOHIDE_SPEED_HIDE;
+                if (AutoHideOffset.cy < -h)
+                    AutoHideOffset.cy = -h;
+                break;
+            case ABE_RIGHT:
+                AutoHideOffset.cy = 0;
+                AutoHideOffset.cx += AUTOHIDE_SPEED_HIDE;
+                if (AutoHideOffset.cx > w)
+                    AutoHideOffset.cx = w;
+                break;
+            case ABE_BOTTOM:
+                AutoHideOffset.cx = 0;
+                AutoHideOffset.cy += AUTOHIDE_SPEED_HIDE;
+                if (AutoHideOffset.cy > h)
+                    AutoHideOffset.cy = h;
+                break;
+            }
+
+            if (AutoHideOffset.cx != w && AutoHideOffset.cy != h)
+            {
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+                break;
+            }
+
+            /* fallthrough */
+        case AUTOHIDE_HIDDEN:
+
+            switch (Position)
+            {
+            case ABE_LEFT:
+                AutoHideOffset.cx = -w;
+                AutoHideOffset.cy = 0;
+                break;
+            case ABE_TOP:
+                AutoHideOffset.cx = 0;
+                AutoHideOffset.cy = -h;
+                break;
+            case ABE_RIGHT:
+                AutoHideOffset.cx = w;
+                AutoHideOffset.cy = 0;
+                break;
+            case ABE_BOTTOM:
+                AutoHideOffset.cx = 0;
+                AutoHideOffset.cy = h;
+                break;
+            }
+
+            KillTimer(TIMER_ID_AUTOHIDE);
+            AutoHideState = AUTOHIDE_HIDDEN;
+            break;
+
+        case AUTOHIDE_SHOWING:
+            if (AutoHideOffset.cx >= AUTOHIDE_SPEED_SHOW)
+            {
+                AutoHideOffset.cx -= AUTOHIDE_SPEED_SHOW;
+            }
+            else if (AutoHideOffset.cx <= -AUTOHIDE_SPEED_SHOW)
+            {
+                AutoHideOffset.cx += AUTOHIDE_SPEED_SHOW;
+            }
+            else
+            {
+                AutoHideOffset.cx = 0;
+            }
+
+            if (AutoHideOffset.cy >= AUTOHIDE_SPEED_SHOW)
+            {
+                AutoHideOffset.cy -= AUTOHIDE_SPEED_SHOW;
+            }
+            else if (AutoHideOffset.cy <= -AUTOHIDE_SPEED_SHOW)
+            {
+                AutoHideOffset.cy += AUTOHIDE_SPEED_SHOW;
+            }
+            else
+            {
+                AutoHideOffset.cy = 0;
+            }
+
+            if (AutoHideOffset.cx != 0 || AutoHideOffset.cy != 0)
+            {
+                SetTimer(TIMER_ID_AUTOHIDE, AUTOHIDE_INTERVAL_ANIMATING, NULL);
+                break;
+            }
+
+            /* fallthrough */
+        case AUTOHIDE_SHOWN:
+
+            KillTimer(TIMER_ID_AUTOHIDE);
+            AutoHideState = AUTOHIDE_SHOWN;
+            break;
+        }
+
+        rc.left += AutoHideOffset.cx;
+        rc.right += AutoHideOffset.cx;
+        rc.top += AutoHideOffset.cy;
+        rc.bottom += AutoHideOffset.cy;
+
+        TRACE("AutoHide Changing position to (%d, %d, %d, %d) and state=%u.\n", rc.left, rc.top, rc.right, rc.bottom, AutoHideState);
+        SetWindowPos(NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOACTIVATE | SWP_NOZORDER);
+    }
+
+    LRESULT OnDisplayChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        /* Load the saved tray window settings */
+        RegLoadSettings();
+
+        /* Move the tray window to the right position and resize it if neccessary */
+        CheckTrayWndPosition();
+
+        /* Align all controls on the tray window */
+        AlignControls(NULL);
+
+        return TRUE;
+    }
+
+    LRESULT OnCopyData(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (hwndTrayNotify)
+        {
+            TrayNotify_NotifyMsg(wParam, lParam);
+        }
+        return TRUE;
+    }
+
+    LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (!TaskbarTheme)
+        {
+            bHandled = FALSE;
+            return 0;
+        }
+
+        return DrawSizer((HRGN) wParam);
+    }
+
+    LRESULT OnCtlColorBtn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        SetBkMode((HDC) wParam, TRANSPARENT);
+        return (LRESULT) GetStockObject(HOLLOW_BRUSH);
+    }
+
+    LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        RECT rcClient;
+        POINT pt;
+
+        if (Locked)
+        {
+            /* The user may not be able to resize the tray window.
+            Pretend like the window is not sizeable when the user
+            clicks on the border. */
+            return HTBORDER;
+        }
+
+        SetLastError(ERROR_SUCCESS);
+        if (GetClientRect(&rcClient) &&
+            (MapWindowPoints(m_hWnd, NULL, (LPPOINT) &rcClient, 2) != 0 || GetLastError() == ERROR_SUCCESS))
+        {
+            pt.x = (SHORT) LOWORD(lParam);
+            pt.y = (SHORT) HIWORD(lParam);
+
+            if (PtInRect(&rcClient,
+                pt))
+            {
+                /* The user is trying to drag the tray window */
+                return HTCAPTION;
+            }
+
+            /* Depending on the position of the tray window, allow only
+            changing the border next to the monitor working area */
+            switch (Position)
+            {
+            case ABE_TOP:
+                if (pt.y > rcClient.bottom)
+                    return HTBOTTOM;
+                break;
+            case ABE_LEFT:
+                if (pt.x > rcClient.right)
+                    return HTRIGHT;
+                break;
+            case ABE_RIGHT:
+                if (pt.x < rcClient.left)
+                    return HTLEFT;
+                break;
+            case ABE_BOTTOM:
+            default:
+                if (pt.y < rcClient.top)
+                    return HTTOP;
+                break;
+            }
+        }
+        return HTBORDER;
+        return TRUE;
+    }
+
+    LRESULT OnMoving(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        POINT ptCursor;
+        PRECT pRect = (PRECT) lParam;
+
+        /* We need to ensure that an application can not accidently
+        move the tray window (using SetWindowPos). However, we still
+        need to be able to move the window in case the user wants to
+        drag the tray window to another position or in case the user
+        wants to resize the tray window. */
+        if (!Locked && GetCursorPos(&ptCursor))
+        {
+            IsDragging = TRUE;
+            DraggingPosition = GetDraggingRectFromPt(
+                ptCursor,
+                pRect,
+                &DraggingMonitor);
+        }
+        else
+        {
+            *pRect = rcTrayWnd[Position];
+
+            if (AutoHide)
+            {
+                pRect->left += AutoHideOffset.cx;
+                pRect->right += AutoHideOffset.cx;
+                pRect->top += AutoHideOffset.cy;
+                pRect->bottom += AutoHideOffset.cy;
+            }
+        }
+        return TRUE;
+    }
+
+    LRESULT OnSizing(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        PRECT pRect = (PRECT) lParam;
+
+        if (!Locked)
+        {
+            CalculateValidSize(Position, pRect);
+        }
+        else
+        {
+            *pRect = rcTrayWnd[Position];
+
+            if (AutoHide)
+            {
+                pRect->left += AutoHideOffset.cx;
+                pRect->right += AutoHideOffset.cx;
+                pRect->top += AutoHideOffset.cy;
+                pRect->bottom += AutoHideOffset.cy;
+            }
+        }
+        return TRUE;
+    }
+
+    LRESULT OnWindowPosChange(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        ChangingWinPos((LPWINDOWPOS) lParam);
+        return TRUE;
+    }
+
+    LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        RECT rcClient;
+        InvalidateRect(NULL, TRUE);
+        if (wParam == SIZE_RESTORED && lParam == 0)
+        {
+            ResizeWorkArea();
+            /* Clip the tray window on multi monitor systems so the edges can't
+            overlap into another monitor */
+            ApplyClipping(TRUE);
+
+            if (!GetClientRect(&rcClient))
+            {
+                return FALSE;
+            }
+        }
+        else
+        {
+            rcClient.left = rcClient.top = 0;
+            rcClient.right = LOWORD(lParam);
+            rcClient.bottom = HIWORD(lParam);
+        }
+
+        AlignControls(&rcClient);
+        return TRUE;
+    }
+
+    LRESULT OnEnterSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        InSizeMove = TRUE;
+        IsDragging = FALSE;
+        if (!Locked)
+        {
+            /* Remove the clipping on multi monitor systems while dragging around */
+            ApplyClipping(FALSE);
+        }
+        return TRUE;
+    }
+
+    LRESULT OnExitSizeMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        InSizeMove = FALSE;
+        if (!Locked)
+        {
+            /* Apply clipping */
+            PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0);
+        }
+        return TRUE;
+    }
+
+    LRESULT OnSysChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        switch (wParam)
+        {
+        case TEXT(' '):
+        {
+            /* The user pressed Alt+Space, this usually brings up the system menu of a window.
+            The tray window needs to handle this specially, since it normally doesn't have
+            a system menu. */
+
+            static const UINT uidDisableItem [] = {
+                SC_RESTORE,
+                SC_MOVE,
+                SC_SIZE,
+                SC_MAXIMIZE,
+                SC_MINIMIZE,
+            };
+            HMENU hSysMenu;
+            INT i;
+            UINT uId;
+
+            /* temporarily enable the system menu */
+            SetWindowStyle(m_hWnd, WS_SYSMENU, WS_SYSMENU);
+
+            hSysMenu = GetSystemMenu(m_hWnd, FALSE);
+            if (hSysMenu != NULL)
+            {
+                /* Disable all items that are not relevant */
+                for (i = 0; i != sizeof(uidDisableItem) / sizeof(uidDisableItem[0]); i++)
+                {
+                    EnableMenuItem(hSysMenu,
+                                   uidDisableItem[i],
+                                   MF_BYCOMMAND | MF_GRAYED);
+                }
+
+                EnableMenuItem(hSysMenu,
+                               SC_CLOSE,
+                               MF_BYCOMMAND |
+                               (SHRestricted(REST_NOCLOSE) ? MF_GRAYED : MF_ENABLED));
+
+                /* Display the system menu */
+                uId = TrackMenu(
+                    hSysMenu,
+                    NULL,
+                    hwndStart,
+                    Position != ABE_TOP,
+                    FALSE);
+                if (uId != 0)
+                {
+                    SendMessage(m_hWnd,
+                                WM_SYSCOMMAND,
+                                (WPARAM) uId,
+                                0);
+                }
+            }
+
+            /* revert the system menu window style */
+            SetWindowStyle(m_hWnd, WS_SYSMENU, 0);
+            break;
+        }
+
+        default:
+            bHandled = FALSE;
+        }
+        return TRUE;
+    }
+
+    LRESULT OnNcRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        /* We want the user to be able to get a context menu even on the nonclient
+        area (including the sizing border)! */
+        uMsg = WM_CONTEXTMENU;
+        wParam = (WPARAM) m_hWnd;
+
+        return OnContextMenu(uMsg, wParam, lParam, bHandled);
+    }
+
+    LRESULT OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        LRESULT Ret = FALSE;
+        POINT pt, *ppt = NULL;
+        HWND hWndExclude = NULL;
+
+        /* Check if the administrator has forbidden access to context menus */
+        if (SHRestricted(REST_NOTRAYCONTEXTMENU))
+            return FALSE;
+
+        pt.x = (SHORT) LOWORD(lParam);
+        pt.y = (SHORT) HIWORD(lParam);
+
+        if (pt.x != -1 || pt.y != -1)
+            ppt = &pt;
+        else
+            hWndExclude = hwndStart;
+
+        if ((HWND) wParam == hwndStart)
+        {
+            /* Make sure we can't track the context menu if the start
+            menu is currently being shown */
+            if (!(SendMessage(hwndStart,
+                BM_GETSTATE,
+                0,
+                0) & BST_PUSHED))
+            {
+                TrackCtxMenu(
+                    &StartMenuBtnCtxMenu,
+                    ppt,
+                    hWndExclude,
+                    Position == ABE_BOTTOM,
+                    this);
+            }
+        }
+        else
+        {
+            /* See if the context menu should be handled by the task band site */
+            if (ppt != NULL && TrayBandSite != NULL)
+            {
+                HWND hWndAtPt;
+                POINT ptClient = *ppt;
+
+                /* Convert the coordinates to client-coordinates */
+                MapWindowPoints(NULL,
+                                m_hWnd,
+                                &ptClient,
+                                1);
+
+                hWndAtPt = ChildWindowFromPoint(m_hWnd,
+                                                ptClient);
+                if (hWndAtPt != NULL &&
+                    (hWndAtPt == hwndRebar || IsChild(hwndRebar,
+                    hWndAtPt)))
+                {
+                    /* Check if the user clicked on the task switch window */
+                    ptClient = *ppt;
+                    MapWindowPoints(NULL,
+                                    hwndRebar,
+                                    &ptClient,
+                                    1);
+
+                    hWndAtPt = ChildWindowFromPointEx(hwndRebar,
+                                                      ptClient,
+                                                      CWP_SKIPINVISIBLE | CWP_SKIPDISABLED);
+                    if (hWndAtPt == hwndTaskSwitch)
+                        goto HandleTrayContextMenu;
+
+                    /* Forward the message to the task band site */
+                    TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
+                }
+                else
+                    goto HandleTrayContextMenu;
+            }
+            else
+            {
+HandleTrayContextMenu:
+                /* Tray the default tray window context menu */
+                TrackCtxMenu(
+                    &TrayWindowCtxMenu,
+                    ppt,
+                    NULL,
+                    FALSE,
+                    this);
+            }
+        }
+        return Ret;
+    }
+
+    LRESULT OnNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        LRESULT Ret = FALSE;
+        /* FIXME: We can't check with IsChild whether the hwnd is somewhere inside
+        the rebar control! But we shouldn't forward messages that the band
+        site doesn't handle, such as other controls (start button, tray window */
+
+        HRESULT hr = E_FAIL;
+
+        if (TrayBandSite)
+        {
+            hr = TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret);
+            if (SUCCEEDED(hr))
+                return Ret;
+        }
+
+        if (TrayBandSite == NULL || FAILED_UNEXPECTEDLY(hr))
+        {
+            const NMHDR *nmh = (const NMHDR *) lParam;
+
+            if (nmh->hwndFrom == hwndTrayNotify)
+            {
+                switch (nmh->code)
+                {
+                case NTNWM_REALIGN:
+                    /* Cause all controls to be aligned */
+                    PostMessage(m_hWnd, WM_SIZE, SIZE_RESTORED, 0);
+                    break;
+                }
+            }
+        }
+        return Ret;
+    }
+
+    LRESULT OnNcLButtonDblClick(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        /* We "handle" this message so users can't cause a weird maximize/restore
+        window animation when double-clicking the tray window! */
+
+        /* We should forward mouse messages to child windows here.
+        Right now, this is only clock double-click */
+        RECT rcClock;
+        if (TrayNotify_GetClockRect(&rcClock))
+        {
+            POINT ptClick;
+            ptClick.x = MAKEPOINTS(lParam).x;
+            ptClick.y = MAKEPOINTS(lParam).y;
+            if (PtInRect(&rcClock, ptClick))
+                LaunchCPanel(NULL, TEXT("timedate.cpl"));
+        }
+        return TRUE;
+    }
+
+    LRESULT OnAppTrayDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        DestroyWindow();
+        return TRUE;
+    }
+
+    LRESULT OnOpenStartMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        HWND hwndStartMenu;
+        HRESULT hr = IUnknown_GetWindow((IUnknown*) StartMenuPopup, &hwndStartMenu);
+        if (FAILED_UNEXPECTEDLY(hr))
+            return FALSE;
+
+        if (IsWindowVisible(hwndStartMenu))
+        {
+            StartMenuPopup->OnSelect(MPOS_CANCELLEVEL);
+        }
+        else
+        {
+            SendMessage(m_hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDC_STARTBTN), reinterpret_cast<LPARAM>(hwndStart));
+        }
+
+        return TRUE;
+    }
+
+    LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        LRESULT Ret = FALSE;
+
+        if ((HWND) lParam == hwndStart)
+        {
+            PopupStartMenu();
+            return FALSE;
+        }
+
+        if (TrayBandSite == NULL || FAILED_UNEXPECTEDLY(TrayBandSite->ProcessMessage(m_hWnd, uMsg, wParam, lParam, &Ret)))
+        {
+            switch (LOWORD(wParam))
+            {
+                /* FIXME: Handle these commands as well */
+            case IDM_TASKBARANDSTARTMENU:
+
+                DisplayProperties();
+                break;
+
+            case IDM_SEARCH:
+                break;
+
+            case IDM_HELPANDSUPPORT:
+            {
+                /* TODO: Implement properly */
+
+                LPCWSTR strSite = L"https://www.reactos.org/";
+
+                /* TODO: Make localizable */
+                LPCWSTR strCaption = L"Sorry";
+                LPCWSTR strMessage = L"ReactOS could not browse to '%s' (error %d). Please make sure there is a web browser installed.";
+                WCHAR tmpMessage[512];
+
+                /* TODO: Read from the registry */
+                LPCWSTR strVerb = NULL; /* default */
+                LPCWSTR strPath = strSite;
+                LPCWSTR strParams = NULL;
+
+                /* The return value is defined as HINSTANCE for backwards compatibility only, the cast is needed */
+                int result = (int) ShellExecuteW(m_hWnd, strVerb, strPath, strParams, NULL, SW_SHOWNORMAL);
+                if (result <= 32)
+                {
+                    StringCchPrintfW(tmpMessage, 512, strMessage, strSite, result);
+                    MessageBoxExW(m_hWnd, tmpMessage, strCaption, MB_OK, 0);
+                }
+                break;
+            }
+
+            case IDM_RUN:
+            {
+                DisplayRunFileDlg();
+                break;
+            }
+
+                /* FIXME: Handle these commands as well */
+            case IDM_SYNCHRONIZE:
+            case IDM_LOGOFF:
+            case IDM_DISCONNECT:
+            case IDM_UNDOCKCOMPUTER:
+                break;
+
+            case IDM_SHUTDOWN:
+            {
+                HINSTANCE hShell32;
+                EXITWINDLG ExitWinDlg;
+
+                hShell32 = GetModuleHandle(TEXT("SHELL32.DLL"));
+                ExitWinDlg = (EXITWINDLG) GetProcAddress(hShell32, (LPCSTR) 60);
+
+                ExitWinDlg(m_hWnd);
+                break;
+            }
+            }
+        }
+        return Ret;
+    }
+
+    LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (AutoHide)
+        {
+            SetTimer(TIMER_ID_MOUSETRACK, MOUSETRACK_INTERVAL, NULL);
+        }
+
+        return TRUE;
+    }
+
+    LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+    {
+        if (wParam == TIMER_ID_MOUSETRACK)
+        {
+            ProcessMouseTracking();
+        }
+        else if (wParam == TIMER_ID_AUTOHIDE)
+        {
+            ProcessAutoHide();
+        }
+
+        bHandled = FALSE;
+        return TRUE;
+    }
+
+    LRESULT OnRebarAutoSize(INT code, LPNMHDR nmhdr, BOOL& bHandled)
+    {
+#if 0
+        LPNMRBAUTOSIZE as = (LPNMRBAUTOSIZE) nmhdr;
+
+        if (!as->fChanged)
+            return 0;
+
+        RECT rc;
+        ::GetWindowRect(m_hWnd, &rc);
+
+        SIZE szWindow = { 
+            rc.right - rc.left, 
+            rc.bottom - rc.top };
+        SIZE szTarget = { 
+            as->rcTarget.right - as->rcTarget.left, 
+            as->rcTarget.bottom - as->rcTarget.top };
+        SIZE szActual = { 
+            as->rcActual.right - as->rcActual.left, 
+            as->rcActual.bottom - as->rcActual.top };
+
+        SIZE borders = {
+            szWindow.cx - szTarget.cx,
+            szWindow.cy - szTarget.cx,
+        };
+
+        switch (Position)
+        {
+        case ABE_LEFT:
+            szWindow.cx = szActual.cx + borders.cx;
+            break;
+        case ABE_TOP:
+            szWindow.cy = szActual.cy + borders.cy;
+            break;
+        case ABE_RIGHT:
+            szWindow.cx = szActual.cx + borders.cx;
+            rc.left = rc.right - szWindow.cy;
+            break;
+        case ABE_BOTTOM:
+            szWindow.cy = szActual.cy + borders.cy;
+            rc.top = rc.bottom - szWindow.cy;
+            break;
+        }
+
+        SetWindowPos(NULL, rc.left, rc.top, szWindow.cx, szWindow.cy, SWP_NOACTIVATE | SWP_NOZORDER);
+#else
+        bHandled = FALSE;
+#endif
+        return 0;
+    }
+
+    DECLARE_WND_CLASS_EX(szTrayWndClass, CS_DBLCLKS, COLOR_3DFACE)
+
+    BEGIN_MSG_MAP(ITrayWindowImpl)
+        if (StartMenuBand != NULL)
+        {
+            MSG Msg;
+            LRESULT lRet;
+
+            Msg.hwnd = m_hWnd;
+            Msg.message = uMsg;
+            Msg.wParam = wParam;
+            Msg.lParam = lParam;
+
+            if (StartMenuBand->TranslateMenuMessage(
+                &Msg,
+                &lRet) == S_OK)
+            {
+                return lRet;
+            }
+
+            wParam = Msg.wParam;
+            lParam = Msg.lParam;
+        }
+        MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged)
+            NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnRebarAutoSize) // Doesn't quite work ;P
+            MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
+            MESSAGE_HANDLER(WM_SIZE, OnSize)
+            MESSAGE_HANDLER(WM_CREATE, OnCreate)
+            /*MESSAGE_HANDLER(WM_DESTROY, OnDestroy)*/
+            MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
+            MESSAGE_HANDLER(WM_COMMAND, OnCommand)
+            MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
+            MESSAGE_HANDLER(WM_CONTEXTMENU, OnContextMenu)
+            MESSAGE_HANDLER(WM_TIMER, OnTimer)
+            MESSAGE_HANDLER(WM_DISPLAYCHANGE, OnDisplayChange)
+            MESSAGE_HANDLER(WM_COPYDATA, OnCopyData)
+            MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
+            MESSAGE_HANDLER(WM_CTLCOLORBTN, OnCtlColorBtn)
+            MESSAGE_HANDLER(WM_MOVING, OnMoving)
+            MESSAGE_HANDLER(WM_SIZING, OnSizing)
+            MESSAGE_HANDLER(WM_WINDOWPOSCHANGING, OnWindowPosChange)
+            MESSAGE_HANDLER(WM_ENTERSIZEMOVE, OnEnterSizeMove)
+            MESSAGE_HANDLER(WM_EXITSIZEMOVE, OnExitSizeMove)
+            MESSAGE_HANDLER(WM_SYSCHAR, OnSysChar)
+            MESSAGE_HANDLER(WM_NCRBUTTONUP, OnNcRButtonUp)
+            MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDblClick)
+            MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
+            MESSAGE_HANDLER(WM_NCMOUSEMOVE, OnMouseMove)
+            MESSAGE_HANDLER(WM_APP_TRAYDESTROY, OnAppTrayDestroy)
+            MESSAGE_HANDLER(TWM_OPENSTARTMENU, OnOpenStartMenu)
+    END_MSG_MAP()
+
+    /*
+     * Tray Window Context Menu
+     */
+
+    static HMENU CreateTrayWindowContextMenu(IN HWND hWndOwner,
+                                             IN PVOID *ppcmContext,
+                                             IN PVOID Context OPTIONAL)
+    {
+        ITrayWindowImpl *This = (ITrayWindowImpl *) Context;
+        IContextMenu *pcm = NULL;
+        HMENU hPopup;
+
+        hPopup = LoadPopupMenu(hExplorerInstance,
+                               MAKEINTRESOURCE(IDM_TRAYWND));
+
+        if (hPopup != NULL)
+        {
+            if (SHRestricted(REST_CLASSICSHELL) != 0)
+            {
+                DeleteMenu(hPopup,
+                           ID_LOCKTASKBAR,
+                           MF_BYCOMMAND);
+            }
+
+            CheckMenuItem(hPopup,
+                          ID_LOCKTASKBAR,
+                          MF_BYCOMMAND | (This->Locked ? MF_CHECKED : MF_UNCHECKED));
+
+            if (This->TrayBandSite != NULL)
+            {
+                if (SUCCEEDED(This->TrayBandSite->AddContextMenus(
+                    hPopup,
+                    0,
+                    ID_SHELL_CMD_FIRST,
+                    ID_SHELL_CMD_LAST,
+                    CMF_NORMAL,
+                    &pcm)))
+                {
+                    TRACE("ITrayBandSite::AddContextMenus succeeded!\n");
+                    *(IContextMenu **) ppcmContext = pcm;
+                }
+            }
+        }
+
+        return hPopup;
+    }
+
+    static VOID OnTrayWindowContextMenuCommand(IN HWND hWndOwner,
+                                               IN UINT uiCmdId,
+                                               IN PVOID pcmContext OPTIONAL,
+                                               IN PVOID Context OPTIONAL)
+    {
+        ITrayWindowImpl *This = (ITrayWindowImpl *) Context;
+        IContextMenu *pcm = (IContextMenu *) pcmContext;
+
+        if (uiCmdId != 0)
+        {
+            if (uiCmdId >= ID_SHELL_CMD_FIRST && uiCmdId <= ID_SHELL_CMD_LAST)
+            {
+                CMINVOKECOMMANDINFO cmici = { 0 };
+
+                if (pcm != NULL)
+                {
+                    /* 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;
+
+                    pcm->InvokeCommand(
+                        &cmici);
+                }
+            }
+            else
+            {
+                This->ExecContextMenuCmd(uiCmdId);
+            }
+        }
+
+        if (pcm != NULL)
+            pcm->Release();
+    }
+
+    /*****************************************************************************/
+
+    VOID TrayProcessMessages()
+    {
+        MSG Msg;
+
+        /* FIXME: We should keep a reference here... */
+
+        while (PeekMessage(&Msg,
+            NULL,
+            0,
+            0,
+            PM_REMOVE))
+        {
+            if (Msg.message == WM_QUIT)
+                break;
+
+            if (StartMenuBand == NULL ||
+                StartMenuBand->IsMenuMessage(
+                &Msg) != S_OK)
+            {
+                TranslateMessage(&Msg);
+                DispatchMessage(&Msg);
+            }
+        }
+    }
+
+    VOID TrayMessageLoop()
+    {
+        MSG Msg;
+        BOOL Ret;
+
+        /* FIXME: We should keep a reference here... */
+
+        while (1)
+        {
+            Ret = GetMessage(&Msg,
+                             NULL,
+                             0,
+                             0);
+
+            if (!Ret || Ret == -1)
+                break;
+
+            if (Msg.message == WM_HOTKEY)
+            {
+                switch (Msg.wParam)
+                {
+                case IDHK_RUN: /* Win+R */
+                    DisplayRunFileDlg();
+                    break;
+                }
+            }
+
+            if (StartMenuBand == NULL ||
+                StartMenuBand->IsMenuMessage(&Msg) != S_OK)
+            {
+                TranslateMessage(&Msg);
+                DispatchMessage(&Msg);
+            }
+        }
+    }
+
+    /*
+     * IShellDesktopTray
+     *
+     * NOTE: this is a very windows-specific COM interface used by SHCreateDesktop()!
+     *       These are the calls I observed, it may be wrong/incomplete/buggy!!!
+     *       The reason we implement it is because we have to use SHCreateDesktop() so
+     *       that the shell provides the desktop window and all the features that come
+     *       with it (especially positioning of desktop icons)
+     */
+
+    virtual ULONG STDMETHODCALLTYPE GetState()
+    {
+        /* FIXME: Return ABS_ flags? */
+        TRACE("IShellDesktopTray::GetState() unimplemented!\n");
+        return 0;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE GetTrayWindow(OUT HWND *phWndTray)
+    {
+        TRACE("IShellDesktopTray::GetTrayWindow(0x%p)\n", phWndTray);
+        *phWndTray = m_hWnd;
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE RegisterDesktopWindow(IN HWND hWndDesktop)
+    {
+        TRACE("IShellDesktopTray::RegisterDesktopWindow(0x%p)\n", hWndDesktop);
+
+        this->hWndDesktop = hWndDesktop;
+        return S_OK;
+    }
+
+    virtual HRESULT STDMETHODCALLTYPE Unknown(IN DWORD dwUnknown1, IN DWORD dwUnknown2)
+    {
+        TRACE("IShellDesktopTray::Unknown(%u,%u) unimplemented!\n", dwUnknown1, dwUnknown2);
+        return S_OK;
+    }
+
+    virtual HRESULT RaiseStartButton()
+    {
+        SendMessageW(hwndStart, BM_SETSTATE, FALSE, 0);
+        return S_OK;
+    }
+
+    void _Init()
+    {
+        Position = (DWORD) -1;
+    }
+
+    DECLARE_NOT_AGGREGATABLE(ITrayWindowImpl)
+
+    DECLARE_PROTECT_FINAL_CONSTRUCT()
+    BEGIN_COM_MAP(ITrayWindowImpl)
+        /*COM_INTERFACE_ENTRY_IID(IID_ITrayWindow, ITrayWindow)*/
+        COM_INTERFACE_ENTRY_IID(IID_IShellDesktopTray, IShellDesktopTray)
+    END_COM_MAP()
+};
+
+const TRAYWINDOW_CTXMENU TrayWindowCtxMenu = {
+    ITrayWindowImpl::CreateTrayWindowContextMenu,
+    ITrayWindowImpl::OnTrayWindowContextMenuCommand
+};
+
+ITrayWindowImpl * g_TrayWindow;
+
+HRESULT
+Tray_OnStartMenuDismissed()
+{
+    return g_TrayWindow->RaiseStartButton();
+}
+
+
+HRESULT CreateTrayWindow(ITrayWindow ** ppTray)
+{
+    CComPtr<ITrayWindowImpl> Tray = new CComObject<ITrayWindowImpl>();
+    if (Tray == NULL)
+        return E_OUTOFMEMORY;
+
+    Tray->_Init();
+    Tray->Open();
+    g_TrayWindow = Tray;
+
+    *ppTray = (ITrayWindow *) Tray;
+
+    return S_OK;
+}
+
+VOID TrayProcessMessages(ITrayWindow *)
+{
+    g_TrayWindow->TrayProcessMessages();
+}
+
+VOID TrayMessageLoop(ITrayWindow *)
+{
+    g_TrayWindow->TrayMessageLoop();
+}
diff --git a/base/shell/explorer-new/util.cpp b/base/shell/explorer-new/util.cpp
new file mode 100644 (file)
index 0000000..6bdea90
--- /dev/null
@@ -0,0 +1,323 @@
+#include "precomp.h"
+#include <winver.h>
+
+typedef struct _LANGCODEPAGE
+{
+    WORD wLanguage;
+    WORD wCodePage;
+} LANGCODEPAGE, *PLANGCODEPAGE;
+
+HRESULT
+IsSameObject(IN IUnknown *punk1, IN IUnknown *punk2)
+{
+    HRESULT hRet;
+
+    hRet = punk1->QueryInterface(IID_PPV_ARG(IUnknown, &punk1));
+
+    if (!SUCCEEDED(hRet))
+        return hRet;
+
+    hRet = punk2->QueryInterface(IID_PPV_ARG(IUnknown, &punk2));
+
+    punk1->Release();
+
+    if (!SUCCEEDED(hRet))
+        return hRet;
+
+    punk2->Release();
+
+    /* We're dealing with the same object if the IUnknown pointers are equal */
+    return (punk1 == punk2) ? S_OK : S_FALSE;
+}
+
+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(WCHAR)) - 1;
+    if (RegQueryValueEx(hkExplorer,
+        TEXT("Logon User Name"),
+        0,
+        &dwType,
+        (LPBYTE) szBuffer,
+        &dwSize) == ERROR_SUCCESS &&
+        (dwSize / sizeof(WCHAR)) > 1 &&
+        szBuffer[0] != _T('\0'))
+    {
+        szBuffer[dwSize / sizeof(WCHAR)] = _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;
+    WCHAR szBuf[128];
+    WCHAR 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)
+{
+    WCHAR szBuffer[MAX_PATH];
+    HKEY hkSubKey;
+    DWORD dwType, dwSize;
+    BOOL Ret = FALSE;
+
+    StringCbCopy(szBuffer, sizeof(szBuffer),
+                 TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"));
+    if (FAILED_UNEXPECTEDLY(StringCbCat(szBuffer, sizeof(szBuffer),
+        _T("\\"))))
+        return FALSE;
+    if (FAILED_UNEXPECTEDLY(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 = *((PCHAR) szBuffer) != 0;
+        }
+
+        RegCloseKey(hkSubKey);
+    }
+    return Ret;
+}
+
+BOOL
+GetVersionInfoString(IN WCHAR *szFileName,
+IN WCHAR *szVersionInfo,
+OUT WCHAR *szBuffer,
+IN UINT cbBufLen)
+{
+    LPVOID lpData = NULL;
+    WCHAR szSubBlock[128];
+    WCHAR *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;
+}
index 602dd9b..5e46e71 100644 (file)
@@ -634,7 +634,7 @@ HRESULT STDMETHODCALLTYPE CBandSiteBase::SetDeskBarSite(IUnknown *pUnk)
     if (FAILED_UNEXPECTEDLY(hRet))
         return E_FAIL;
 
     if (FAILED_UNEXPECTEDLY(hRet))
         return E_FAIL;
 
-    style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_VARHEIGHT |
+    style = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_VARHEIGHT | RBS_AUTOSIZE |
         RBS_BANDBORDERS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
 
     fRebarWindow = CreateWindowExW(WS_EX_TOOLWINDOW,
         RBS_BANDBORDERS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
 
     fRebarWindow = CreateWindowExW(WS_EX_TOOLWINDOW,