blob: d797b4a7f197177acefc73a6945f12fa8ff342e4 [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sfx2.hxx"
#ifdef WNT
// necessary to include system headers without warnings
#ifdef _MSC_VER
#pragma warning(disable:4668 4917)
#endif
// Support Windows 95 too
#undef WINVER
#define WINVER 0x0400
#define USE_APP_SHORTCUTS
//
// the systray icon is only available on windows
//
#include <unotools/moduleoptions.hxx>
#include <unotools/dynamicmenuoptions.hxx>
#include "shutdownicon.hxx"
#include "app.hrc"
#include <shlobj.h>
#include <objidl.h>
#include <stdio.h>
#include <io.h>
#include <osl/thread.h>
#include <setup_native/qswin32.h>
#include <comphelper/sequenceashashmap.hxx>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/task/XJob.hpp>
#include <com/sun/star/beans/NamedValue.hpp>
#include <set>
using namespace ::rtl;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::task;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::osl;
#define EXECUTER_WINDOWCLASS "SO Executer Class"
#define EXECUTER_WINDOWNAME "SO Executer Window"
#define ID_QUICKSTART 1
#define IDM_EXIT 2
#if defined(USE_APP_SHORTCUTS)
# 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
#endif
#define IDM_INSTALL 10
#define IDM_UNINSTALL 11
#define ICON_SO_DEFAULT 1
#define ICON_TEXT_DOCUMENT 2
#define ICON_TEXT_TEMPLATE 3
#define ICON_SPREADSHEET_DOCUMENT 4
#define ICON_SPREADSHEET_TEMPLATE 5
#define ICON_DRAWING_DOCUMENT 6
#define ICON_DRAWING_TEMPLATE 7
#define ICON_PRESENTATION_DOCUMENT 8
#define ICON_PRESENTATION_TEMPLATE 9
#define ICON_PRESENTATION_COMPRESSED 10
#define ICON_GLOBAL_DOCUMENT 11
#define ICON_HTML_DOCUMENT 12
#define ICON_CHART_DOCUMENT 13
#define ICON_DATABASE_DOCUMENT 14
#define ICON_MATH_DOCUMENT 15
#define ICON_TEMPLATE 16
#define ICON_MACROLIBRARY 17
#define ICON_CONFIGURATION 18
#define ICON_OPEN 5 // See index of open folder icon in shell32.dll
#define ICON_SETUP 500
#define SFX_TASKBAR_NOTIFICATION WM_USER+1
static HWND aListenerWindow = NULL;
static HWND aExecuterWindow = NULL;
static HMENU popupMenu = NULL;
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 bool isNT()
{
static bool bInitialized = false;
static bool bWnt = false;
if( !bInitialized )
{
bInitialized = true;
OSVERSIONINFO aVerInfo;
aVerInfo.dwOSVersionInfoSize = sizeof( aVerInfo );
if ( GetVersionEx( &aVerInfo ) )
{
if ( aVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
bWnt = true;
}
}
return bWnt;
}
// -------------------------------
static void addMenuItem( HMENU hMenu, UINT id, UINT iconId, const OUString& text, int& pos, int bOwnerdraw, const OUString& module )
{
MENUITEMINFOW mi;
memset( &mi, 0, sizeof( MENUITEMINFOW ) );
mi.cbSize = sizeof( MENUITEMINFOW );
if( id == -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 = (DWORD) 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 = (LPWSTR) text.getStr();
mi.cch = text.getLength();
}
#if defined(USE_APP_SHORTCUTS)
if ( IDM_TEMPLATE == id )
mi.fState |= MFS_DEFAULT;
#endif
}
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 NULL;
#if defined(USE_APP_SHORTCUTS)
// collect the URLs of the entries in the File/New menu
::std::set< ::rtl::OUString > aFileNewAppsAvailable;
SvtDynamicMenuOptions aOpt;
Sequence < Sequence < PropertyValue > > aNewMenu = aOpt.GetMenu( E_NEWMENU );
const ::rtl::OUString sURLKey( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
const Sequence< PropertyValue >* pNewMenu = aNewMenu.getConstArray();
const Sequence< PropertyValue >* pNewMenuEnd = aNewMenu.getConstArray() + aNewMenu.getLength();
for ( ; pNewMenu != pNewMenuEnd; ++pNewMenu )
{
::comphelper::SequenceAsHashMap aEntryItems( *pNewMenu );
::rtl::OUString sURL( aEntryItems.getUnpackedValueOrDefault( sURLKey, ::rtl::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::E_SWRITER, IDM_WRITER, ICON_TEXT_DOCUMENT, WRITER_URL },
{ SvtModuleOptions::E_SCALC, IDM_CALC, ICON_SPREADSHEET_DOCUMENT, CALC_URL },
{ SvtModuleOptions::E_SIMPRESS, IDM_IMPRESS,ICON_PRESENTATION_DOCUMENT, IMPRESS_WIZARD_URL },
{ SvtModuleOptions::E_SDRAW, IDM_DRAW, ICON_DRAWING_DOCUMENT, DRAW_URL },
{ SvtModuleOptions::E_SDATABASE, IDM_BASE, ICON_DATABASE_DOCUMENT, BASE_URL },
{ SvtModuleOptions::E_SMATH, IDM_MATH, ICON_MATH_DOCUMENT, MATH_URL },
};
OUString aEmpty;
// insert the menu entries for launching the applications
for ( size_t i = 0; i < sizeof( aMenuItems ) / sizeof( aMenuItems[0] ); ++i )
{
if ( !aModuleOptions.IsModuleInstalled( aMenuItems[i].eModuleIdentifier ) )
// the complete application is not even installed
continue;
::rtl::OUString sURL( ::rtl::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,
pShutdownIcon->GetUrlDescription( sURL ), pos, true, aEmpty );
}
// insert the remaining menu entries
addMenuItem( hMenu, IDM_TEMPLATE, ICON_TEMPLATE,
pShutdownIcon->GetResString( STR_QUICKSTART_FROMTEMPLATE ), pos, true, aEmpty);
addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, aEmpty );
addMenuItem( hMenu, IDM_OPEN, ICON_OPEN, pShutdownIcon->GetResString( STR_QUICKSTART_FILEOPEN ), pos, true, OUString::createFromAscii( "SHELL32" ));
addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, aEmpty );
#endif
addMenuItem( hMenu, IDM_INSTALL,0, pShutdownIcon->GetResString( STR_QUICKSTART_PRELAUNCH ), pos, false, aEmpty );
addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, aEmpty );
addMenuItem( hMenu, IDM_EXIT, 0, pShutdownIcon->GetResString( STR_QUICKSTART_EXIT ), pos, false, aEmpty );
// 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;
MYITEM *pMyItem;
int pos=0;
memset( &mi, 0, sizeof( mi ) );
mi.cbSize = sizeof( mi );
mi.fMask = MIIM_DATA;
while( GetMenuItemInfoW( hMenu, pos++, true, &mi ) )
{
pMyItem = (MYITEM*) mi.dwItemData;
if( pMyItem )
{
pMyItem->text = OUString();
delete pMyItem;
}
mi.fMask = MIIM_DATA;
}
}
// -------------------------------
static void addTaskbarIcon( HWND hWnd )
{
OUString strTip;
if( ShutdownIcon::getInstance() )
strTip = ShutdownIcon::getInstance()->GetResString( STR_QUICKSTART_TIP );
// add taskbar icon
NOTIFYICONDATAA nid;
nid.hIcon = (HICON)LoadImageA( GetModuleHandle( NULL ), MAKEINTRESOURCE( ICON_SO_DEFAULT ),
IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
LR_DEFAULTCOLOR | LR_SHARED );
// better use unicode wrapper here ?
strncpy( nid.szTip, ( OUStringToOString(strTip, osl_getThreadTextEncoding()).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_NotifyIconA(NIM_ADD, &nid);
}
// -------------------------------
/*
static void removeTaskbarIcon()
{
ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
OSL_ENSURE( pShutdownIcon, "ShutdownIcon instance empty!");
if( !pShutdownIcon )
return;
if ( IsWindow( aListenerWindow ))
{
deleteSystrayMenu( popupMenu );
NOTIFYICONDATAA nid;
nid.cbSize=sizeof(NOTIFYICONDATA);
nid.hWnd = aListenerWindow;
nid.uID = ID_QUICKSTART;
Shell_NotifyIconA(NIM_DELETE, &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 notfication when taskbar is recreated
// we then have to add our icon again
s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
s_uMsgKillTray = RegisterWindowMessage( SHUTDOWN_QUICKSTART_MESSAGE );
// create the menu
if( !popupMenu )
if( (popupMenu = createSystrayMenu( )) == NULL )
return -1;
// and the icon
addTaskbarIcon( hWnd );
// disable shutdown
ShutdownIcon::getInstance()->SetVeto( true );
ShutdownIcon::getInstance()->addTerminateListener();
}
return 0;
case WM_MEASUREITEM:
OnMeasureItem(hWnd, (LPMEASUREITEMSTRUCT) lParam);
return TRUE;
case WM_DRAWITEM:
OnDrawItem(hWnd, (LPDRAWITEMSTRUCT) lParam);
return TRUE;
case SFX_TASKBAR_NOTIFICATION:
switch( lParam )
{
case WM_LBUTTONDBLCLK:
#if defined(USE_APP_SHORTCUTS)
PostMessage( aExecuterWindow, WM_COMMAND, IDM_TEMPLATE, (LPARAM)hWnd );
#endif
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) );
#if defined(USE_APP_SHORTCUTS)
EnableMenuItem( popupMenu, IDM_OPEN, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
EnableMenuItem( popupMenu, IDM_TEMPLATE, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
#endif
int m = TrackPopupMenuEx( popupMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON,
pt.x, pt.y, hWnd, NULL );
// BUGFIX: See Q135788 (PRB: Menus for Notification Icons Don't Work Correctly)
PostMessage( hWnd, NULL, 0, 0 );
switch( m )
{
#if defined(USE_APP_SHORTCUTS)
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;
#endif
case IDM_INSTALL:
CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
break;
case IDM_EXIT:
// delete taskbar icon
NOTIFYICONDATAA nid;
nid.cbSize=sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = ID_QUICKSTART;
Shell_NotifyIconA(NIM_DELETE, &nid);
break;
}
PostMessage( aExecuterWindow, WM_COMMAND, m, (LPARAM)hWnd );
}
break;
}
break;
case WM_DESTROY:
deleteSystrayMenu( popupMenu );
// We don't need the Systray Thread anymore
PostQuitMessage( 0 );
return DefWindowProc(hWnd, uMsg, wParam, lParam);
default:
if( uMsg == s_uTaskbarRestart )
{
// re-create taskbar icon
addTaskbarIcon( hWnd );
}
else if ( uMsg == s_uMsgKillTray )
{
// delete taskbar icon
NOTIFYICONDATAA nid;
nid.cbSize=sizeof(NOTIFYICONDATA);
nid.hWnd = hWnd;
nid.uID = ID_QUICKSTART;
Shell_NotifyIconA(NIM_DELETE, &nid);
PostMessage( aExecuterWindow, WM_COMMAND, IDM_EXIT, (LPARAM)hWnd );
}
else
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
// -------------------------------
static sal_Bool checkOEM() {
Reference<XMultiServiceFactory> rFactory = ::comphelper::getProcessServiceFactory();
Reference<XJob> rOemJob(rFactory->createInstance(
OUString::createFromAscii("com.sun.star.office.OEMPreloadJob")),
UNO_QUERY );
Sequence<NamedValue> args;
sal_Bool bResult = sal_False;
if (rOemJob.is())
{
Any aResult = rOemJob->execute(args);
aResult >>= bResult;
} else bResult = sal_True;
return bResult;
}
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) )
{
#if defined(USE_APP_SHORTCUTS)
case IDM_OPEN:
if ( !ShutdownIcon::bModalMode && checkOEM() )
ShutdownIcon::FileOpen();
break;
case IDM_WRITER:
if (checkOEM())
ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( WRITER_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
break;
case IDM_CALC:
if (checkOEM())
ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( CALC_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
break;
case IDM_IMPRESS:
if (checkOEM())
ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( IMPRESS_WIZARD_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
break;
case IDM_DRAW:
if (checkOEM())
ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( DRAW_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
break;
case IDM_BASE:
if (checkOEM())
ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( BASE_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
break;
case IDM_MATH:
if (checkOEM())
ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( MATH_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
break;
case IDM_TEMPLATE:
if ( !ShutdownIcon::bModalMode && checkOEM())
ShutdownIcon::FromTemplate();
break;
#endif
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 DefWindowProc(hWnd, uMsg, wParam, lParam);
}
return 0;
}
// -------------------------------
DWORD WINAPI SystrayThread( LPVOID /*lpParam*/ )
{
aListenerWindow = CreateWindowExA(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
(HWND) NULL, // handle to parent or owner window
NULL, // menu handle or child identifier
(HINSTANCE) GetModuleHandle( NULL ), // handle to application instance
NULL // window-creation data
);
MSG msg;
while ( GetMessage( &msg, NULL, 0, 0 ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
return msg.wParam; // Exit code of WM_QUIT
}
// -------------------------------
void win32_init_sys_tray()
{
if ( ShutdownIcon::IsQuickstarterInstalled() )
{
WNDCLASSEXA listenerClass;
listenerClass.cbSize = sizeof(WNDCLASSEX);
listenerClass.style = 0;
listenerClass.lpfnWndProc = listenerWndProc;
listenerClass.cbClsExtra = 0;
listenerClass.cbWndExtra = 0;
listenerClass.hInstance = (HINSTANCE) GetModuleHandle( NULL );
listenerClass.hIcon = NULL;
listenerClass.hCursor = NULL;
listenerClass.hbrBackground = NULL;
listenerClass.lpszMenuName = NULL;
listenerClass.lpszClassName = QUICKSTART_CLASSNAME;
listenerClass.hIconSm = NULL;
RegisterClassExA(&listenerClass);
WNDCLASSEXA executerClass;
executerClass.cbSize = sizeof(WNDCLASSEX);
executerClass.style = 0;
executerClass.lpfnWndProc = executerWndProc;
executerClass.cbClsExtra = 0;
executerClass.cbWndExtra = 0;
executerClass.hInstance = (HINSTANCE) GetModuleHandle( NULL );
executerClass.hIcon = NULL;
executerClass.hCursor = NULL;
executerClass.hbrBackground = NULL;
executerClass.lpszMenuName = NULL;
executerClass.lpszClassName = EXECUTER_WINDOWCLASS;
executerClass.hIconSm = NULL;
RegisterClassExA( &executerClass );
aExecuterWindow = CreateWindowExA(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
(HWND) NULL, // handle to parent or owner window
NULL, // menu handle or child identifier
(HINSTANCE) GetModuleHandle( NULL ), // handle to application instance
NULL // window-creation data
);
DWORD dwThreadId;
CreateThread( NULL, 0, SystrayThread, NULL, 0, &dwThreadId );
}
}
// -------------------------------
void win32_shutdown_sys_tray()
{
if ( ShutdownIcon::IsQuickstarterInstalled() )
{
if( IsWindow( aListenerWindow ) )
{
DestroyWindow( aListenerWindow );
aListenerWindow = NULL;
DestroyWindow( aExecuterWindow );
aExecuterWindow = NULL;
}
UnregisterClassA( QUICKSTART_CLASSNAME, GetModuleHandle( NULL ) );
UnregisterClassA( EXECUTER_WINDOWCLASS, GetModuleHandle( NULL ) );
}
}
// -------------------------------
void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)
{
MYITEM *pMyItem = (MYITEM *) lpmis->itemData;
HDC hdc = GetDC(hwnd);
SIZE size;
NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(ncm));
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0);
// Assume every menu item can be default and printed bold
ncm.lfMenuFont.lfWeight = FW_BOLD;
HFONT hfntOld = (HFONT) SelectObject(hdc, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
GetTextExtentPoint32W(hdc, reinterpret_cast<LPCWSTR>(pMyItem->text.getStr()),
pMyItem->text.getLength(), &size);
lpmis->itemWidth = size.cx + 4 + GetSystemMetrics( SM_CXSMICON );
lpmis->itemHeight = (size.cy > GetSystemMetrics( SM_CYSMICON )) ? size.cy : GetSystemMetrics( SM_CYSMICON );
lpmis->itemHeight += 4;
DeleteObject( SelectObject(hdc, hfntOld) );
ReleaseDC(hwnd, hdc);
}
void OnDrawItem(HWND /*hwnd*/, LPDRAWITEMSTRUCT lpdis)
{
MYITEM *pMyItem = (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 = (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( 0 );
HMODULE hModule( GetModuleHandle( NULL ) );
if ( pMyItem->module.getLength() > 0 )
{
LPCWSTR pModuleName = reinterpret_cast<LPCWSTR>( pMyItem->module.getStr() );
hModule = GetModuleHandleW( pModuleName );
if ( hModule == NULL )
{
LoadLibraryW( pModuleName );
hModule = GetModuleHandleW( pModuleName );
}
}
hIcon = (HICON) LoadImageA( hModule, MAKEINTRESOURCE( pMyItem->iconId ),
IMAGE_ICON, cx, cy,
LR_DEFAULTCOLOR | LR_SHARED );
// DrawIconEx( lpdis->hDC, x, y+(height-cy)/2, hIcon, cx, cy, 0, NULL, DI_NORMAL );
HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
DrawStateW( lpdis->hDC, (HBRUSH)hbrIcon, (DRAWSTATEPROC)NULL, (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;
NONCLIENTMETRICS ncm;
memset(&ncm, 0, sizeof(ncm));
ncm.cbSize = sizeof(ncm);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0);
// Print default menu entry with bold font
if ( lpdis->itemState & ODS_DEFAULT )
ncm.lfMenuFont.lfWeight = FW_BOLD;
hfntOld = (HFONT) SelectObject(lpdis->hDC, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
SIZE size;
GetTextExtentPointW( lpdis->hDC, reinterpret_cast<LPCWSTR>(pMyItem->text.getStr()), pMyItem->text.getLength(), &size );
DrawStateW( lpdis->hDC, (HBRUSH)NULL, (DRAWSTATEPROC)NULL, (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) ((type *) HeapAlloc(GetProcessHeap(), 0, sizeof(type) * n ))
#define FREE(p) HeapFree(GetProcessHeap(), 0, p)
static OUString _SHGetSpecialFolder( int nFolderID )
{
LPITEMIDLIST pidl;
HRESULT hHdl = SHGetSpecialFolderLocation( NULL, nFolderID, &pidl );
OUString aFolder;
if( hHdl == NOERROR )
{
WCHAR *lpFolderA;
lpFolderA = ALLOC( WCHAR, 16000 );
SHGetPathFromIDListW( pidl, lpFolderA );
aFolder = OUString( reinterpret_cast<const sal_Unicode*>(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 = GetModuleHandle( "SHELL32" );
if ( hModShell != NULL )
{
typedef HRESULT (WINAPI *SHCoCreateInstance_PROC)( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknwon, REFIID iid, LPVOID *ppv );
SHCoCreateInstance_PROC lpfnSHCoCreateInstance = (SHCoCreateInstance_PROC)GetProcAddress( hModShell, MAKEINTRESOURCE(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;
IShellLink* psl;
CLSID clsid_ShellLink = CLSID_ShellLink;
CLSID clsid_IShellLink = IID_IShellLink;
hres = CoCreateInstance( clsid_ShellLink, NULL, CLSCTX_INPROC_SERVER,
clsid_IShellLink, (void**)&psl );
if( FAILED(hres) )
hres = SHCoCreateInstance( NULL, clsid_ShellLink, NULL, clsid_IShellLink, (void**)&psl );
if( SUCCEEDED(hres) )
{
IPersistFile* ppf;
psl->SetPath( OUStringToOString(rAbsObject, osl_getThreadTextEncoding()).getStr() );
psl->SetWorkingDirectory( OUStringToOString(rAbsObjectPath, osl_getThreadTextEncoding()).getStr() );
psl->SetDescription( OUStringToOString(rDescription, osl_getThreadTextEncoding()).getStr() );
if( rParameter.getLength() )
psl->SetArguments( OUStringToOString(rParameter, osl_getThreadTextEncoding()).getStr() );
CLSID clsid_IPersistFile = IID_IPersistFile;
hres = psl->QueryInterface( clsid_IPersistFile, (void**)&ppf );
if( SUCCEEDED(hres) )
{
hres = ppf->Save( reinterpret_cast<LPCOLESTR>(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];
if( isNT() )
{
GetModuleFileNameW( NULL, aPath, _MAX_PATH-1);
}
else
{
char szPathA[_MAX_PATH];
GetModuleFileNameA( NULL, szPathA, _MAX_PATH-1);
// calc the string wcstr len
int nNeededWStrBuffSize = MultiByteToWideChar( CP_ACP, 0, szPathA, -1, NULL, 0 );
// copy the string if necessary
if ( nNeededWStrBuffSize > 0 )
MultiByteToWideChar( CP_ACP, 0, szPathA, -1, aPath, nNeededWStrBuffSize );
}
OUString aOfficepath( reinterpret_cast<const sal_Unicode*>(aPath) );
int i = aOfficepath.lastIndexOf((sal_Char) '\\');
if( i != -1 )
aOfficepath = aOfficepath.copy(0, i);
OUString quickstartExe(aOfficepath);
quickstartExe += OUString( RTL_CONSTASCII_USTRINGPARAM( "\\quickstart.exe" ) );
return FileExistsW( reinterpret_cast<LPCWSTR>(quickstartExe.getStr()) );
}
void ShutdownIcon::EnableAutostartW32( const rtl::OUString &aShortcut )
{
wchar_t aPath[_MAX_PATH];
if( isNT() )
GetModuleFileNameW( NULL, aPath, _MAX_PATH-1);
else
{
char szPathA[_MAX_PATH];
GetModuleFileNameA( NULL, szPathA, _MAX_PATH-1);
// calc the string wcstr len
int nNeededWStrBuffSize = MultiByteToWideChar( CP_ACP, 0, szPathA, -1, NULL, 0 );
// copy the string if necessary
if ( nNeededWStrBuffSize > 0 )
MultiByteToWideChar( CP_ACP, 0, szPathA, -1, aPath, nNeededWStrBuffSize );
}
OUString aOfficepath( reinterpret_cast<const sal_Unicode*>(aPath) );
int i = aOfficepath.lastIndexOf((sal_Char) '\\');
if( i != -1 )
aOfficepath = aOfficepath.copy(0, i);
OUString quickstartExe(aOfficepath);
quickstartExe += OUString( RTL_CONSTASCII_USTRINGPARAM( "\\quickstart.exe" ) );
CreateShortcut( quickstartExe, aOfficepath, aShortcut, OUString(), OUString() );
}
#endif // WNT