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