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