    /*
     * This file is part of the LibreOffice project.
     *
     * This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     *
     * This file incorporates work covered by the following license notice:
     *
     *   Licensed to the Apache Software Foundation (ASF) under one or more
     *   contributor license agreements. See the NOTICE file distributed
     *   with this work for additional information regarding copyright
     *   ownership. The ASF licenses this file to you under the Apache
     *   License, Version 2.0 (the "License"); you may not use this file
     *   except in compliance with the License. You may obtain a copy of
     *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
     */

    #if !defined WINVER
    #define WINVER 0x0400
    #endif

    #include <sal/macros.h>
    #include <sal/log.hxx>

    #include <unotools/moduleoptions.hxx>
    #include <unotools/dynamicmenuoptions.hxx>

    #undef WB_LEFT
    #undef WB_RIGHT

    #include "shutdownicon.hxx"
    #include <sfx2/sfxresid.hxx>
    #include <sfx2/strings.hrc>
    #include <shlobj.h>
    #include <objidl.h>
    #include <osl/thread.h>
    #include <systools/win32/qswin32.h>
    #include <comphelper/sequenceashashmap.hxx>
    #include <o3tl/char16_t2wchar_t.hxx>

    #include <set>

    using namespace ::osl;

    using ::com::sun::star::uno::Sequence;
    using ::com::sun::star::beans::PropertyValue;

    #define EXECUTER_WINDOWCLASS    L"SO Executer Class"
    #define EXECUTER_WINDOWNAME     L"SO Executer Window"

    #define ID_QUICKSTART               1
    #define IDM_EXIT                    2
    #define IDM_OPEN                    3
    #define IDM_WRITER                  4
    #define IDM_CALC                    5
    #define IDM_IMPRESS                 6
    #define IDM_DRAW                    7
    #define IDM_BASE                    8
    #define IDM_TEMPLATE                9
    #define IDM_MATH                    12
    #define IDM_INSTALL                 10
    #define IDM_STARTCENTER             14

    #define ICON_LO_DEFAULT                 1
    #define ICON_TEXT_DOCUMENT              2
    #define ICON_SPREADSHEET_DOCUMENT       4
    #define ICON_DRAWING_DOCUMENT           6
    #define ICON_PRESENTATION_DOCUMENT      8
    #define ICON_TEMPLATE                   11
    #define ICON_DATABASE_DOCUMENT          12
    #define ICON_MATH_DOCUMENT              13
    #define ICON_OPEN                       5   // See index of open folder icon in shell32.dll

    #define SFX_TASKBAR_NOTIFICATION    WM_USER+1

    static HWND  aListenerWindow = nullptr;
    static HWND  aExecuterWindow = nullptr;
    static HMENU popupMenu = nullptr;

    static void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis);
    static void OnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis);

    typedef struct tagMYITEM
    {
        OUString text;
        OUString module;
        UINT iconId;
    } MYITEM;

    static void addMenuItem( HMENU hMenu, UINT id, UINT iconId, const OUString& text, int& pos, bool bOwnerdraw, const OUString& module )
    {
        MENUITEMINFOW mi;
        memset( &mi, 0, sizeof( mi ) );

        mi.cbSize = sizeof( mi );
        if( id == static_cast<UINT>( -1 ) )
        {
            mi.fMask=MIIM_TYPE;
            mi.fType=MFT_SEPARATOR;
        }
        else
        {
            if( bOwnerdraw )
            {
                mi.fMask=MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
                mi.fType=MFT_OWNERDRAW;
                mi.fState=MFS_ENABLED;
                mi.wID = id;

                MYITEM *pMyItem = new MYITEM;
                pMyItem->text = text;
                pMyItem->iconId = iconId;
                pMyItem->module = module;
                mi.dwItemData = reinterpret_cast<DWORD_PTR>(pMyItem);
            }
            else
            {
                mi.fMask=MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
                mi.fType=MFT_STRING;
                mi.fState=MFS_ENABLED;
                mi.wID = id;
                mi.dwTypeData = o3tl::toW(
                    const_cast<sal_Unicode *>(text.getStr()));
                mi.cch = text.getLength();
            }

            if ( IDM_TEMPLATE == id )
                mi.fState |= MFS_DEFAULT;
        }

        InsertMenuItemW( hMenu, pos++, TRUE, &mi );
    }

    static HMENU createSystrayMenu( )
    {
        SvtModuleOptions    aModuleOptions;

        HMENU hMenu = CreatePopupMenu();
        int pos=0;

        ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
        OSL_ENSURE( pShutdownIcon, "ShutdownIcon instance empty!");

        if( !pShutdownIcon )
            return nullptr;

        // collect the URLs of the entries in the File/New menu
        ::std::set< OUString > aFileNewAppsAvailable;
        SvtDynamicMenuOptions aOpt;
        Sequence < Sequence < PropertyValue > > aNewMenu = aOpt.GetMenu( EDynamicMenuType::NewMenu );
        const OUString sURLKey( "URL"  );

        for ( auto const & newMenuProp : aNewMenu )
        {
            ::comphelper::SequenceAsHashMap aEntryItems( newMenuProp );
            OUString sURL( aEntryItems.getUnpackedValueOrDefault( sURLKey, OUString() ) );
            if ( sURL.getLength() )
                aFileNewAppsAvailable.insert( sURL );
        }

        // describe the menu entries for launching the applications
        struct MenuEntryDescriptor
        {
            SvtModuleOptions::EModule   eModuleIdentifier;
            UINT                        nMenuItemID;
            UINT                        nMenuIconID;
            const char*                 pAsciiURLDescription;
        }   aMenuItems[] =
        {
            { SvtModuleOptions::EModule::WRITER,    IDM_WRITER, ICON_TEXT_DOCUMENT,         WRITER_URL },
            { SvtModuleOptions::EModule::CALC,      IDM_CALC,   ICON_SPREADSHEET_DOCUMENT,  CALC_URL },
            { SvtModuleOptions::EModule::IMPRESS,   IDM_IMPRESS,ICON_PRESENTATION_DOCUMENT, IMPRESS_WIZARD_URL },
            { SvtModuleOptions::EModule::DRAW,      IDM_DRAW,   ICON_DRAWING_DOCUMENT,      DRAW_URL },
            { SvtModuleOptions::EModule::DATABASE,  IDM_BASE,   ICON_DATABASE_DOCUMENT,     BASE_URL },
            { SvtModuleOptions::EModule::MATH,      IDM_MATH,   ICON_MATH_DOCUMENT,         MATH_URL },
        };

        // insert the menu entries for launching the applications
        for ( size_t i = 0; i < SAL_N_ELEMENTS(aMenuItems); ++i )
        {
            if ( !aModuleOptions.IsModuleInstalled( aMenuItems[i].eModuleIdentifier ) )
                // the complete application is not even installed
                continue;

            OUString sURL( OUString::createFromAscii( aMenuItems[i].pAsciiURLDescription ) );

            if ( aFileNewAppsAvailable.find( sURL ) == aFileNewAppsAvailable.end() )
                // the application is installed, but the entry has been configured to *not* appear in the File/New
                // menu => also let not appear it in the quickstarter
                continue;

            addMenuItem( hMenu, aMenuItems[i].nMenuItemID, aMenuItems[i].nMenuIconID,
                ShutdownIcon::GetUrlDescription( sURL ), pos, true, "" );
        }

        // insert the remaining menu entries
        addMenuItem( hMenu, IDM_TEMPLATE, ICON_TEMPLATE,
            SfxResId( STR_QUICKSTART_FROMTEMPLATE ), pos, true, "");
        addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
        addMenuItem( hMenu, IDM_OPEN,   ICON_OPEN, SfxResId(STR_QUICKSTART_FILEOPEN), pos, true, "SHELL32");
        addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
        addMenuItem( hMenu, IDM_INSTALL,0, SfxResId(STR_QUICKSTART_PRELAUNCH), pos, false, "" );
        addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
        addMenuItem( hMenu, IDM_EXIT,   0, SfxResId(STR_QUICKSTART_EXIT), pos, false, "" );

        // indicate status of autostart folder
        CheckMenuItem( hMenu, IDM_INSTALL, MF_BYCOMMAND | (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );

        return hMenu;
    }

    static void deleteSystrayMenu( HMENU hMenu )
    {
        if( !hMenu || !IsMenu( hMenu ))
            return;

        MENUITEMINFOW mi;
        int pos=0;
        memset( &mi, 0, sizeof( mi ) );
        mi.cbSize = sizeof( mi );
        mi.fMask = MIIM_DATA;

        while( GetMenuItemInfoW( hMenu, pos++, true, &mi ) )
        {
            MYITEM *pMyItem = reinterpret_cast<MYITEM*>(mi.dwItemData);
            if( pMyItem )
            {
                pMyItem->text.clear();
                delete pMyItem;
            }
            mi.fMask = MIIM_DATA;
        }
    }

    static void addTaskbarIcon( HWND hWnd )
    {
        OUString strTip = SfxResId(STR_QUICKSTART_TIP);

        // add taskbar icon
        NOTIFYICONDATAW nid;
        nid.hIcon = static_cast<HICON>(LoadImageW( GetModuleHandleW( nullptr ), MAKEINTRESOURCEW( ICON_LO_DEFAULT ),
            IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
            LR_DEFAULTCOLOR | LR_SHARED ));

        wcsncpy( nid.szTip, o3tl::toW(strTip.getStr()), 64 );

        nid.cbSize              = sizeof(nid);
        nid.hWnd                = hWnd;
        nid.uID                 = ID_QUICKSTART;
        nid.uCallbackMessage    = SFX_TASKBAR_NOTIFICATION;
        nid.uFlags              = NIF_MESSAGE|NIF_TIP|NIF_ICON;

        Shell_NotifyIconW(NIM_ADD, &nid);
    }

    LRESULT CALLBACK listenerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        static UINT s_uTaskbarRestart = 0;
        static UINT s_uMsgKillTray = 0;

        switch (uMsg)
        {
            case WM_NCCREATE:
                return TRUE;
            case WM_CREATE:
                {
                    // request notification when taskbar is recreated
                    // we then have to add our icon again
                    s_uTaskbarRestart = RegisterWindowMessageW(L"TaskbarCreated");
                    s_uMsgKillTray = RegisterWindowMessageW( SHUTDOWN_QUICKSTART_MESSAGE );

                    // create the menu
                    if( !popupMenu )
                        if( (popupMenu = createSystrayMenu( )) == nullptr )
                            return -1;

                    // and the icon
                    addTaskbarIcon( hWnd );

                    // disable shutdown
                    ShutdownIcon::getInstance()->SetVeto( true );
                    ShutdownIcon::addTerminateListener();
                }
                return 0;

            case WM_MEASUREITEM:
                OnMeasureItem(hWnd, reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam));
                return TRUE;

            case WM_DRAWITEM:
                OnDrawItem(hWnd, reinterpret_cast<LPDRAWITEMSTRUCT>(lParam));
                return TRUE;

            case SFX_TASKBAR_NOTIFICATION:
                switch( lParam )
                {
                    case WM_LBUTTONDOWN:
                    {
                        BOOL const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_STARTCENTER, reinterpret_cast<LPARAM>(hWnd));
                        SAL_WARN_IF(0 == ret, "sfx.appl", "ERROR: PostMessage() failed!");
                        break;
                    }

                    case WM_RBUTTONDOWN:
                    {
                        POINT pt;
                        GetCursorPos(&pt);
                        SetForegroundWindow( hWnd );

                        // update status before showing menu, could have been changed from option page
                        CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );

                        EnableMenuItem( popupMenu, IDM_EXIT, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
                        EnableMenuItem( popupMenu, IDM_OPEN, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
                        EnableMenuItem( popupMenu, IDM_TEMPLATE, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
                        int m = TrackPopupMenuEx( popupMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON,
                                                  pt.x, pt.y, hWnd, nullptr );
                        BOOL const ret = PostMessageW( hWnd, 0, 0, 0 );
                        SAL_WARN_IF(0 == ret, "sfx.appl", "ERROR: PostMessage() failed!");
                        switch( m )
                        {
                            case IDM_OPEN:
                            case IDM_WRITER:
                            case IDM_CALC:
                            case IDM_IMPRESS:
                            case IDM_DRAW:
                            case IDM_TEMPLATE:
                            case IDM_BASE:
                            case IDM_MATH:
                                break;
                            case IDM_INSTALL:
                                CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
                                break;
                            case IDM_EXIT:
                                // delete taskbar icon
                                NOTIFYICONDATAW nid;
                                nid.cbSize=sizeof(nid);
                                nid.hWnd = hWnd;
                                nid.uID = ID_QUICKSTART;
                                Shell_NotifyIconW(NIM_DELETE, &nid);
                                break;
                        }

                        BOOL const ret2 = PostMessageW(aExecuterWindow, WM_COMMAND, m, reinterpret_cast<LPARAM>(hWnd));
                        SAL_WARN_IF(0 == ret2, "sfx.appl", "ERROR: PostMessage() failed!");
                    }
                    break;
                }
                break;
            case WM_DESTROY:
                deleteSystrayMenu( popupMenu );
                // We don't need the Systray Thread anymore
                PostQuitMessage( 0 );
                return DefWindowProcW(hWnd, uMsg, wParam, lParam);
            default:
                if( uMsg == s_uTaskbarRestart )
                {
                    // re-create taskbar icon
                    addTaskbarIcon( hWnd );
                }
                else if ( uMsg == s_uMsgKillTray )
                {
                    // delete taskbar icon
                    NOTIFYICONDATAW nid;
                    nid.cbSize=sizeof(nid);
                    nid.hWnd = hWnd;
                    nid.uID = ID_QUICKSTART;
                    Shell_NotifyIconW(NIM_DELETE, &nid);

                    BOOL const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_EXIT, reinterpret_cast<LPARAM>(hWnd));
                    SAL_WARN_IF(0 == ret, "sfx.appl", "ERROR: PostMessage() failed!");
                }
                else
                    return DefWindowProcW(hWnd, uMsg, wParam, lParam);
        }
        return 0;
    }

    LRESULT CALLBACK executerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (uMsg)
        {
            case WM_NCCREATE:
                return TRUE;
            case WM_CREATE:
                return 0;

            case WM_COMMAND:
                switch( LOWORD(wParam) )
                {
                    case IDM_OPEN:
                        if ( !ShutdownIcon::bModalMode )
                            ShutdownIcon::FileOpen();
                    break;
                    case IDM_WRITER:
                        ShutdownIcon::OpenURL( WRITER_URL, "_default" );
                    break;
                    case IDM_CALC:
                        ShutdownIcon::OpenURL( CALC_URL, "_default" );
                    break;
                    case IDM_IMPRESS:
                        ShutdownIcon::OpenURL( IMPRESS_WIZARD_URL, "_default" );
                    break;
                    case IDM_DRAW:
                        ShutdownIcon::OpenURL( DRAW_URL, "_default" );
                    break;
                    case IDM_BASE:
                        ShutdownIcon::OpenURL( BASE_URL, "_default" );
                    break;
                    case IDM_MATH:
                        ShutdownIcon::OpenURL( MATH_URL, "_default" );
                    break;
                    case IDM_STARTCENTER:
                        ShutdownIcon::OpenURL( STARTMODULE_URL, "_default" );
                    break;
                    case IDM_TEMPLATE:
                        if ( !ShutdownIcon::bModalMode )
                            ShutdownIcon::FromTemplate();
                    break;
                    case IDM_INSTALL:
                        ShutdownIcon::SetAutostart( !ShutdownIcon::GetAutostart() );
                        break;
                    case IDM_EXIT:
                        // remove listener and
                        //  terminate office if running in background
                        if ( !ShutdownIcon::bModalMode )
                            ShutdownIcon::terminateDesktop();
                        break;
                }
                break;
            case WM_DESTROY:
            default:
                return DefWindowProcW(hWnd, uMsg, wParam, lParam);
        }
        return 0;
    }

    DWORD WINAPI SystrayThread( LPVOID /*lpParam*/ )
    {
        osl_setThreadName("SystrayThread");

        aListenerWindow = CreateWindowExW(0,
            QUICKSTART_CLASSNAME,        // registered class name
            QUICKSTART_WINDOWNAME,       // window name
            0,                           // window style
            CW_USEDEFAULT,               // horizontal position of window
            CW_USEDEFAULT,               // vertical position of window
            CW_USEDEFAULT,               // window width
            CW_USEDEFAULT,               // window height
            nullptr,                     // handle to parent or owner window
            nullptr,                     // menu handle or child identifier
            GetModuleHandleW( nullptr ), // handle to application instance
            nullptr                      // window-creation data
            );

        MSG msg;

        while ( GetMessageW( &msg, nullptr, 0, 0 ) )
        {
            TranslateMessage( &msg );
            DispatchMessageW( &msg );
        }

        return msg.wParam; // Exit code of WM_QUIT
    }

    void win32_init_sys_tray()
    {
        if ( ShutdownIcon::IsQuickstarterInstalled() )
        {
            WNDCLASSEXW listenerClass;
            listenerClass.cbSize        = sizeof(listenerClass);
            listenerClass.style         = 0;
            listenerClass.lpfnWndProc   = listenerWndProc;
            listenerClass.cbClsExtra    = 0;
            listenerClass.cbWndExtra    = 0;
            listenerClass.hInstance     = GetModuleHandleW( nullptr );
            listenerClass.hIcon         = nullptr;
            listenerClass.hCursor       = nullptr;
            listenerClass.hbrBackground = nullptr;
            listenerClass.lpszMenuName  = nullptr;
            listenerClass.lpszClassName = QUICKSTART_CLASSNAME;
            listenerClass.hIconSm       = nullptr;

            RegisterClassExW(&listenerClass);

            WNDCLASSEXW executerClass;
            executerClass.cbSize        = sizeof(executerClass);
            executerClass.style         = 0;
            executerClass.lpfnWndProc   = executerWndProc;
            executerClass.cbClsExtra    = 0;
            executerClass.cbWndExtra    = 0;
            executerClass.hInstance     = GetModuleHandleW( nullptr );
            executerClass.hIcon         = nullptr;
            executerClass.hCursor       = nullptr;
            executerClass.hbrBackground = nullptr;
            executerClass.lpszMenuName  = nullptr;
            executerClass.lpszClassName = EXECUTER_WINDOWCLASS;
            executerClass.hIconSm       = nullptr;

            RegisterClassExW( &executerClass );

            aExecuterWindow = CreateWindowExW(0,
                EXECUTER_WINDOWCLASS,        // registered class name
                EXECUTER_WINDOWNAME,         // window name
                0,                           // window style
                CW_USEDEFAULT,               // horizontal position of window
                CW_USEDEFAULT,               // vertical position of window
                CW_USEDEFAULT,               // window width
                CW_USEDEFAULT,               // window height
                nullptr,                     // handle to parent or owner window
                nullptr,                     // menu handle or child identifier
                GetModuleHandleW( nullptr ), // handle to application instance
                nullptr                      // window-creation data
                );

            DWORD   dwThreadId;
            CloseHandle(CreateThread(nullptr, 0, SystrayThread, nullptr, 0, &dwThreadId));
        }
    }

    void win32_shutdown_sys_tray()
    {
        if ( ShutdownIcon::IsQuickstarterInstalled() )
        {
            if( IsWindow( aListenerWindow ) )
            {
                DestroyWindow( aListenerWindow );
                aListenerWindow = nullptr;
                DestroyWindow( aExecuterWindow );
                aExecuterWindow = nullptr;
            }
            UnregisterClassW( QUICKSTART_CLASSNAME, GetModuleHandleW( nullptr ) );
            UnregisterClassW( EXECUTER_WINDOWCLASS, GetModuleHandleW( nullptr ) );
        }
    }

    void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)
    {
        MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpmis->itemData);
        HDC hdc = GetDC(hwnd);
        SIZE size;

        NONCLIENTMETRICSW ncm;
        memset(&ncm, 0, sizeof(ncm));
        ncm.cbSize = sizeof(ncm);

        SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);

        // Assume every menu item can be default and printed bold
        ncm.lfMenuFont.lfWeight = FW_BOLD;

        HFONT hfntOld = static_cast<HFONT>(SelectObject(hdc, CreateFontIndirectW( &ncm.lfMenuFont )));

        GetTextExtentPoint32W(hdc, o3tl::toW(pMyItem->text.getStr()),
                pMyItem->text.getLength(), &size);

        lpmis->itemWidth = size.cx + 4 + GetSystemMetrics( SM_CXSMICON );
        lpmis->itemHeight = std::max<int>(size.cy, GetSystemMetrics( SM_CYSMICON ));
        lpmis->itemHeight += 4;

        DeleteObject( SelectObject(hdc, hfntOld) );
        ReleaseDC(hwnd, hdc);
    }

    void OnDrawItem(HWND /*hwnd*/, LPDRAWITEMSTRUCT lpdis)
    {
        MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpdis->itemData);
        COLORREF clrPrevText, clrPrevBkgnd;
        HFONT hfntOld;
        HBRUSH hbrOld;
        int x, y;
        BOOL    fSelected = lpdis->itemState & ODS_SELECTED;
        BOOL    fDisabled = lpdis->itemState & (ODS_DISABLED | ODS_GRAYED);

        // Set the appropriate foreground and background colors.

        RECT aRect = lpdis->rcItem;

        clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );

        if ( fDisabled )
            clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( COLOR_GRAYTEXT ) );
        else
            clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );

        if ( fSelected )
            clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT) );
        else
            clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );

        hbrOld = static_cast<HBRUSH>(SelectObject( lpdis->hDC, CreateSolidBrush( GetBkColor( lpdis->hDC ) ) ));

        // Fill background
        PatBlt(lpdis->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY);

        int height = aRect.bottom-aRect.top;

        x = aRect.left;
        y = aRect.top;

        int     cx = GetSystemMetrics( SM_CXSMICON );
        int     cy = GetSystemMetrics( SM_CYSMICON );
        HICON   hIcon( nullptr );
        HMODULE hModule( GetModuleHandleW( nullptr ) );

        if ( pMyItem->module.getLength() > 0 )
        {
            LPCWSTR pModuleName = o3tl::toW( pMyItem->module.getStr() );
            hModule = GetModuleHandleW( pModuleName );
            if ( hModule == nullptr )
            {
                LoadLibraryW( pModuleName );
                hModule = GetModuleHandleW( pModuleName );
            }
        }

        hIcon = static_cast<HICON>(LoadImageW( hModule, MAKEINTRESOURCEW( pMyItem->iconId ),
                                    IMAGE_ICON, cx, cy,
                                    LR_DEFAULTCOLOR | LR_SHARED ));

        HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );

        DrawStateW( lpdis->hDC, hbrIcon, nullptr, reinterpret_cast<LPARAM>(hIcon), WPARAM(0), x, y+(height-cy)/2, 0, 0, DST_ICON | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );

        DeleteObject( hbrIcon );

        x += cx + 4;    // space for icon
        aRect.left = x;

        NONCLIENTMETRICSW ncm;
        memset(&ncm, 0, sizeof(ncm));
        ncm.cbSize = sizeof(ncm);

        SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);

        // Print default menu entry with bold font
        if ( lpdis->itemState & ODS_DEFAULT )
            ncm.lfMenuFont.lfWeight = FW_BOLD;

        hfntOld = static_cast<HFONT>(SelectObject(lpdis->hDC, CreateFontIndirectW( &ncm.lfMenuFont )));

        SIZE    size;
        GetTextExtentPointW( lpdis->hDC, o3tl::toW(pMyItem->text.getStr()), pMyItem->text.getLength(), &size );

        DrawStateW( lpdis->hDC, nullptr, nullptr, reinterpret_cast<LPARAM>(pMyItem->text.getStr()), WPARAM(0), aRect.left, aRect.top + (height - size.cy)/2, 0, 0, DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) );

        // Restore the original font and colors.
        DeleteObject( SelectObject( lpdis->hDC, hbrOld ) );
        DeleteObject( SelectObject( lpdis->hDC, hfntOld) );
        SetTextColor(lpdis->hDC, clrPrevText);
        SetBkColor(lpdis->hDC, clrPrevBkgnd);
    }

    // code from setup2 project

    void SHFree_( void *pv )
    {
        IMalloc *pMalloc;
        if( NOERROR == SHGetMalloc(&pMalloc) )
        {
            pMalloc->Free( pv );
            pMalloc->Release();
        }
    }

    #define ALLOC(type, n) static_cast<type *>(HeapAlloc(GetProcessHeap(), 0, sizeof(type) * n ))
    #define FREE(p) HeapFree(GetProcessHeap(), 0, p)

    static OUString SHGetSpecialFolder( int nFolderID )
    {

        LPITEMIDLIST    pidl;
        HRESULT         hHdl = SHGetSpecialFolderLocation( nullptr, nFolderID, &pidl );
        OUString        aFolder;

        if( hHdl == NOERROR )
        {
            WCHAR *lpFolderA;
            lpFolderA = ALLOC( WCHAR, 16000 );

            SHGetPathFromIDListW( pidl, lpFolderA );
            aFolder = o3tl::toU( lpFolderA );

            FREE( lpFolderA );
            SHFree_( pidl );
        }
        return aFolder;
    }

    OUString ShutdownIcon::GetAutostartFolderNameW32()
    {
        return SHGetSpecialFolder(CSIDL_STARTUP);
    }

    static HRESULT WINAPI SHCoCreateInstance( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknown, REFIID iid, LPVOID *ppv )
    {
        HRESULT hResult = E_NOTIMPL;
        HMODULE hModShell = GetModuleHandleW( L"SHELL32" );

        if ( hModShell != nullptr )
        {
            typedef HRESULT (WINAPI *SHCoCreateInstance_PROC)( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknwon, REFIID iid, LPVOID *ppv );

            SHCoCreateInstance_PROC lpfnSHCoCreateInstance = reinterpret_cast<SHCoCreateInstance_PROC>(GetProcAddress( hModShell, MAKEINTRESOURCEA(102) ));

            if ( lpfnSHCoCreateInstance )
                hResult = lpfnSHCoCreateInstance( lpszReserved, clsid, pUnkUnknown, iid, ppv );
        }
        return hResult;
    }

    BOOL CreateShortcut( const OUString& rAbsObject, const OUString& rAbsObjectPath,
        const OUString& rAbsShortcut, const OUString& rDescription, const OUString& rParameter )
    {
        HRESULT hres;
        IShellLinkW* psl;
        CLSID clsid_ShellLink = CLSID_ShellLink;
        CLSID clsid_IShellLink = IID_IShellLinkW;

        hres = CoCreateInstance( clsid_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
                                 clsid_IShellLink, reinterpret_cast<void**>(&psl) );
        if( FAILED(hres) )
            hres = SHCoCreateInstance( nullptr, clsid_ShellLink, nullptr, clsid_IShellLink, reinterpret_cast<void**>(&psl) );

        if( SUCCEEDED(hres) )
        {
            IPersistFile* ppf;
            psl->SetPath( o3tl::toW(rAbsObject.getStr()) );
            psl->SetWorkingDirectory( o3tl::toW(rAbsObjectPath.getStr()) );
            psl->SetDescription( o3tl::toW(rDescription.getStr()) );
            if( rParameter.getLength() )
                psl->SetArguments( o3tl::toW(rParameter.getStr()) );

            CLSID clsid_IPersistFile = IID_IPersistFile;
            hres = psl->QueryInterface( clsid_IPersistFile, reinterpret_cast<void**>(&ppf) );

            if( SUCCEEDED(hres) )
            {
                hres = ppf->Save( o3tl::toW(rAbsShortcut.getStr()), TRUE );
                ppf->Release();
            } else return FALSE;
            psl->Release();
        } else return FALSE;
        return TRUE;
    }

    // install/uninstall

    static bool FileExistsW( LPCWSTR lpPath )
    {
        bool    bExists = false;
        WIN32_FIND_DATAW    aFindData;

        HANDLE  hFind = FindFirstFileW( lpPath, &aFindData );

        if ( INVALID_HANDLE_VALUE != hFind )
        {
            bExists = true;
            FindClose( hFind );
        }

        return bExists;
    }

    bool ShutdownIcon::IsQuickstarterInstalled()
    {
        wchar_t aPath[_MAX_PATH];
        GetModuleFileNameW( nullptr, aPath, _MAX_PATH-1);

        OUString aOfficepath( o3tl::toU(aPath) );
        int i = aOfficepath.lastIndexOf('\\');
        if( i != -1 )
            aOfficepath = aOfficepath.copy(0, i);

        OUString quickstartExe(aOfficepath);
        quickstartExe += "\\quickstart.exe";

        return FileExistsW( o3tl::toW(quickstartExe.getStr()) );
    }

    void ShutdownIcon::EnableAutostartW32( const OUString &aShortcut )
    {
        wchar_t aPath[_MAX_PATH];
        GetModuleFileNameW( nullptr, aPath, _MAX_PATH-1);

        OUString aOfficepath( o3tl::toU(aPath) );
        int i = aOfficepath.lastIndexOf('\\');
        if( i != -1 )
            aOfficepath = aOfficepath.copy(0, i);

        OUString quickstartExe(aOfficepath);
        quickstartExe += "\\quickstart.exe";

        CreateShortcut( quickstartExe, aOfficepath, aShortcut, OUString(), OUString() );
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V530 The return value of function 'LoadLibraryW' is required to be utilized.