1 /*
2 * This file is part of the LibreOffice project.
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 *
8 * This file incorporates work covered by the following license notice:
9 *
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
17 */
18
19 #include <sal/macros.h>
20 #include <sal/log.hxx>
21
22 #include <unotools/moduleoptions.hxx>
23 #include <unotools/dynamicmenuoptions.hxx>
24
25 #undef WB_LEFT
26 #undef WB_RIGHT
27
28 #include <shutdownicon.hxx>
29 #include <sfx2/sfxresid.hxx>
30 #include <sfx2/strings.hrc>
31 #include <shlobj.h>
32 #include <objidl.h>
33 #include <osl/diagnose.h>
34 #include <osl/thread.h>
35 #include <systools/win32/comtools.hxx>
36 #include <systools/win32/extended_max_path.hxx>
37 #include <systools/win32/qswin32.h>
38 #include <comphelper/sequenceashashmap.hxx>
39 #include <comphelper/windowserrorstring.hxx>
40 #include <o3tl/char16_t2wchar_t.hxx>
41
42 #include <set>
43
44
45 #define EXECUTER_WINDOWCLASS L"SO Executer Class"
46 #define EXECUTER_WINDOWNAME L"SO Executer Window"
47
48
49 #define ID_QUICKSTART 1
50 #define IDM_EXIT 2
51 #define IDM_OPEN 3
52 #define IDM_WRITER 4
53 #define IDM_CALC 5
54 #define IDM_IMPRESS 6
55 #define IDM_DRAW 7
56 #define IDM_BASE 8
57 #define IDM_TEMPLATE 9
58 #define IDM_MATH 12
59 #define IDM_INSTALL 10
60 #define IDM_STARTCENTER 14
61
62
63 #define ICON_LO_DEFAULT 1
64 #define ICON_TEXT_DOCUMENT 2
65 #define ICON_SPREADSHEET_DOCUMENT 4
66 #define ICON_DRAWING_DOCUMENT 6
67 #define ICON_PRESENTATION_DOCUMENT 8
68 #define ICON_TEMPLATE 11
69 #define ICON_DATABASE_DOCUMENT 12
70 #define ICON_MATH_DOCUMENT 13
71 #define ICON_OPEN 5 // See index of open folder icon in shell32.dll
72
73 #define SFX_TASKBAR_NOTIFICATION WM_USER+1
74
75 static HWND aListenerWindow = nullptr;
76 static HWND aExecuterWindow = nullptr;
77 static HMENU popupMenu = nullptr;
78
79 static void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis);
80 static void OnDrawItem(HWND hwnd, LPDRAWITEMSTRUCT lpdis);
81
82 namespace {
83
84 struct MYITEM
85 {
86 OUString text;
87 OUString module;
88 UINT iconId;
89 };
90
91 }
92
addMenuItem(HMENU hMenu,UINT id,UINT iconId,const OUString & text,int & pos,bool bOwnerdraw,const OUString & module)93 static void addMenuItem( HMENU hMenu, UINT id, UINT iconId, const OUString& text, int& pos, bool bOwnerdraw, const OUString& module )
94 {
95 MENUITEMINFOW mi = {};
96
97 mi.cbSize = sizeof( mi );
98 if( id == static_cast<UINT>( -1 ) )
99 {
100 mi.fMask=MIIM_FTYPE;
101 mi.fType=MFT_SEPARATOR;
102 }
103 else
104 {
105 if( bOwnerdraw )
106 {
107 mi.fMask=MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_DATA;
108 mi.fType=MFT_OWNERDRAW;
109
110 MYITEM *pMyItem = new MYITEM;
111 pMyItem->text = text;
112 pMyItem->iconId = iconId;
113 pMyItem->module = module;
114 mi.dwItemData = reinterpret_cast<ULONG_PTR>(pMyItem);
115 }
116 else
117 {
118 mi.fMask=MIIM_STRING | MIIM_STATE | MIIM_ID;
119 mi.dwTypeData = o3tl::toW(
120 const_cast<sal_Unicode *>(text.getStr()));
121 mi.cch = text.getLength();
122 }
123
124 mi.fState = MFS_ENABLED;
125 mi.wID = id;
126 if ( IDM_TEMPLATE == id )
127 mi.fState |= MFS_DEFAULT;
128 }
129
130 InsertMenuItemW( hMenu, pos++, TRUE, &mi );
131 }
132
133
createSystrayMenu()134 static HMENU createSystrayMenu( )
135 {
136 SvtModuleOptions aModuleOptions;
137
138 HMENU hMenu = CreatePopupMenu();
139 int pos=0;
140
141 ShutdownIcon *pShutdownIcon = ShutdownIcon::getInstance();
142 OSL_ENSURE( pShutdownIcon, "ShutdownIcon instance empty!");
143
144 if( !pShutdownIcon )
145 return nullptr;
146
147 // collect the URLs of the entries in the File/New menu
148 ::std::set< OUString > aFileNewAppsAvailable;
149 std::vector< SvtDynMenuEntry > const aNewMenu = SvtDynamicMenuOptions::GetMenu( EDynamicMenuType::NewMenu );
150 for ( SvtDynMenuEntry const & newMenuProp : aNewMenu )
151 {
152 if ( !newMenuProp.sURL.isEmpty() )
153 aFileNewAppsAvailable.insert( newMenuProp.sURL );
154 }
155
156 // describe the menu entries for launching the applications
157 struct MenuEntryDescriptor
158 {
159 SvtModuleOptions::EModule eModuleIdentifier;
160 UINT nMenuItemID;
161 UINT nMenuIconID;
162 OUString sURLDescription;
163 } static constexpr aMenuItems[] =
164 {
165 { SvtModuleOptions::EModule::WRITER, IDM_WRITER, ICON_TEXT_DOCUMENT, WRITER_URL },
166 { SvtModuleOptions::EModule::CALC, IDM_CALC, ICON_SPREADSHEET_DOCUMENT, CALC_URL },
167 { SvtModuleOptions::EModule::IMPRESS, IDM_IMPRESS,ICON_PRESENTATION_DOCUMENT, IMPRESS_WIZARD_URL },
168 { SvtModuleOptions::EModule::DRAW, IDM_DRAW, ICON_DRAWING_DOCUMENT, DRAW_URL },
169 { SvtModuleOptions::EModule::DATABASE, IDM_BASE, ICON_DATABASE_DOCUMENT, BASE_URL },
170 { SvtModuleOptions::EModule::MATH, IDM_MATH, ICON_MATH_DOCUMENT, MATH_URL },
171 };
172
173 // insert the menu entries for launching the applications
174 for (const auto& [eModuleIdentifier, nMenuItemID, nMenuIconID, sURL] : aMenuItems)
175 {
176 if ( !aModuleOptions.IsModuleInstalled( eModuleIdentifier ) )
177 // the complete application is not even installed
178 continue;
179
180 if ( aFileNewAppsAvailable.find( sURL ) == aFileNewAppsAvailable.end() )
181 // the application is installed, but the entry has been configured to *not* appear in the File/New
182 // menu => also let not appear it in the quickstarter
183 continue;
184
185 addMenuItem( hMenu, nMenuItemID, nMenuIconID,
186 ShutdownIcon::GetUrlDescription( sURL ), pos, true, "" );
187 }
188
189
190 // insert the remaining menu entries
191 addMenuItem( hMenu, IDM_TEMPLATE, ICON_TEMPLATE,
192 SfxResId( STR_QUICKSTART_FROMTEMPLATE ), pos, true, "");
193 addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
194 addMenuItem( hMenu, IDM_OPEN, ICON_OPEN, SfxResId(STR_QUICKSTART_FILEOPEN), pos, true, "SHELL32");
195 addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
196 addMenuItem( hMenu, IDM_INSTALL,0, SfxResId(STR_QUICKSTART_PRELAUNCH), pos, false, "" );
197 addMenuItem( hMenu, static_cast< UINT >( -1 ), 0, OUString(), pos, false, "" );
198 addMenuItem( hMenu, IDM_EXIT, 0, SfxResId(STR_QUICKSTART_EXIT), pos, false, "" );
199
200 // indicate status of autostart folder
201 CheckMenuItem( hMenu, IDM_INSTALL, MF_BYCOMMAND | (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
202
203 return hMenu;
204 }
205
206
deleteSystrayMenu(HMENU hMenu)207 static void deleteSystrayMenu( HMENU hMenu )
208 {
209 if( !hMenu || !IsMenu( hMenu ))
210 return;
211
212 MENUITEMINFOW mi = {};
213 mi.cbSize = sizeof( mi );
214 mi.fMask = MIIM_DATA;
215
216 for (UINT pos = 0; GetMenuItemInfoW(hMenu, pos, true, &mi); ++pos)
217 {
218 if (MYITEM* pMyItem = reinterpret_cast<MYITEM*>(mi.dwItemData))
219 delete pMyItem;
220 mi.fMask = MIIM_DATA;
221 }
222 }
223
224
addTaskbarIcon(HWND hWnd)225 static void addTaskbarIcon( HWND hWnd )
226 {
227 OUString strTip = SfxResId(STR_QUICKSTART_TIP);
228
229 // add taskbar icon
230 NOTIFYICONDATAW nid;
231 nid.hIcon = static_cast<HICON>(LoadImageW( GetModuleHandleW( nullptr ), MAKEINTRESOURCEW( ICON_LO_DEFAULT ),
232 IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ),
233 LR_DEFAULTCOLOR | LR_SHARED ));
234
235 wcsncpy( nid.szTip, o3tl::toW(strTip.getStr()), 64 );
236
237 nid.cbSize = sizeof(nid);
238 nid.hWnd = hWnd;
239 nid.uID = ID_QUICKSTART;
240 nid.uCallbackMessage = SFX_TASKBAR_NOTIFICATION;
241 nid.uFlags = NIF_MESSAGE|NIF_TIP|NIF_ICON;
242
243 Shell_NotifyIconW(NIM_ADD, &nid);
244 }
245
246
listenerWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)247 static LRESULT CALLBACK listenerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
248 {
249 static UINT s_uTaskbarRestart = 0;
250 static UINT s_uMsgKillTray = 0;
251
252 switch (uMsg)
253 {
254 case WM_NCCREATE:
255 return TRUE;
256 case WM_CREATE:
257 {
258 // request notification when taskbar is recreated
259 // we then have to add our icon again
260 s_uTaskbarRestart = RegisterWindowMessageW(L"TaskbarCreated");
261 s_uMsgKillTray = RegisterWindowMessageW( SHUTDOWN_QUICKSTART_MESSAGE );
262
263 // create the menu
264 if( !popupMenu )
265 if( (popupMenu = createSystrayMenu( )) == nullptr )
266 return -1;
267
268 // and the icon
269 addTaskbarIcon( hWnd );
270
271 // disable shutdown
272 ShutdownIcon::getInstance()->SetVeto( true );
273 ShutdownIcon::addTerminateListener();
274 }
275 return 0;
276
277 case WM_MEASUREITEM:
278 OnMeasureItem(hWnd, reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam));
279 return TRUE;
280
281 case WM_DRAWITEM:
282 OnDrawItem(hWnd, reinterpret_cast<LPDRAWITEMSTRUCT>(lParam));
283 return TRUE;
284
285 case SFX_TASKBAR_NOTIFICATION:
286 switch( lParam )
287 {
288 case WM_LBUTTONDOWN:
289 {
290 bool const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_STARTCENTER, reinterpret_cast<LPARAM>(hWnd));
291 SAL_WARN_IF(!ret, "sfx.appl", "ERROR: PostMessage() failed!");
292 break;
293 }
294
295 case WM_RBUTTONDOWN:
296 {
297 POINT pt;
298 GetCursorPos(&pt);
299 SetForegroundWindow( hWnd );
300
301 // update status before showing menu, could have been changed from option page
302 CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
303
304 EnableMenuItem( popupMenu, IDM_EXIT, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
305 EnableMenuItem( popupMenu, IDM_OPEN, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
306 EnableMenuItem( popupMenu, IDM_TEMPLATE, MF_BYCOMMAND | (ShutdownIcon::bModalMode ? MF_GRAYED : MF_ENABLED) );
307 int m = TrackPopupMenuEx( popupMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_RIGHTBUTTON,
308 pt.x, pt.y, hWnd, nullptr );
309 bool const ret = PostMessageW( hWnd, 0, 0, 0 );
310 SAL_WARN_IF(!ret, "sfx.appl", "ERROR: PostMessage() failed!");
311 switch( m )
312 {
313 case IDM_OPEN:
314 case IDM_WRITER:
315 case IDM_CALC:
316 case IDM_IMPRESS:
317 case IDM_DRAW:
318 case IDM_TEMPLATE:
319 case IDM_BASE:
320 case IDM_MATH:
321 break;
322 case IDM_INSTALL:
323 CheckMenuItem( popupMenu, IDM_INSTALL, MF_BYCOMMAND| (ShutdownIcon::GetAutostart() ? MF_CHECKED : MF_UNCHECKED) );
324 break;
325 case IDM_EXIT:
326 // delete taskbar icon
327 NOTIFYICONDATAW nid;
328 nid.cbSize=sizeof(nid);
329 nid.hWnd = hWnd;
330 nid.uID = ID_QUICKSTART;
331 Shell_NotifyIconW(NIM_DELETE, &nid);
332 break;
333 }
334
335 bool const ret2 = PostMessageW(aExecuterWindow, WM_COMMAND, m, reinterpret_cast<LPARAM>(hWnd));
336 SAL_WARN_IF(!ret2, "sfx.appl", "ERROR: PostMessage() failed!");
337 }
338 break;
339 }
340 break;
341 case WM_DESTROY:
342 deleteSystrayMenu( popupMenu );
343 // We don't need the Systray Thread anymore
344 PostQuitMessage( 0 );
345 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
346 default:
347 if( uMsg == s_uTaskbarRestart )
348 {
349 // re-create taskbar icon
350 addTaskbarIcon( hWnd );
351 }
352 else if ( uMsg == s_uMsgKillTray )
353 {
354 // delete taskbar icon
355 NOTIFYICONDATAW nid;
356 nid.cbSize=sizeof(nid);
357 nid.hWnd = hWnd;
358 nid.uID = ID_QUICKSTART;
359 Shell_NotifyIconW(NIM_DELETE, &nid);
360
361 bool const ret = PostMessageW(aExecuterWindow, WM_COMMAND, IDM_EXIT, reinterpret_cast<LPARAM>(hWnd));
362 SAL_WARN_IF(!ret, "sfx.appl", "ERROR: PostMessage() failed!");
363 }
364 else
365 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
366 }
367 return 0;
368 }
369
370
executerWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)371 static LRESULT CALLBACK executerWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
372 {
373 switch (uMsg)
374 {
375 case WM_NCCREATE:
376 return TRUE;
377 case WM_CREATE:
378 return 0;
379
380 case WM_COMMAND:
381 switch( LOWORD(wParam) )
382 {
383 case IDM_OPEN:
384 if ( !ShutdownIcon::bModalMode )
385 ShutdownIcon::FileOpen();
386 break;
387 case IDM_WRITER:
388 ShutdownIcon::OpenURL( WRITER_URL, "_default" );
389 break;
390 case IDM_CALC:
391 ShutdownIcon::OpenURL( CALC_URL, "_default" );
392 break;
393 case IDM_IMPRESS:
394 ShutdownIcon::OpenURL( IMPRESS_WIZARD_URL, "_default" );
395 break;
396 case IDM_DRAW:
397 ShutdownIcon::OpenURL( DRAW_URL, "_default" );
398 break;
399 case IDM_BASE:
400 ShutdownIcon::OpenURL( BASE_URL, "_default" );
401 break;
402 case IDM_MATH:
403 ShutdownIcon::OpenURL( MATH_URL, "_default" );
404 break;
405 case IDM_STARTCENTER:
406 ShutdownIcon::OpenURL( STARTMODULE_URL, "_default" );
407 break;
408 case IDM_TEMPLATE:
409 if ( !ShutdownIcon::bModalMode )
410 ShutdownIcon::FromTemplate();
411 break;
412 case IDM_INSTALL:
413 ShutdownIcon::SetAutostart( !ShutdownIcon::GetAutostart() );
414 break;
415 case IDM_EXIT:
416 // remove listener and
417 // terminate office if running in background
418 if ( !ShutdownIcon::bModalMode )
419 ShutdownIcon::terminateDesktop();
420 break;
421 }
422 break;
423 case WM_DESTROY:
424 default:
425 return DefWindowProcW(hWnd, uMsg, wParam, lParam);
426 }
427 return 0;
428 }
429
430
SystrayThread(void *)431 static unsigned __stdcall SystrayThread(void* /*lpParam*/)
432 {
433 osl_setThreadName("SystrayThread");
434
435 aListenerWindow = CreateWindowExW(0,
436 QUICKSTART_CLASSNAME, // registered class name
437 QUICKSTART_WINDOWNAME, // window name
438 0, // window style
439 CW_USEDEFAULT, // horizontal position of window
440 CW_USEDEFAULT, // vertical position of window
441 CW_USEDEFAULT, // window width
442 CW_USEDEFAULT, // window height
443 nullptr, // handle to parent or owner window
444 nullptr, // menu handle or child identifier
445 GetModuleHandleW( nullptr ), // handle to application instance
446 nullptr // window-creation data
447 );
448
449 MSG msg;
450
451 for (;;)
452 {
453 int const bRet = GetMessageW(&msg, nullptr, 0, 0);
454 if (bRet == 0)
455 {
456 break;
457 }
458 if (-1 == bRet)
459 {
460 SAL_WARN("sfx.appl", "GetMessageW failed: " << comphelper::WindowsErrorString(GetLastError()));
461 return 1;
462 }
463 TranslateMessage( &msg );
464 DispatchMessageW( &msg );
465 }
466
467 return msg.wParam; // Exit code of WM_QUIT
468 }
469
470
win32_init_sys_tray()471 void win32_init_sys_tray()
472 {
473 if ( ShutdownIcon::IsQuickstarterInstalled() )
474 {
475 WNDCLASSEXW listenerClass;
476 listenerClass.cbSize = sizeof(listenerClass);
477 listenerClass.style = 0;
478 listenerClass.lpfnWndProc = listenerWndProc;
479 listenerClass.cbClsExtra = 0;
480 listenerClass.cbWndExtra = 0;
481 listenerClass.hInstance = GetModuleHandleW( nullptr );
482 listenerClass.hIcon = nullptr;
483 listenerClass.hCursor = nullptr;
484 listenerClass.hbrBackground = nullptr;
485 listenerClass.lpszMenuName = nullptr;
486 listenerClass.lpszClassName = QUICKSTART_CLASSNAME;
487 listenerClass.hIconSm = nullptr;
488
489 RegisterClassExW(&listenerClass);
490
491 WNDCLASSEXW executerClass;
492 executerClass.cbSize = sizeof(executerClass);
493 executerClass.style = 0;
494 executerClass.lpfnWndProc = executerWndProc;
495 executerClass.cbClsExtra = 0;
496 executerClass.cbWndExtra = 0;
497 executerClass.hInstance = GetModuleHandleW( nullptr );
498 executerClass.hIcon = nullptr;
499 executerClass.hCursor = nullptr;
500 executerClass.hbrBackground = nullptr;
501 executerClass.lpszMenuName = nullptr;
502 executerClass.lpszClassName = EXECUTER_WINDOWCLASS;
503 executerClass.hIconSm = nullptr;
504
505 RegisterClassExW( &executerClass );
506
507 aExecuterWindow = CreateWindowExW(0,
508 EXECUTER_WINDOWCLASS, // registered class name
509 EXECUTER_WINDOWNAME, // window name
510 0, // window style
511 CW_USEDEFAULT, // horizontal position of window
512 CW_USEDEFAULT, // vertical position of window
513 CW_USEDEFAULT, // window width
514 CW_USEDEFAULT, // window height
515 nullptr, // handle to parent or owner window
516 nullptr, // menu handle or child identifier
517 GetModuleHandleW( nullptr ), // handle to application instance
518 nullptr // window-creation data
519 );
520
521 CloseHandle(reinterpret_cast<HANDLE>(
522 _beginthreadex(nullptr, 0, SystrayThread, nullptr, 0, nullptr)));
523 }
524 }
525
526
win32_shutdown_sys_tray()527 void win32_shutdown_sys_tray()
528 {
529 if ( ShutdownIcon::IsQuickstarterInstalled() )
530 {
531 if( IsWindow( aListenerWindow ) )
532 {
533 DestroyWindow( aListenerWindow );
534 aListenerWindow = nullptr;
535 DestroyWindow( aExecuterWindow );
536 aExecuterWindow = nullptr;
537 }
538 UnregisterClassW( QUICKSTART_CLASSNAME, GetModuleHandleW( nullptr ) );
539 UnregisterClassW( EXECUTER_WINDOWCLASS, GetModuleHandleW( nullptr ) );
540 }
541 }
542
543
OnMeasureItem(HWND hwnd,LPMEASUREITEMSTRUCT lpmis)544 void OnMeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT lpmis)
545 {
546 MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpmis->itemData);
547 HDC hdc = GetDC(hwnd);
548 SIZE size;
549
550 NONCLIENTMETRICSW ncm = {};
551 ncm.cbSize = sizeof(ncm);
552
553 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
554
555 // Assume every menu item can be default and printed bold
556 ncm.lfMenuFont.lfWeight = FW_BOLD;
557
558 HFONT hfntOld = static_cast<HFONT>(SelectObject(hdc, CreateFontIndirectW( &ncm.lfMenuFont )));
559
560 GetTextExtentPoint32W(hdc, o3tl::toW(pMyItem->text.getStr()),
561 pMyItem->text.getLength(), &size);
562
563 lpmis->itemWidth = size.cx + 4 + GetSystemMetrics( SM_CXSMICON );
564 lpmis->itemHeight = std::max<int>(size.cy, GetSystemMetrics( SM_CYSMICON ));
565 lpmis->itemHeight += 4;
566
567 DeleteObject( SelectObject(hdc, hfntOld) );
568 ReleaseDC(hwnd, hdc);
569 }
570
OnDrawItem(HWND,LPDRAWITEMSTRUCT lpdis)571 void OnDrawItem(HWND /*hwnd*/, LPDRAWITEMSTRUCT lpdis)
572 {
573 MYITEM *pMyItem = reinterpret_cast<MYITEM *>(lpdis->itemData);
574 COLORREF clrPrevText, clrPrevBkgnd;
575 HFONT hfntOld;
576 HBRUSH hbrOld;
577 int x, y;
578 bool fSelected = lpdis->itemState & ODS_SELECTED;
579 bool fDisabled = lpdis->itemState & (ODS_DISABLED | ODS_GRAYED);
580
581 // Set the appropriate foreground and background colors.
582
583 RECT aRect = lpdis->rcItem;
584
585 clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
586
587 if ( fDisabled )
588 clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( COLOR_GRAYTEXT ) );
589 else
590 clrPrevText = SetTextColor( lpdis->hDC, GetSysColor( fSelected ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT ) );
591
592 if ( fSelected )
593 clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_HIGHLIGHT) );
594 else
595 clrPrevBkgnd = SetBkColor( lpdis->hDC, GetSysColor(COLOR_MENU) );
596
597 hbrOld = static_cast<HBRUSH>(SelectObject( lpdis->hDC, CreateSolidBrush( GetBkColor( lpdis->hDC ) ) ));
598
599 // Fill background
600 PatBlt(lpdis->hDC, aRect.left, aRect.top, aRect.right-aRect.left, aRect.bottom-aRect.top, PATCOPY);
601
602 int height = aRect.bottom-aRect.top;
603
604 x = aRect.left;
605 y = aRect.top;
606
607 int cx = GetSystemMetrics( SM_CXSMICON );
608 int cy = GetSystemMetrics( SM_CYSMICON );
609 HICON hIcon( nullptr );
610 HMODULE hModule( GetModuleHandleW( nullptr ) );
611
612 if ( pMyItem->module.getLength() > 0 )
613 {
614 LPCWSTR pModuleName = o3tl::toW( pMyItem->module.getStr() );
615 hModule = GetModuleHandleW( pModuleName );
616 if ( hModule == nullptr )
617 {
618 hModule = LoadLibraryW(pModuleName);
619 }
620 }
621
622 hIcon = static_cast<HICON>(LoadImageW( hModule, MAKEINTRESOURCEW( pMyItem->iconId ),
623 IMAGE_ICON, cx, cy,
624 LR_DEFAULTCOLOR | LR_SHARED ));
625
626
627 HBRUSH hbrIcon = CreateSolidBrush( GetSysColor( COLOR_GRAYTEXT ) );
628
629 DrawStateW( lpdis->hDC, hbrIcon, nullptr, reinterpret_cast<LPARAM>(hIcon), WPARAM(0), x, y+(height-cy)/2, 0, 0, DST_ICON | (fDisabled ? (fSelected ? DSS_MONO : DSS_DISABLED) : DSS_NORMAL) );
630
631 DeleteObject( hbrIcon );
632
633 x += cx + 4; // space for icon
634 aRect.left = x;
635
636 NONCLIENTMETRICSW ncm = {};
637 ncm.cbSize = sizeof(ncm);
638
639 SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0);
640
641 // Print default menu entry with bold font
642 if ( lpdis->itemState & ODS_DEFAULT )
643 ncm.lfMenuFont.lfWeight = FW_BOLD;
644
645 hfntOld = static_cast<HFONT>(SelectObject(lpdis->hDC, CreateFontIndirectW( &ncm.lfMenuFont )));
646
647
648 SIZE size;
649 GetTextExtentPointW( lpdis->hDC, o3tl::toW(pMyItem->text.getStr()), pMyItem->text.getLength(), &size );
650
651 DrawStateW( lpdis->hDC, nullptr, nullptr, reinterpret_cast<LPARAM>(pMyItem->text.getStr()), WPARAM(0), aRect.left, aRect.top + (height - size.cy)/2, 0, 0, DST_TEXT | (fDisabled && !fSelected ? DSS_DISABLED : DSS_NORMAL) );
652
653 // Restore the original font and colors.
654 DeleteObject( SelectObject( lpdis->hDC, hbrOld ) );
655 DeleteObject( SelectObject( lpdis->hDC, hfntOld) );
656 SetTextColor(lpdis->hDC, clrPrevText);
657 SetBkColor(lpdis->hDC, clrPrevBkgnd);
658 }
659
660
661 // code from setup2 project
662
SHGetSpecialFolder(int nFolderID)663 static OUString SHGetSpecialFolder( int nFolderID )
664 {
665
666 LPITEMIDLIST pidl;
667 HRESULT hHdl = SHGetSpecialFolderLocation( nullptr, nFolderID, &pidl );
668 OUString aFolder;
669
670 if( hHdl == NOERROR )
671 {
672 auto xFolder = std::make_unique<WCHAR[]>(16000);
673 SHGetPathFromIDListW(pidl, xFolder.get());
674 aFolder = o3tl::toU(xFolder.get());
675 }
676
677 return aFolder;
678 }
679
GetAutostartFolderNameW32()680 OUString ShutdownIcon::GetAutostartFolderNameW32()
681 {
682 return SHGetSpecialFolder(CSIDL_STARTUP);
683 }
684
SHCoCreateInstance(LPVOID lpszReserved,REFCLSID clsid,LPUNKNOWN pUnkUnknown,REFIID iid,LPVOID * ppv)685 static HRESULT WINAPI SHCoCreateInstance( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknown, REFIID iid, LPVOID *ppv )
686 {
687 HRESULT hResult = E_NOTIMPL;
688 HMODULE hModShell = GetModuleHandleW( L"SHELL32" );
689
690 if ( hModShell != nullptr )
691 {
692 typedef HRESULT (WINAPI *SHCoCreateInstance_PROC)( LPVOID lpszReserved, REFCLSID clsid, LPUNKNOWN pUnkUnknown, REFIID iid, LPVOID *ppv );
693
694 SHCoCreateInstance_PROC lpfnSHCoCreateInstance = reinterpret_cast<SHCoCreateInstance_PROC>(GetProcAddress( hModShell, MAKEINTRESOURCEA(102) ));
695
696 if ( lpfnSHCoCreateInstance )
697 hResult = lpfnSHCoCreateInstance( lpszReserved, clsid, pUnkUnknown, iid, ppv );
698 }
699 return hResult;
700 }
701
CreateShortcut(const OUString & rAbsObject,const OUString & rAbsObjectPath,const OUString & rAbsShortcut,const OUString & rDescription,const OUString & rParameter)702 static bool CreateShortcut( const OUString& rAbsObject, const OUString& rAbsObjectPath,
703 const OUString& rAbsShortcut, const OUString& rDescription, const OUString& rParameter )
704 {
705 try
706 {
707 sal::systools::COMReference<IShellLinkW> psl(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER);
708 psl->SetPath( o3tl::toW(rAbsObject.getStr()) );
709 psl->SetWorkingDirectory( o3tl::toW(rAbsObjectPath.getStr()) );
710 psl->SetDescription( o3tl::toW(rDescription.getStr()) );
711 if (!rParameter.isEmpty())
712 psl->SetArguments( o3tl::toW(rParameter.getStr()) );
713
714 sal::systools::COMReference<IPersistFile> ppf(psl, sal::systools::COM_QUERY_THROW);
715 return SUCCEEDED(ppf->Save(o3tl::toW(rAbsShortcut.getStr()), TRUE));
716 }
717 catch (const sal::systools::ComError&)
718 {
719 return false;
720 }
721 }
722
723
724 // install/uninstall
725
FileExistsW(LPCWSTR lpPath)726 static bool FileExistsW( LPCWSTR lpPath )
727 {
728 bool bExists = false;
729 WIN32_FIND_DATAW aFindData;
730
731 HANDLE hFind = FindFirstFileW( lpPath, &aFindData );
732
733 if ( INVALID_HANDLE_VALUE != hFind )
734 {
735 bExists = true;
736 FindClose( hFind );
737 }
738
739 return bExists;
740 }
741
IsQuickstarterInstalled()742 bool ShutdownIcon::IsQuickstarterInstalled()
743 {
744 wchar_t aPath[EXTENDED_MAX_PATH];
745 GetModuleFileNameW(nullptr, aPath, std::size(aPath));
746
747 std::u16string_view aOfficepath(o3tl::toU(aPath));
748 auto i = aOfficepath.find_last_of('\\');
749 if (i != std::u16string_view::npos)
750 aOfficepath = aOfficepath.substr(0, i);
751
752 OUString quickstartExe(OUString::Concat(aOfficepath) + "\\quickstart.exe");
753
754 return FileExistsW( o3tl::toW(quickstartExe.getStr()) );
755 }
756
EnableAutostartW32(const OUString & aShortcut)757 void ShutdownIcon::EnableAutostartW32( const OUString &aShortcut )
758 {
759 wchar_t aPath[EXTENDED_MAX_PATH];
760 GetModuleFileNameW(nullptr, aPath, std::size(aPath));
761
762 OUString aOfficepath( o3tl::toU(aPath) );
763 int i = aOfficepath.lastIndexOf('\\');
764 if( i != -1 )
765 aOfficepath = aOfficepath.copy(0, i);
766
767 OUString quickstartExe(aOfficepath + "\\quickstart.exe");
768
769 CreateShortcut( quickstartExe, aOfficepath, aShortcut, OUString(), OUString() );
770 }
771
772
773 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
774