1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 #ifdef WNT
32 
33 // necessary to include system headers without warnings
34 #ifdef _MSC_VER
35 #pragma warning(disable:4668 4917)
36 #endif
37 
38 // Support Windows 95 too
39 #undef WINVER
40 #define WINVER 0x0400
41 #define USE_APP_SHORTCUTS
42 //
43 // the systray icon is only available on windows
44 //
45 
46 #include <unotools/moduleoptions.hxx>
47 #include <unotools/dynamicmenuoptions.hxx>
48 
49 #include "shutdownicon.hxx"
50 #include "app.hrc"
51 #include <shlobj.h>
52 #include <objidl.h>
53 #include <stdio.h>
54 #include <io.h>
55 #include <osl/thread.h>
56 #include <setup_native/qswin32.h>
57 #include <comphelper/sequenceashashmap.hxx>
58 #include <comphelper/processfactory.hxx>
59 #include <com/sun/star/uno/Reference.h>
60 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
61 #include <com/sun/star/task/XJob.hpp>
62 #include <com/sun/star/beans/NamedValue.hpp>
63 
64 #include <set>
65 
66 using namespace ::rtl;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::task;
69 using namespace ::com::sun::star::lang;
70 using namespace ::com::sun::star::beans;
71 using namespace ::osl;
72 
73 
74 #define EXECUTER_WINDOWCLASS    "SO Executer Class"
75 #define EXECUTER_WINDOWNAME     "SO Executer Window"
76 
77 
78 #define ID_QUICKSTART               1
79 #define IDM_EXIT                    2
80 #if defined(USE_APP_SHORTCUTS)
81 #	define IDM_OPEN                    3
82 #	define IDM_WRITER                  4
83 #	define IDM_CALC                    5
84 #	define IDM_IMPRESS                 6
85 #	define IDM_DRAW                    7
86 #   define IDM_BASE                    8
87 #   define IDM_TEMPLATE                9
88 #	define IDM_MATH					  12
89 #endif
90 #define IDM_INSTALL                 10
91 #define IDM_UNINSTALL               11
92 
93 
94 #define ICON_SO_DEFAULT 				1
95 #define ICON_TEXT_DOCUMENT				2
96 #define ICON_TEXT_TEMPLATE				3
97 #define ICON_SPREADSHEET_DOCUMENT		4
98 #define ICON_SPREADSHEET_TEMPLATE		5
99 #define ICON_DRAWING_DOCUMENT			6
100 #define ICON_DRAWING_TEMPLATE			7
101 #define ICON_PRESENTATION_DOCUMENT		8
102 #define ICON_PRESENTATION_TEMPLATE		9
103 #define ICON_PRESENTATION_COMPRESSED	10
104 #define ICON_GLOBAL_DOCUMENT			11
105 #define ICON_HTML_DOCUMENT				12
106 #define ICON_CHART_DOCUMENT				13
107 #define ICON_DATABASE_DOCUMENT			14
108 #define ICON_MATH_DOCUMENT				15
109 #define ICON_TEMPLATE					16
110 #define ICON_MACROLIBRARY				17
111 #define ICON_CONFIGURATION				18
112 #define ICON_OPEN						5   // See index of open folder icon in shell32.dll
113 #define ICON_SETUP						500
114 
115 #define SFX_TASKBAR_NOTIFICATION    WM_USER+1
116 
117 static HWND  aListenerWindow = NULL;
118 static HWND  aExecuterWindow = NULL;
119 static HMENU popupMenu = NULL;
120 
121 static void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis);
122 static void OnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis);
123 
124 typedef struct tagMYITEM
125 {
126     OUString text;
127     OUString module;
128     UINT iconId;
129 } MYITEM;
130 
131 // -------------------------------
132 
133 static bool isNT()
134 {
135     static bool bInitialized    = false;
136     static bool bWnt            = false;
137 
138     if( !bInitialized )
139     {
140         bInitialized = true;
141 
142 	    OSVERSIONINFO   aVerInfo;
143 	    aVerInfo.dwOSVersionInfoSize = sizeof( aVerInfo );
144 	    if ( GetVersionEx( &aVerInfo ) )
145 	    {
146 		    if ( aVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
147 			    bWnt = true;
148 	    }
149     }
150     return bWnt;
151 }
152 
153 
154 // -------------------------------
155 
156 static void addMenuItem( HMENU hMenu, UINT id, UINT iconId, const OUString& text, int& pos, int bOwnerdraw, const OUString& module )
157 {
158     MENUITEMINFOW mi;
159     memset( &mi, 0, sizeof( MENUITEMINFOW ) );
160 
161     mi.cbSize = sizeof( MENUITEMINFOW );
162     if( id == -1 )
163     {
164         mi.fMask=MIIM_TYPE;
165         mi.fType=MFT_SEPARATOR;
166     }
167     else
168     {
169         if( bOwnerdraw )
170         {
171             mi.fMask=MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
172             mi.fType=MFT_OWNERDRAW;
173             mi.fState=MFS_ENABLED;
174             mi.wID = id;
175 
176             MYITEM *pMyItem = new MYITEM;
177             pMyItem->text = text;
178             pMyItem->iconId = iconId;
179             pMyItem->module = module;
180             mi.dwItemData = (DWORD) pMyItem;
181         }
182         else
183         {
184             mi.fMask=MIIM_TYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
185             mi.fType=MFT_STRING;
186             mi.fState=MFS_ENABLED;
187             mi.wID = id;
188             mi.dwTypeData = (LPWSTR) text.getStr();
189             mi.cch = text.getLength();
190         }
191 
192 #if defined(USE_APP_SHORTCUTS)
193 		if ( IDM_TEMPLATE == id )
194 			mi.fState |= MFS_DEFAULT;
195 #endif
196 	}
197 
198     InsertMenuItemW( hMenu, pos++, TRUE, &mi );
199 }
200 
201 // -------------------------------
202 
203 static HMENU createSystrayMenu( )
204 {
205 	SvtModuleOptions	aModuleOptions;
206 
207     HMENU hMenu = CreatePopupMenu();
208     int pos=0;
209 
210     ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
211     OSL_ENSURE( pShutdownIcon, "ShutdownIcon instance empty!");
212 
213     if( !pShutdownIcon )
214         return NULL;
215 
216 #if defined(USE_APP_SHORTCUTS)
217     // collect the URLs of the entries in the File/New menu
218     ::std::set< ::rtl::OUString > aFileNewAppsAvailable;
219     SvtDynamicMenuOptions aOpt;
220     Sequence < Sequence < PropertyValue > > aNewMenu = aOpt.GetMenu( E_NEWMENU );
221     const ::rtl::OUString sURLKey( RTL_CONSTASCII_USTRINGPARAM( "URL" ) );
222 
223     const Sequence< PropertyValue >* pNewMenu = aNewMenu.getConstArray();
224     const Sequence< PropertyValue >* pNewMenuEnd = aNewMenu.getConstArray() + aNewMenu.getLength();
225     for ( ; pNewMenu != pNewMenuEnd; ++pNewMenu )
226     {
227         ::comphelper::SequenceAsHashMap aEntryItems( *pNewMenu );
228         ::rtl::OUString sURL( aEntryItems.getUnpackedValueOrDefault( sURLKey, ::rtl::OUString() ) );
229         if ( sURL.getLength() )
230             aFileNewAppsAvailable.insert( sURL );
231     }
232 
233     // describe the menu entries for launching the applications
234     struct MenuEntryDescriptor
235     {
236         SvtModuleOptions::EModule   eModuleIdentifier;
237         UINT                        nMenuItemID;
238         UINT                        nMenuIconID;
239         const char*                 pAsciiURLDescription;
240     }   aMenuItems[] =
241     {
242         { SvtModuleOptions::E_SWRITER,    IDM_WRITER, ICON_TEXT_DOCUMENT,         WRITER_URL },
243         { SvtModuleOptions::E_SCALC,      IDM_CALC,   ICON_SPREADSHEET_DOCUMENT,  CALC_URL },
244         { SvtModuleOptions::E_SIMPRESS,   IDM_IMPRESS,ICON_PRESENTATION_DOCUMENT, IMPRESS_WIZARD_URL },
245         { SvtModuleOptions::E_SDRAW,      IDM_DRAW,   ICON_DRAWING_DOCUMENT,      DRAW_URL },
246         { SvtModuleOptions::E_SDATABASE,  IDM_BASE,   ICON_DATABASE_DOCUMENT,     BASE_URL },
247         { SvtModuleOptions::E_SMATH,      IDM_MATH,   ICON_MATH_DOCUMENT,	      MATH_URL },
248     };
249 
250     OUString aEmpty;
251 
252     // insert the menu entries for launching the applications
253     for ( size_t i = 0; i < sizeof( aMenuItems ) / sizeof( aMenuItems[0] ); ++i )
254     {
255         if ( !aModuleOptions.IsModuleInstalled( aMenuItems[i].eModuleIdentifier ) )
256             // the complete application is not even installed
257             continue;
258 
259         ::rtl::OUString sURL( ::rtl::OUString::createFromAscii( aMenuItems[i].pAsciiURLDescription ) );
260 
261         if ( aFileNewAppsAvailable.find( sURL ) == aFileNewAppsAvailable.end() )
262             // the application is installed, but the entry has been configured to *not* appear in the File/New
263             // menu => also let not appear it in the quickstarter
264             continue;
265 
266 		addMenuItem( hMenu, aMenuItems[i].nMenuItemID, aMenuItems[i].nMenuIconID,
267 			pShutdownIcon->GetUrlDescription( sURL ), pos, true, aEmpty );
268     }
269 
270 
271 
272     // insert the remaining menu entries
273     addMenuItem( hMenu, IDM_TEMPLATE, ICON_TEMPLATE,
274         pShutdownIcon->GetResString( STR_QUICKSTART_FROMTEMPLATE ), pos, true, aEmpty);
275     addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, aEmpty );
276     addMenuItem( hMenu, IDM_OPEN,   ICON_OPEN, pShutdownIcon->GetResString( STR_QUICKSTART_FILEOPEN ), pos, true, OUString::createFromAscii( "SHELL32" ));
277     addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, aEmpty );
278 #endif
279     addMenuItem( hMenu, IDM_INSTALL,0, pShutdownIcon->GetResString( STR_QUICKSTART_PRELAUNCH ), pos, false, aEmpty );
280     addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, aEmpty );
281     addMenuItem( hMenu, IDM_EXIT,   0, pShutdownIcon->GetResString( STR_QUICKSTART_EXIT ), pos, false, aEmpty );
282 
283     // indicate status of autostart folder
284     CheckMenuItem( hMenu, IDM_INSTALL, MF_BYCOMMAND | (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
285 
286     return hMenu;
287 }
288 
289 // -------------------------------
290 
291 static void deleteSystrayMenu( HMENU hMenu )
292 {
293     if( !hMenu || !IsMenu( hMenu ))
294         return;
295 
296     MENUITEMINFOW mi;
297     MYITEM *pMyItem;
298     int pos=0;
299     memset( &mi, 0, sizeof( mi ) );
300     mi.cbSize = sizeof( mi );
301     mi.fMask = MIIM_DATA;
302 
303     while( GetMenuItemInfoW( hMenu, pos++, true, &mi ) )
304     {
305         pMyItem = (MYITEM*) mi.dwItemData;
306         if( pMyItem )
307         {
308             pMyItem->text = OUString();
309             delete pMyItem;
310         }
311         mi.fMask = MIIM_DATA;
312     }
313 }
314 
315 // -------------------------------
316 
317 static void addTaskbarIcon( HWND hWnd )
318 {
319     OUString strTip;
320     if( ShutdownIcon::getInstance() )
321         strTip = ShutdownIcon::getInstance()->GetResString( STR_QUICKSTART_TIP );
322 
323     // add taskbar icon
324     NOTIFYICONDATAA nid;
325     nid.hIcon = (HICON)LoadImageA( GetModuleHandle( NULL ), MAKEINTRESOURCE( ICON_SO_DEFAULT ),
326         IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
327         LR_DEFAULTCOLOR | LR_SHARED );
328 
329     // better use unicode wrapper here ?
330     strncpy( nid.szTip, ( OUStringToOString(strTip, osl_getThreadTextEncoding()).getStr() ), 64 );
331 
332     nid.cbSize              = sizeof(nid);
333     nid.hWnd                = hWnd;
334     nid.uID                 = ID_QUICKSTART;
335     nid.uCallbackMessage    = SFX_TASKBAR_NOTIFICATION;
336     nid.uFlags              = NIF_MESSAGE|NIF_TIP|NIF_ICON;
337 
338     Shell_NotifyIconA(NIM_ADD, &nid);
339 }
340 
341 // -------------------------------
342 
343 /*
344 static void removeTaskbarIcon()
345 {
346     ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
347     OSL_ENSURE( pShutdownIcon, "ShutdownIcon instance empty!");
348 
349     if( !pShutdownIcon )
350         return;
351 
352     if ( IsWindow( aListenerWindow ))
353     {
354         deleteSystrayMenu( popupMenu );
355 
356         NOTIFYICONDATAA nid;
357         nid.cbSize=sizeof(NOTIFYICONDATA);
358         nid.hWnd = aListenerWindow;
359         nid.uID = ID_QUICKSTART;
360         Shell_NotifyIconA(NIM_DELETE, &nid);
361     }
362 }
363 */
364 
365 // -------------------------------
366 
367 LRESULT CALLBACK listenerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
368 {
369     static UINT s_uTaskbarRestart = 0;
370     static UINT s_uMsgKillTray = 0;
371 
372     switch (uMsg)
373     {
374         case WM_NCCREATE:
375             return TRUE;
376         case WM_CREATE:
377             {
378                 // request notfication when taskbar is recreated
379                 // we then have to add our icon again
380                 s_uTaskbarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
381                 s_uMsgKillTray = RegisterWindowMessage( SHUTDOWN_QUICKSTART_MESSAGE );
382 
383                 // create the menu
384                 if( !popupMenu )
385                     if( (popupMenu = createSystrayMenu( )) == NULL )
386                         return -1;
387 
388                 // and the icon
389                 addTaskbarIcon( hWnd );
390 
391                 // disable shutdown
392                 ShutdownIcon::getInstance()->SetVeto( true );
393 				ShutdownIcon::getInstance()->addTerminateListener();
394             }
395             return 0;
396 
397         case WM_MEASUREITEM:
398             OnMeasureItem(hWnd, (LPMEASUREITEMSTRUCT) lParam);
399             return TRUE;
400 
401         case WM_DRAWITEM:
402             OnDrawItem(hWnd, (LPDRAWITEMSTRUCT) lParam);
403             return TRUE;
404 
405         case SFX_TASKBAR_NOTIFICATION:
406             switch( lParam )
407             {
408                 case WM_LBUTTONDBLCLK:
409 #if defined(USE_APP_SHORTCUTS)
410 					PostMessage( aExecuterWindow, WM_COMMAND, IDM_TEMPLATE, (LPARAM)hWnd );
411 #endif
412                     break;
413 
414                 case WM_RBUTTONDOWN:
415                 {
416                     POINT pt;
417                     GetCursorPos(&pt);
418                     SetForegroundWindow( hWnd );
419 
420                     // update status before showing menu, could have been changed from option page
421                     CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
422 
423 					EnableMenuItem( popupMenu, IDM_EXIT, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
424 #if defined(USE_APP_SHORTCUTS)
425 					EnableMenuItem( popupMenu, IDM_OPEN, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
426 					EnableMenuItem( popupMenu, IDM_TEMPLATE, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
427 #endif
428                     int m = TrackPopupMenuEx( popupMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON,
429                                               pt.x, pt.y, hWnd, NULL );
430                     // BUGFIX: See Q135788 (PRB: Menus for Notification Icons Don't Work Correctly)
431                     PostMessage( hWnd, NULL, 0, 0 );
432                     switch( m )
433                     {
434 #if defined(USE_APP_SHORTCUTS)
435                         case IDM_OPEN:
436                         case IDM_WRITER:
437                         case IDM_CALC:
438                         case IDM_IMPRESS:
439                         case IDM_DRAW:
440                         case IDM_TEMPLATE:
441                         case IDM_BASE:
442 						case IDM_MATH:
443 							break;
444 #endif
445                         case IDM_INSTALL:
446                             CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
447                             break;
448                         case IDM_EXIT:
449                             // delete taskbar icon
450                             NOTIFYICONDATAA nid;
451                             nid.cbSize=sizeof(NOTIFYICONDATA);
452                             nid.hWnd = hWnd;
453                             nid.uID = ID_QUICKSTART;
454                             Shell_NotifyIconA(NIM_DELETE, &nid);
455                             break;
456                     }
457 
458 					PostMessage( aExecuterWindow, WM_COMMAND, m, (LPARAM)hWnd );
459                 }
460                 break;
461             }
462             break;
463         case WM_DESTROY:
464             deleteSystrayMenu( popupMenu );
465 			// We don't need the Systray Thread anymore
466 			PostQuitMessage( 0 );
467             return DefWindowProc(hWnd, uMsg, wParam, lParam);
468         default:
469             if( uMsg == s_uTaskbarRestart )
470             {
471                 // re-create taskbar icon
472                 addTaskbarIcon( hWnd );
473             }
474 			else if ( uMsg == s_uMsgKillTray )
475 			{
476                 // delete taskbar icon
477                 NOTIFYICONDATAA nid;
478                 nid.cbSize=sizeof(NOTIFYICONDATA);
479                 nid.hWnd = hWnd;
480                 nid.uID = ID_QUICKSTART;
481                 Shell_NotifyIconA(NIM_DELETE, &nid);
482 
483 				PostMessage( aExecuterWindow, WM_COMMAND, IDM_EXIT, (LPARAM)hWnd );
484 			}
485 			else
486 				return DefWindowProc(hWnd, uMsg, wParam, lParam);
487     }
488     return 0;
489 }
490 
491 // -------------------------------
492 
493 static sal_Bool checkOEM() {
494     Reference<XMultiServiceFactory> rFactory = ::comphelper::getProcessServiceFactory();
495     Reference<XJob> rOemJob(rFactory->createInstance(
496         OUString::createFromAscii("com.sun.star.office.OEMPreloadJob")),
497         UNO_QUERY );
498     Sequence<NamedValue> args;
499     sal_Bool bResult = sal_False;
500     if (rOemJob.is())
501     {
502         Any aResult = rOemJob->execute(args);
503         aResult >>= bResult;
504     } else bResult = sal_True;
505     return bResult;
506 }
507 
508 LRESULT CALLBACK executerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
509 {
510     switch (uMsg)
511     {
512         case WM_NCCREATE:
513             return TRUE;
514         case WM_CREATE:
515             return 0;
516 
517         case WM_COMMAND:
518             switch( LOWORD(wParam) )
519             {
520 #if defined(USE_APP_SHORTCUTS)
521                 case IDM_OPEN:
522 					if ( !ShutdownIcon::bModalMode && checkOEM() )
523 						ShutdownIcon::FileOpen();
524                 break;
525                 case IDM_WRITER:
526                     if (checkOEM())
527                     ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( WRITER_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
528                 break;
529                 case IDM_CALC:
530                     if (checkOEM())
531                     ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( CALC_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
532                 break;
533                 case IDM_IMPRESS:
534                     if (checkOEM())
535                     ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( IMPRESS_WIZARD_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
536                 break;
537                 case IDM_DRAW:
538                     if (checkOEM())
539                     ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( DRAW_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
540                 break;
541                 case IDM_BASE:
542                     if (checkOEM())
543                     ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( BASE_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
544                 break;
545                 case IDM_MATH:
546                     if (checkOEM())
547                     ShutdownIcon::OpenURL( OUString( RTL_CONSTASCII_USTRINGPARAM( MATH_URL ) ), OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
548                 break;
549                 case IDM_TEMPLATE:
550 					if ( !ShutdownIcon::bModalMode && checkOEM())
551 						ShutdownIcon::FromTemplate();
552                 break;
553 #endif
554                 case IDM_INSTALL:
555                     ShutdownIcon::SetAutostart( !ShutdownIcon::GetAutostart() );
556                     break;
557                 case IDM_EXIT:
558                     // remove listener and
559                     //  terminate office if running in background
560 					if ( !ShutdownIcon::bModalMode )
561 						ShutdownIcon::terminateDesktop();
562                     break;
563             }
564 			break;
565         case WM_DESTROY:
566         default:
567             return DefWindowProc(hWnd, uMsg, wParam, lParam);
568     }
569     return 0;
570 }
571 
572 // -------------------------------
573 
574 
575 DWORD WINAPI SystrayThread( LPVOID /*lpParam*/ )
576 {
577 	aListenerWindow = CreateWindowExA(0,
578         QUICKSTART_CLASSNAME,	    // registered class name
579         QUICKSTART_WINDOWNAME,        // window name
580         0,          				// window style
581         CW_USEDEFAULT,			    // horizontal position of window
582         CW_USEDEFAULT,			    // vertical position of window
583         CW_USEDEFAULT,			    // window width
584         CW_USEDEFAULT,			    // window height
585         (HWND) NULL,	            // handle to parent or owner window
586         NULL,						// menu handle or child identifier
587         (HINSTANCE) GetModuleHandle( NULL ),    // handle to application instance
588         NULL						// window-creation data
589         );
590 
591 	MSG	msg;
592 
593 	while ( GetMessage( &msg, NULL, 0, 0 ) )
594 	{
595 		TranslateMessage( &msg );
596 		DispatchMessage( &msg );
597 	}
598 
599 	return msg.wParam; // Exit code of WM_QUIT
600 }
601 
602 // -------------------------------
603 
604 void win32_init_sys_tray()
605 {
606 	if ( ShutdownIcon::IsQuickstarterInstalled() )
607 	{
608 		WNDCLASSEXA listenerClass;
609 		listenerClass.cbSize		= sizeof(WNDCLASSEX);
610 		listenerClass.style			= 0;
611 		listenerClass.lpfnWndProc	= listenerWndProc;
612 		listenerClass.cbClsExtra	= 0;
613 		listenerClass.cbWndExtra	= 0;
614 		listenerClass.hInstance		= (HINSTANCE) GetModuleHandle( NULL );
615 		listenerClass.hIcon			= NULL;
616 		listenerClass.hCursor		= NULL;
617 		listenerClass.hbrBackground	= NULL;
618 		listenerClass.lpszMenuName	= NULL;
619 		listenerClass.lpszClassName	= QUICKSTART_CLASSNAME;
620 		listenerClass.hIconSm	    = NULL;
621 
622 		RegisterClassExA(&listenerClass);
623 
624 		WNDCLASSEXA executerClass;
625 		executerClass.cbSize		= sizeof(WNDCLASSEX);
626 		executerClass.style			= 0;
627 		executerClass.lpfnWndProc	= executerWndProc;
628 		executerClass.cbClsExtra	= 0;
629 		executerClass.cbWndExtra	= 0;
630 		executerClass.hInstance		= (HINSTANCE) GetModuleHandle( NULL );
631 		executerClass.hIcon			= NULL;
632 		executerClass.hCursor		= NULL;
633 		executerClass.hbrBackground	= NULL;
634 		executerClass.lpszMenuName	= NULL;
635 		executerClass.lpszClassName	= EXECUTER_WINDOWCLASS;
636 		executerClass.hIconSm	    = NULL;
637 
638 		RegisterClassExA( &executerClass );
639 
640 		aExecuterWindow = CreateWindowExA(0,
641 			EXECUTER_WINDOWCLASS,	    // registered class name
642 			EXECUTER_WINDOWNAME,        // window name
643 			0,          				// window style
644 			CW_USEDEFAULT,			    // horizontal position of window
645 			CW_USEDEFAULT,			    // vertical position of window
646 			CW_USEDEFAULT,			    // window width
647 			CW_USEDEFAULT,			    // window height
648 			(HWND) NULL,	            // handle to parent or owner window
649 			NULL,						// menu handle or child identifier
650 			(HINSTANCE) GetModuleHandle( NULL ),    // handle to application instance
651 			NULL						// window-creation data
652 			);
653 
654 		DWORD	dwThreadId;
655 		CreateThread( NULL, 0, SystrayThread, NULL, 0, &dwThreadId );
656 	}
657 }
658 
659 // -------------------------------
660 
661 void win32_shutdown_sys_tray()
662 {
663 	if ( ShutdownIcon::IsQuickstarterInstalled() )
664 	{
665 		if( IsWindow( aListenerWindow ) )
666 		{
667 			DestroyWindow( aListenerWindow );
668 			aListenerWindow = NULL;
669 			DestroyWindow( aExecuterWindow );
670 			aExecuterWindow = NULL;
671 		}
672 		UnregisterClassA( QUICKSTART_CLASSNAME, GetModuleHandle( NULL ) );
673 		UnregisterClassA( EXECUTER_WINDOWCLASS, GetModuleHandle( NULL ) );
674 	}
675 }
676 
677 
678 
679 // -------------------------------
680 
681 void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)
682 {
683     MYITEM *pMyItem = (MYITEM *) lpmis->itemData;
684     HDC hdc = GetDC(hwnd);
685     SIZE size;
686 
687 	NONCLIENTMETRICS ncm;
688 	memset(&ncm, 0, sizeof(ncm));
689 	ncm.cbSize = sizeof(ncm);
690 
691 	SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0);
692 
693 	// Assume every menu item can be default and printed bold
694 	ncm.lfMenuFont.lfWeight = FW_BOLD;
695 
696     HFONT hfntOld = (HFONT) SelectObject(hdc, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
697 
698     GetTextExtentPoint32W(hdc, reinterpret_cast<LPCWSTR>(pMyItem->text.getStr()),
699             pMyItem->text.getLength(), &size);
700 
701     lpmis->itemWidth = size.cx + 4 + GetSystemMetrics( SM_CXSMICON );
702     lpmis->itemHeight = (size.cy > GetSystemMetrics( SM_CYSMICON )) ? size.cy : GetSystemMetrics( SM_CYSMICON );
703     lpmis->itemHeight += 4;
704 
705     DeleteObject( SelectObject(hdc, hfntOld) );
706     ReleaseDC(hwnd, hdc);
707 }
708 
709 void OnDrawItem(HWND /*hwnd*/, LPDRAWITEMSTRUCT lpdis)
710 {
711     MYITEM *pMyItem = (MYITEM *) lpdis->itemData;
712     COLORREF clrPrevText, clrPrevBkgnd;
713     HFONT hfntOld;
714     HBRUSH hbrOld;
715     int x, y;
716 	BOOL	fSelected = lpdis->itemState & ODS_SELECTED;
717 	BOOL	fDisabled = lpdis->itemState & (ODS_DISABLED | ODS_GRAYED);
718 
719     // Set the appropriate foreground and background colors.
720 
721     RECT aRect = lpdis->rcItem;
722 
723     clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
724 
725 	if ( fDisabled )
726         clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( COLOR_GRAYTEXT ) );
727 	else
728         clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
729 
730 	if ( fSelected )
731 		clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT) );
732 	else
733 		clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
734 
735 	hbrOld = (HBRUSH)SelectObject( lpdis->hDC, CreateSolidBrush( GetBkColor( lpdis->hDC ) ) );
736 
737     // Fill background
738     PatBlt(lpdis->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY);
739 
740     int height = aRect.bottom-aRect.top;
741 
742     x = aRect.left;
743     y = aRect.top;
744 
745     int     cx = GetSystemMetrics( SM_CXSMICON );
746     int     cy = GetSystemMetrics( SM_CYSMICON );
747     HICON   hIcon( 0 );
748     HMODULE hModule( GetModuleHandle( NULL ) );
749 
750     if ( pMyItem->module.getLength() > 0 )
751     {
752         LPCWSTR pModuleName = reinterpret_cast<LPCWSTR>( pMyItem->module.getStr() );
753         hModule = GetModuleHandleW( pModuleName );
754         if ( hModule == NULL )
755         {
756             LoadLibraryW( pModuleName );
757             hModule = GetModuleHandleW( pModuleName );
758         }
759     }
760 
761     hIcon = (HICON) LoadImageA( hModule, MAKEINTRESOURCE( pMyItem->iconId ),
762                                 IMAGE_ICON, cx, cy,
763                                 LR_DEFAULTCOLOR | LR_SHARED );
764 
765     // DrawIconEx( lpdis->hDC, x, y+(height-cy)/2, hIcon, cx, cy, 0, NULL, DI_NORMAL );
766 
767 	HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
768 
769 	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) );
770 
771 	DeleteObject( hbrIcon );
772 
773     x += cx + 4;    // space for icon
774     aRect.left = x;
775 
776 	NONCLIENTMETRICS ncm;
777 	memset(&ncm, 0, sizeof(ncm));
778 	ncm.cbSize = sizeof(ncm);
779 
780 	SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, (PVOID) &ncm, 0);
781 
782 	// Print default menu entry with bold font
783 	if ( lpdis->itemState & ODS_DEFAULT )
784 		ncm.lfMenuFont.lfWeight = FW_BOLD;
785 
786     hfntOld = (HFONT) SelectObject(lpdis->hDC, (HFONT) CreateFontIndirect( &ncm.lfMenuFont ));
787 
788 
789 	SIZE	size;
790 	GetTextExtentPointW( lpdis->hDC, reinterpret_cast<LPCWSTR>(pMyItem->text.getStr()), pMyItem->text.getLength(), &size );
791 
792 	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) );
793 
794     // Restore the original font and colors.
795     DeleteObject( SelectObject( lpdis->hDC, hbrOld ) );
796     DeleteObject( SelectObject( lpdis->hDC, hfntOld) );
797     SetTextColor(lpdis->hDC, clrPrevText);
798     SetBkColor(lpdis->hDC, clrPrevBkgnd);
799 }
800 
801 // -------------------------------
802 // code from setup2 project
803 // -------------------------------
804 
805 void _SHFree( void *pv )
806 {
807 	IMalloc	*pMalloc;
808 	if( NOERROR == SHGetMalloc(&pMalloc) )
809 	{
810 		pMalloc->Free( pv );
811 		pMalloc->Release();
812 	}
813 }
814 
815 #define ALLOC(type, n) ((type *) HeapAlloc(GetProcessHeap(), 0, sizeof(type) * n ))
816 #define FREE(p) HeapFree(GetProcessHeap(), 0, p)
817 
818 static OUString _SHGetSpecialFolder( int nFolderID )
819 {
820 
821 	LPITEMIDLIST	pidl;
822 	HRESULT			hHdl = SHGetSpecialFolderLocation( NULL, nFolderID, &pidl );
823 	OUString		aFolder;
824 
825 	if( hHdl == NOERROR )
826 	{
827 		WCHAR *lpFolderA;
828 		lpFolderA = ALLOC( WCHAR, 16000 );
829 
830 		SHGetPathFromIDListW( pidl, lpFolderA );
831 		aFolder = OUString( reinterpret_cast<const sal_Unicode*>(lpFolderA) );
832 
833 		FREE( lpFolderA );
834 		_SHFree( pidl );
835 	}
836 	return aFolder;
837 }
838 
839 OUString ShutdownIcon::GetAutostartFolderNameW32()
840 {
841 	return _SHGetSpecialFolder(CSIDL_STARTUP);
842 }
843 
844 static HRESULT WINAPI SHCoCreateInstance( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknown, REFIID iid, LPVOID *ppv )
845 {
846 	HRESULT	hResult = E_NOTIMPL;
847 	HMODULE	hModShell = GetModuleHandle( "SHELL32" );
848 
849 	if ( hModShell != NULL )
850 	{
851 		typedef	HRESULT (WINAPI *SHCoCreateInstance_PROC)( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknwon, REFIID iid, LPVOID *ppv );
852 
853 		SHCoCreateInstance_PROC	lpfnSHCoCreateInstance = (SHCoCreateInstance_PROC)GetProcAddress( hModShell, MAKEINTRESOURCE(102) );
854 
855 		if ( lpfnSHCoCreateInstance )
856 			hResult = lpfnSHCoCreateInstance( lpszReserved, clsid, pUnkUnknown, iid, ppv );
857 	}
858 	return hResult;
859 }
860 
861 BOOL CreateShortcut( const OUString& rAbsObject, const OUString& rAbsObjectPath,
862 	const OUString& rAbsShortcut, const OUString& rDescription, const OUString& rParameter )
863 {
864 	HRESULT hres;
865 	IShellLink* psl;
866 	CLSID clsid_ShellLink = CLSID_ShellLink;
867 	CLSID clsid_IShellLink = IID_IShellLink;
868 
869 	hres = CoCreateInstance( clsid_ShellLink, NULL, CLSCTX_INPROC_SERVER,
870 							 clsid_IShellLink, (void**)&psl );
871 	if( FAILED(hres) )
872 		hres = SHCoCreateInstance( NULL, clsid_ShellLink, NULL, clsid_IShellLink, (void**)&psl );
873 
874 	if( SUCCEEDED(hres) )
875 	{
876 		IPersistFile* ppf;
877 		psl->SetPath( OUStringToOString(rAbsObject, osl_getThreadTextEncoding()).getStr() );
878 		psl->SetWorkingDirectory( OUStringToOString(rAbsObjectPath, osl_getThreadTextEncoding()).getStr() );
879 		psl->SetDescription( OUStringToOString(rDescription, osl_getThreadTextEncoding()).getStr() );
880 		if( rParameter.getLength() )
881 			psl->SetArguments( OUStringToOString(rParameter, osl_getThreadTextEncoding()).getStr() );
882 
883 		CLSID clsid_IPersistFile = IID_IPersistFile;
884 		hres = psl->QueryInterface( clsid_IPersistFile, (void**)&ppf );
885 
886 		if( SUCCEEDED(hres) )
887 		{
888 			hres = ppf->Save( reinterpret_cast<LPCOLESTR>(rAbsShortcut.getStr()), TRUE );
889 			ppf->Release();
890 		} else return FALSE;
891 		psl->Release();
892 	} else return FALSE;
893 	return TRUE;
894 }
895 
896 // ------------------
897 // install/uninstall
898 
899 static bool FileExistsW( LPCWSTR lpPath )
900 {
901 	bool	bExists = false;
902 	WIN32_FIND_DATAW	aFindData;
903 
904 	HANDLE	hFind = FindFirstFileW( lpPath, &aFindData );
905 
906 	if ( INVALID_HANDLE_VALUE != hFind )
907 	{
908 		bExists = true;
909 		FindClose( hFind );
910 	}
911 
912 	return bExists;
913 }
914 
915 bool ShutdownIcon::IsQuickstarterInstalled()
916 {
917     wchar_t aPath[_MAX_PATH];
918     if( isNT() )
919     {
920         GetModuleFileNameW( NULL, aPath, _MAX_PATH-1);
921     }
922     else
923     {
924         char szPathA[_MAX_PATH];
925         GetModuleFileNameA( NULL, szPathA, _MAX_PATH-1);
926 
927 		// calc the string wcstr len
928 		int nNeededWStrBuffSize = MultiByteToWideChar( CP_ACP, 0, szPathA, -1, NULL, 0 );
929 
930 		// copy the string if necessary
931 		if ( nNeededWStrBuffSize > 0 )
932 			MultiByteToWideChar( CP_ACP, 0, szPathA, -1, aPath, nNeededWStrBuffSize );
933 	}
934 
935     OUString aOfficepath( reinterpret_cast<const sal_Unicode*>(aPath) );
936     int i = aOfficepath.lastIndexOf((sal_Char) '\\');
937     if( i != -1 )
938         aOfficepath = aOfficepath.copy(0, i);
939 
940     OUString quickstartExe(aOfficepath);
941     quickstartExe += OUString( RTL_CONSTASCII_USTRINGPARAM( "\\quickstart.exe" ) );
942 
943 	return FileExistsW( reinterpret_cast<LPCWSTR>(quickstartExe.getStr()) );
944 }
945 
946 void ShutdownIcon::EnableAutostartW32( const rtl::OUString &aShortcut )
947 {
948 	wchar_t aPath[_MAX_PATH];
949 	if( isNT() )
950 		GetModuleFileNameW( NULL, aPath, _MAX_PATH-1);
951 	else
952 	{
953 		char szPathA[_MAX_PATH];
954 		GetModuleFileNameA( NULL, szPathA, _MAX_PATH-1);
955 
956 		// calc the string wcstr len
957 		int nNeededWStrBuffSize = MultiByteToWideChar( CP_ACP, 0, szPathA, -1, NULL, 0 );
958 
959 		// copy the string if necessary
960 		if ( nNeededWStrBuffSize > 0 )
961 			MultiByteToWideChar( CP_ACP, 0, szPathA, -1, aPath, nNeededWStrBuffSize );
962 	}
963 
964 	OUString aOfficepath( reinterpret_cast<const sal_Unicode*>(aPath) );
965 	int i = aOfficepath.lastIndexOf((sal_Char) '\\');
966 	if( i != -1 )
967 		aOfficepath = aOfficepath.copy(0, i);
968 
969 	OUString quickstartExe(aOfficepath);
970 	quickstartExe += OUString( RTL_CONSTASCII_USTRINGPARAM( "\\quickstart.exe" ) );
971 
972 	CreateShortcut( quickstartExe, aOfficepath, aShortcut, OUString(), OUString() );
973 }
974 
975 #endif // WNT
976 
977 
978