xref: /core/vcl/win/app/salinst.cxx (revision 0bcb62c6)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <string.h>
21 #include <svsys.h>
22 #include <process.h>
23 
24 #include <osl/conditn.hxx>
25 #include <osl/file.hxx>
26 #include <sal/log.hxx>
27 #include <tools/debug.hxx>
28 #include <tools/time.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/solarmutex.hxx>
31 #include <comphelper/windowserrorstring.hxx>
32 #include <com/sun/star/uno/Reference.h>
33 #include <o3tl/char16_t2wchar_t.hxx>
34 #include <o3tl/temporary.hxx>
35 
36 #include <dndhelper.hxx>
37 #include <vcl/inputtypes.hxx>
38 #include <vcl/opengl/OpenGLContext.hxx>
39 #include <vcl/sysdata.hxx>
40 #include <vcl/timer.hxx>
41 #include <vclpluginapi.h>
42 
43 #include <win/dnd_source.hxx>
44 #include <win/dnd_target.hxx>
45 #include <win/wincomp.hxx>
46 #include <win/salids.hrc>
47 #include <win/saldata.hxx>
48 #include <win/salinst.h>
49 #include <win/salframe.h>
50 #include <win/salobj.h>
51 #include <win/saltimer.h>
52 #include <win/salbmp.h>
53 #include <win/winlayout.hxx>
54 
55 #include <config_features.h>
56 #include <vcl/skia/SkiaHelper.hxx>
57 #if HAVE_FEATURE_SKIA
58 #include <config_skia.h>
59 #include <skia/salbmp.hxx>
60 #include <skia/win/gdiimpl.hxx>
61 #endif
62 
63 #include <salsys.hxx>
64 
65 #include <desktop/crashreport.hxx>
66 
67 #include <prewin.h>
68 
69 #include <gdiplus.h>
70 #include <shlobj.h>
71 
72 #include <postwin.h>
73 
74 static LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
75 
76 class SalYieldMutex : public comphelper::SolarMutex
77 {
78 public: // for ImplSalYield() and ImplSalYieldMutexAcquireWithWait()
79     osl::Condition            m_condition; /// for MsgWaitForMultipleObjects()
80 
81 protected:
82     virtual void              doAcquire( sal_uInt32 nLockCount ) override;
83     virtual sal_uInt32        doRelease( bool bUnlockAll ) override;
84 
85     static void               BeforeReleaseHandler();
86 
87 public:
88     explicit SalYieldMutex();
89 
90     virtual bool              IsCurrentThread() const override;
91     virtual bool              tryToAcquire() override;
92 };
93 
SalYieldMutex()94 SalYieldMutex::SalYieldMutex()
95 {
96     SetBeforeReleaseHandler( &SalYieldMutex::BeforeReleaseHandler );
97 }
98 
BeforeReleaseHandler()99 void SalYieldMutex::BeforeReleaseHandler()
100 {
101     OpenGLContext::prepareForYield();
102 
103     if ( GetSalData()->mnAppThreadId != GetCurrentThreadId() )
104     {
105         // If we don't call these message, the Output from the
106         // Java clients doesn't come in the right order
107         GdiFlush();
108     }
109 }
110 
111 /// note: while VCL is fully up and running (other threads started and
112 /// before shutdown), the main thread must acquire SolarMutex only via
113 /// this function to avoid deadlock
doAcquire(sal_uInt32 nLockCount)114 void SalYieldMutex::doAcquire( sal_uInt32 nLockCount )
115 {
116     WinSalInstance* pInst = GetSalData()->mpInstance;
117     if ( pInst && pInst->IsMainThread() )
118     {
119         if ( pInst->m_nNoYieldLock )
120             return;
121         // tdf#96887 If this is the main thread, then we must wait for two things:
122         // - the yield mutex being unlocked
123         // - SendMessage() being triggered
124         // This can nicely be done using MsgWaitForMultipleObjects, which is called in
125         // m_condition.wait(). The 2nd one is
126         // needed because if we don't reschedule, then we create deadlocks if a
127         // Window's create/destroy is called via SendMessage() from another thread.
128         // Have a look at the osl_waitCondition implementation for more info.
129         do {
130             // Calling Condition::reset frequently turns out to be a little expensive,
131             // and the vast majority of the time there is no contention, so first
132             // try just acquiring the mutex.
133             if (m_aMutex.tryToAcquire())
134                 break;
135             // reset condition *before* acquiring!
136             m_condition.reset();
137             if (m_aMutex.tryToAcquire())
138                 break;
139             // wait for SalYieldMutex::release() to set the condition
140             osl::Condition::Result res = m_condition.wait();
141             assert(osl::Condition::Result::result_ok == res);
142             (void) res;
143         }
144         while ( true );
145     }
146     else
147         m_aMutex.acquire();
148     ++m_nCount;
149     --nLockCount;
150 
151     comphelper::SolarMutex::doAcquire( nLockCount );
152 }
153 
doRelease(const bool bUnlockAll)154 sal_uInt32 SalYieldMutex::doRelease( const bool bUnlockAll )
155 {
156     WinSalInstance* pInst = GetSalData()->mpInstance;
157     if ( pInst && pInst->m_nNoYieldLock && pInst->IsMainThread() )
158         return 1;
159 
160     sal_uInt32 nCount = comphelper::SolarMutex::doRelease( bUnlockAll );
161     // wake up ImplSalYieldMutexAcquireWithWait() after release
162     if ( 0 == m_nCount )
163         m_condition.set();
164     return nCount;
165 }
166 
tryToAcquire()167 bool SalYieldMutex::tryToAcquire()
168 {
169     WinSalInstance* pInst = GetSalData()->mpInstance;
170     if ( pInst )
171     {
172         if ( pInst->m_nNoYieldLock && pInst->IsMainThread() )
173             return true;
174         else
175             return comphelper::SolarMutex::tryToAcquire();
176     }
177     else
178         return false;
179 }
180 
ImplSalYieldMutexAcquireWithWait(sal_uInt32 nCount)181 void ImplSalYieldMutexAcquireWithWait( sal_uInt32 nCount )
182 {
183     WinSalInstance* pInst = GetSalData()->mpInstance;
184     if ( pInst )
185         pInst->GetYieldMutex()->acquire( nCount );
186 }
187 
ImplSalYieldMutexTryToAcquire()188 bool ImplSalYieldMutexTryToAcquire()
189 {
190     WinSalInstance* pInst = GetSalData()->mpInstance;
191     return pInst && pInst->GetYieldMutex()->tryToAcquire();
192 }
193 
ImplSalYieldMutexRelease()194 void ImplSalYieldMutexRelease()
195 {
196     WinSalInstance* pInst = GetSalData()->mpInstance;
197     if ( pInst )
198     {
199         GdiFlush();
200         pInst->GetYieldMutex()->release();
201     }
202 }
203 
IsCurrentThread() const204 bool SalYieldMutex::IsCurrentThread() const
205 {
206     if ( !GetSalData()->mpInstance->m_nNoYieldLock )
207         return SolarMutex::IsCurrentThread();
208     else
209         return GetSalData()->mpInstance->IsMainThread();
210 }
211 
initKeyCodeMap()212 void SalData::initKeyCodeMap()
213 {
214     auto initKey = [this](wchar_t ch, sal_uInt16 key)
215     {
216         if (UINT vkey = LOWORD(VkKeyScanW(ch)); vkey < 0xffff)
217             maVKMap[vkey] = key;
218     };
219 
220     maVKMap.clear();
221 
222     initKey( L'+', KEY_ADD );
223     initKey( L'-', KEY_SUBTRACT );
224     initKey( L'*', KEY_MULTIPLY );
225     initKey( L'/', KEY_DIVIDE );
226     initKey( L'.', KEY_POINT );
227     initKey( L',', KEY_COMMA );
228     initKey( L'<', KEY_LESS );
229     initKey( L'>', KEY_GREATER );
230     initKey( L'=', KEY_EQUAL );
231     initKey( L'~', KEY_TILDE );
232     initKey( L'`', KEY_QUOTELEFT );
233     initKey( L'[', KEY_BRACKETLEFT );
234     initKey( L']', KEY_BRACKETRIGHT );
235     initKey( L';', KEY_SEMICOLON );
236     initKey( L'\'', KEY_QUOTERIGHT );
237     initKey( L'}', KEY_RIGHTCURLYBRACKET );
238     initKey( L'#', KEY_NUMBERSIGN);
239     initKey( L':', KEY_COLON );
240 }
241 
242 // SalData
243 
SalData()244 SalData::SalData()
245     : sal::systools::CoInitializeGuard(COINIT_APARTMENTTHREADED, false,
246                                        sal::systools::CoInitializeGuard::WhenFailed::NoThrow)
247          // put main thread in Single Threaded Apartment (STA)
248 {
249     mhInst = nullptr;           // default instance handle
250     mnCmdShow = 0;              // default frame show style
251     mhDitherPal = nullptr;      // dither palette
252     mhDitherDIB = nullptr;      // dither memory handle
253     mpDitherDIB = nullptr;      // dither memory
254     mpDitherDIBData = nullptr;  // beginning of DIB data
255     mpDitherDiff = nullptr;     // Dither mapping table
256     mpDitherLow = nullptr;      // Dither mapping table
257     mpDitherHigh = nullptr;     // Dither mapping table
258     mhSalObjMsgHook = nullptr;  // hook to get interesting msg for SalObject
259     mhWantLeaveMsg = nullptr;   // window handle, that want a MOUSELEAVE message
260     mpInstance = nullptr;  // pointer of first instance
261     mpFirstFrame = nullptr;     // pointer of first frame
262     mpFirstObject = nullptr;    // pointer of first object window
263     mpFirstVD = nullptr;        // first VirDev
264     mpFirstPrinter = nullptr;   // first printing printer
265     mh50Bmp = nullptr;          // 50% Bitmap
266     mh50Brush = nullptr;        // 50% Brush
267     int i;
268     for(i=0; i<MAX_STOCKPEN; i++)
269     {
270         maStockPenColorAry[i] = 0;
271         mhStockPenAry[i] = nullptr;
272     }
273     for(i=0; i<MAX_STOCKBRUSH; i++)
274     {
275         maStockBrushColorAry[i] = 0;
276         mhStockBrushAry[i] = nullptr;
277     }
278     mnStockPenCount = 0;        // count of static pens
279     mnStockBrushCount = 0;      // count of static brushes
280     mnSalObjWantKeyEvt = 0;     // KeyEvent for the SalObj hook
281     mnCacheDCInUse = 0;         // count of CacheDC in use
282     mbObjClassInit = false;     // is SALOBJECTCLASS initialised
283     mbInPalChange = false;      // is in WM_QUERYNEWPALETTE
284     mnAppThreadId = 0;          // Id from Application-Thread
285     mpFirstIcon = nullptr;      // icon cache, points to first icon, NULL if none
286     mpSharedTempFontItem = nullptr;
287     mpOtherTempFontItem = nullptr;
288     mbThemeChanged = false;     // true if visual theme was changed: throw away theme handles
289     mbThemeMenuSupport = false;
290 
291     // init with NULL
292     gdiplusToken = 0;
293 
294     initKeyCodeMap();
295 
296     SetSalData( this );
297     initNWF();
298 
299     static Gdiplus::GdiplusStartupInput gdiplusStartupInput;
300     Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
301 }
302 
~SalData()303 SalData::~SalData()
304 {
305     deInitNWF();
306     SetSalData( nullptr );
307 
308     if (gdiplusToken)
309         Gdiplus::GdiplusShutdown(gdiplusToken);
310 }
311 
OSSupportsDarkMode()312 bool OSSupportsDarkMode()
313 {
314     bool bRet = false;
315     if (HMODULE h_ntdll = GetModuleHandleW(L"ntdll.dll"))
316     {
317         typedef LONG(WINAPI* RtlGetVersion_t)(PRTL_OSVERSIONINFOW);
318         if (auto RtlGetVersion
319             = reinterpret_cast<RtlGetVersion_t>(GetProcAddress(h_ntdll, "RtlGetVersion")))
320         {
321             RTL_OSVERSIONINFOW vi2{};
322             vi2.dwOSVersionInfoSize = sizeof(vi2);
323             if (RtlGetVersion(&vi2) == 0)
324             {
325                 if (vi2.dwMajorVersion > 10)
326                     bRet = true;
327                 else if (vi2.dwMajorVersion == 10)
328                 {
329                     if (vi2.dwMinorVersion > 0)
330                         bRet = true;
331                     else if (vi2.dwBuildNumber >= 18362)
332                         bRet = true;
333                 }
334             }
335         }
336     }
337     return bRet;
338 }
339 
340 namespace {
341 
342 enum PreferredAppMode
343 {
344     Default,
345     AllowDark,
346     ForceDark,
347     ForceLight,
348     Max
349 };
350 
351 }
352 
353 extern "C" {
create_SalInstance()354 VCLPLUG_WIN_PUBLIC SalInstance* create_SalInstance()
355 {
356     SalData* pSalData = new SalData();
357 
358     STARTUPINFOW aSI;
359     aSI.cb = sizeof( aSI );
360     GetStartupInfoW( &aSI );
361     pSalData->mhInst = GetModuleHandleW( nullptr );
362     pSalData->mnCmdShow = aSI.wShowWindow;
363 
364     pSalData->mnAppThreadId = GetCurrentThreadId();
365 
366     static bool bSetAllowDarkMode = OSSupportsDarkMode(); // too early to additionally check LibreOffice's config
367     if (bSetAllowDarkMode)
368     {
369         typedef PreferredAppMode(WINAPI* SetPreferredAppMode_t)(PreferredAppMode);
370         if (HINSTANCE hUxthemeLib = LoadLibraryExW(L"uxtheme.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32))
371         {
372             if (auto SetPreferredAppMode = reinterpret_cast<SetPreferredAppMode_t>(GetProcAddress(hUxthemeLib, MAKEINTRESOURCEA(135))))
373                 SetPreferredAppMode(AllowDark);
374             FreeLibrary(hUxthemeLib);
375         }
376     }
377 
378     // register frame class
379     WNDCLASSEXW aWndClassEx;
380     aWndClassEx.cbSize          = sizeof( aWndClassEx );
381     aWndClassEx.style           = CS_OWNDC;
382     aWndClassEx.lpfnWndProc     = SalFrameWndProcW;
383     aWndClassEx.cbClsExtra      = 0;
384     aWndClassEx.cbWndExtra      = SAL_FRAME_WNDEXTRA;
385     aWndClassEx.hInstance       = pSalData->mhInst;
386     aWndClassEx.hCursor         = nullptr;
387     aWndClassEx.hbrBackground   = nullptr;
388     aWndClassEx.lpszMenuName    = nullptr;
389     aWndClassEx.lpszClassName   = SAL_FRAME_CLASSNAMEW;
390     ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm );
391     if ( !RegisterClassExW( &aWndClassEx ) )
392         return nullptr;
393 
394     aWndClassEx.hIcon           = nullptr;
395     aWndClassEx.hIconSm         = nullptr;
396     aWndClassEx.style          |= CS_SAVEBITS;
397     aWndClassEx.lpszClassName   = SAL_SUBFRAME_CLASSNAMEW;
398     if ( !RegisterClassExW( &aWndClassEx ) )
399         return nullptr;
400 
401     // shadow effect for popups on XP
402     aWndClassEx.style          |= CS_DROPSHADOW;
403     aWndClassEx.lpszClassName   = SAL_TMPSUBFRAME_CLASSNAMEW;
404     if ( !RegisterClassExW( &aWndClassEx ) )
405         return nullptr;
406 
407     aWndClassEx.style           = 0;
408     aWndClassEx.lpfnWndProc     = SalComWndProcW;
409     aWndClassEx.cbWndExtra      = 0;
410     aWndClassEx.lpszClassName   = SAL_COM_CLASSNAMEW;
411     if ( !RegisterClassExW( &aWndClassEx ) )
412         return nullptr;
413 
414     HWND hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW,
415                                L"", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr,
416                                pSalData->mhInst, nullptr );
417     if ( !hComWnd )
418         return nullptr;
419 
420     WinSalInstance* pInst = new WinSalInstance;
421 
422     // init instance (only one instance in this version !!!)
423     pSalData->mpInstance   = pInst;
424     pInst->mhInst    = pSalData->mhInst;
425     pInst->mhComWnd  = hComWnd;
426 
427     // init static GDI Data
428     ImplInitSalGDI();
429 
430     return pInst;
431 }
432 }
433 
WinSalInstance()434 WinSalInstance::WinSalInstance()
435     : SalInstance(std::make_unique<SalYieldMutex>())
436     , mhInst( nullptr )
437     , mhComWnd( nullptr )
438     , m_nNoYieldLock( 0 )
439 {
440     ImplSVData* pSVData = ImplGetSVData();
441     pSVData->maAppData.mxToolkitName = OUString("win");
442     m_bSupportsOpenGL = true;
443 #if HAVE_FEATURE_SKIA
444     WinSkiaSalGraphicsImpl::prepareSkia();
445 #if SKIA_USE_BITMAP32
446     if (SkiaHelper::isVCLSkiaEnabled())
447         m_bSupportsBitmap32 = true;
448 #endif
449 #endif
450 }
451 
~WinSalInstance()452 WinSalInstance::~WinSalInstance()
453 {
454     ImplFreeSalGDI();
455     DestroyWindow( mhComWnd );
456 #if HAVE_FEATURE_SKIA
457     SkiaHelper::cleanup();
458 #endif
459 }
460 
AfterAppInit()461 void WinSalInstance::AfterAppInit()
462 {
463 // (1) Ideally this would be done at the place that creates the thread, but since this thread is normally
464 // just the default/main thread, that is not possible.
465 // (2) Don't do this on unix, where it causes tools like pstree on Linux to
466 // confusingly report soffice.bin as VCL Main instead.
467     osl_setThreadName("VCL Main");
468 }
469 
ImplSalDispatchMessage(const MSG * pMsg)470 static LRESULT ImplSalDispatchMessage( const MSG* pMsg )
471 {
472     SalData* pSalData = GetSalData();
473     if ( pSalData->mpFirstObject && ImplSalPreDispatchMsg( pMsg ) )
474         return 0;
475     LRESULT lResult = DispatchMessageW( pMsg );
476     if ( pSalData->mpFirstObject )
477         ImplSalPostDispatchMsg( pMsg );
478     return lResult;
479 }
480 
481 // probably can't be static, because of SalTimer friend? (static gives C4211)
ImplSalYield(const bool bWait,const bool bHandleAllCurrentEvents)482 bool ImplSalYield(const bool bWait, const bool bHandleAllCurrentEvents)
483 {
484     // used to abort further message processing on tick count wraps
485     static sal_uInt32 nLastTicks = 0;
486 
487     // we should never yield in m_nNoYieldLock mode!
488     const bool bNoYieldLock = (GetSalData()->mpInstance->m_nNoYieldLock > 0);
489     assert(!bNoYieldLock);
490     if (bNoYieldLock)
491         return false;
492 
493     MSG aMsg;
494     bool bWasMsg = false, bWasTimeoutMsg = false;
495     WinSalTimer* pTimer = static_cast<WinSalTimer*>(ImplGetSVData()->maSchedCtx.mpSalTimer);
496 
497     sal_uInt32 nCurTicks = GetTickCount();
498 
499     do
500     {
501         if (!PeekMessageW(&aMsg, nullptr, 0, 0, PM_REMOVE))
502             break;
503 
504         bWasMsg = true;
505         TranslateMessage(&aMsg);
506         LRESULT nRet = ImplSalDispatchMessage(&aMsg);
507 
508         bWasTimeoutMsg |= (SAL_MSG_TIMER_CALLBACK == aMsg.message) && static_cast<bool>(nRet);
509 
510         if (!bHandleAllCurrentEvents)
511             break;
512 
513         if ((aMsg.time > nCurTicks) && (nLastTicks <= nCurTicks || aMsg.time < nLastTicks))
514             break;
515     }
516     while( true );
517 
518     // 0ms timeouts are handled out-of-bounds to prevent busy-locking the
519     // event loop with timeout messages.
520     // We ensure we never handle more than one timeout per call.
521     // This way we'll always process a normal system message.
522     if ( !bWasTimeoutMsg && pTimer && pTimer->IsDirectTimeout() )
523     {
524         pTimer->ImplHandleElapsedTimer();
525         bWasMsg = true;
526     }
527 
528     nLastTicks = nCurTicks;
529 
530     if ( bWait && !bWasMsg )
531     {
532         switch (GetMessageW(&aMsg, nullptr, 0, 0))
533         {
534             case -1:
535                 SAL_WARN("vcl.schedule", "GetMessageW failed: " << WindowsErrorString(GetLastError()));
536                 // should we std::abort() / SalAbort here?
537                 break;
538             case 0:
539                 SAL_INFO("vcl.schedule", "GetMessageW received WM_QUIT while waiting");
540                 break;
541             default:
542                 bWasMsg = true;
543                 TranslateMessage(&aMsg);
544                 ImplSalDispatchMessage(&aMsg);
545                 break;
546         }
547     }
548 
549     // If we enabled ForceRealTimer mode skipping our direct timeout processing,
550     // mainly because some Windows API call spawns its own nested message loop,
551     // switch back to our own processing (like after window resize or move)
552     if ( pTimer )
553         pTimer->SetForceRealTimer( false );
554 
555     return bWasMsg;
556 }
557 
IsMainThread() const558 bool WinSalInstance::IsMainThread() const
559 {
560     const SalData* pSalData = GetSalData();
561     return pSalData->mnAppThreadId == GetCurrentThreadId();
562 }
563 
DoYield(bool bWait,bool bHandleAllCurrentEvents)564 bool WinSalInstance::DoYield(bool bWait, bool bHandleAllCurrentEvents)
565 {
566     bool bDidWork = false;
567     SolarMutexReleaser aReleaser;
568     if ( !IsMainThread() )
569     {
570         bDidWork = SendMessageW( mhComWnd, SAL_MSG_THREADYIELD,
571                                  WPARAM(false), static_cast<LPARAM>(bHandleAllCurrentEvents) );
572         if ( !bDidWork && bWait )
573         {
574             maWaitingYieldCond.reset();
575             maWaitingYieldCond.wait();
576             bDidWork = true;
577         }
578     }
579     else
580     {
581         bDidWork = ImplSalYield( bWait, bHandleAllCurrentEvents );
582         if ( bDidWork )
583             maWaitingYieldCond.set();
584     }
585 
586     return bDidWork;
587 }
588 
589 namespace
590 {
591 struct NoYieldLockGuard
592 {
NoYieldLockGuard__anonc363b8950311::NoYieldLockGuard593     NoYieldLockGuard()
594         : counter(InSendMessage() ? GetSalData()->mpInstance->m_nNoYieldLock : dummy())
595     {
596         ++counter;
597     }
~NoYieldLockGuard__anonc363b8950311::NoYieldLockGuard598     ~NoYieldLockGuard() { --counter; }
dummy__anonc363b8950311::NoYieldLockGuard599     static decltype(WinSalInstance::m_nNoYieldLock)& dummy()
600     {
601         DBG_TESTSOLARMUTEX(); // called when !InSendMessage()
602         static decltype(WinSalInstance::m_nNoYieldLock) n = 0;
603         return n;
604     }
605     decltype(WinSalInstance::m_nNoYieldLock)& counter;
606 };
607 }
608 
SalComWndProc(HWND,UINT nMsg,WPARAM wParam,LPARAM lParam,bool & rDef)609 LRESULT CALLBACK SalComWndProc( HWND, UINT nMsg, WPARAM wParam, LPARAM lParam, bool& rDef )
610 {
611     LRESULT nRet = 0;
612     WinSalTimer *const pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
613 
614     SAL_INFO("vcl.gdi.wndproc", "SalComWndProc(nMsg=" << nMsg << ", wParam=" << wParam
615                                 << ", lParam=" << lParam << "); inSendMsg: " << InSendMessage());
616 
617     if (ImplGetSVData()->mbDeInit)
618     {
619         SAL_WARN("vcl.gdi.wndproc", "ignoring timer event because we are shutting down");
620         return 0;
621     }
622 
623     switch ( nMsg )
624     {
625         case SAL_MSG_THREADYIELD:
626             assert( !static_cast<bool>(wParam) );
627             nRet = static_cast<LRESULT>(ImplSalYield(
628                 false, static_cast<bool>( lParam ) ));
629             break;
630 
631         case SAL_MSG_STARTTIMER:
632         {
633             auto const nParam = static_cast<sal_uInt64>( lParam );
634             sal_uInt64 nTime = tools::Time::GetSystemTicks();
635             if ( nTime < nParam )
636                 nTime = nParam - nTime;
637             else
638                 nTime = 0;
639             assert( pTimer != nullptr );
640             pTimer->ImplStart( nTime );
641             break;
642         }
643 
644         case SAL_MSG_STOPTIMER:
645             assert( pTimer != nullptr );
646             pTimer->ImplStop();
647             break;
648 
649         case (SAL_MSG_CREATEFRAME):
650             {
651                 NoYieldLockGuard g;
652                 nRet = reinterpret_cast<LRESULT>(
653                     ImplSalCreateFrame(GetSalData()->mpInstance, reinterpret_cast<HWND>(lParam),
654                                        static_cast<SalFrameStyleFlags>(wParam)));
655             }
656             break;
657         case (SAL_MSG_RECREATEHWND):
658             {
659                 NoYieldLockGuard g;
660                 nRet = reinterpret_cast<LRESULT>(ImplSalReCreateHWND(
661                     reinterpret_cast<HWND>(wParam), reinterpret_cast<HWND>(lParam), false));
662             }
663             break;
664         case (SAL_MSG_RECREATECHILDHWND):
665             {
666                 NoYieldLockGuard g;
667                 nRet = reinterpret_cast<LRESULT>(ImplSalReCreateHWND(
668                     reinterpret_cast<HWND>(wParam), reinterpret_cast<HWND>(lParam), true));
669             }
670             break;
671         case (SAL_MSG_DESTROYFRAME):
672             {
673                 NoYieldLockGuard g;
674                 delete reinterpret_cast<SalFrame*>(lParam);
675             }
676             break;
677 
678         case SAL_MSG_DESTROYHWND:
679             // We only destroy the native window here. We do NOT destroy the SalFrame contained
680             // in the structure (GetWindowPtr()).
681             if (DestroyWindow(reinterpret_cast<HWND>(lParam)) == 0)
682             {
683                 OSL_FAIL("DestroyWindow failed!");
684                 // Failure: We remove the SalFrame from the window structure. So we avoid that
685                 // the window structure may contain an invalid pointer, once the SalFrame is deleted.
686                 SetWindowPtr(reinterpret_cast<HWND>(lParam), nullptr);
687             }
688             break;
689 
690         case (SAL_MSG_CREATEOBJECT):
691             {
692                 NoYieldLockGuard g;
693                 nRet = reinterpret_cast<LRESULT>(ImplSalCreateObject(
694                     GetSalData()->mpInstance, reinterpret_cast<WinSalFrame*>(lParam)));
695             }
696             break;
697         case (SAL_MSG_DESTROYOBJECT):
698             {
699                 NoYieldLockGuard g;
700                 delete reinterpret_cast<SalObject*>(lParam);
701             }
702             break;
703         case (SAL_MSG_GETCACHEDDC):
704             {
705                 NoYieldLockGuard g;
706                 nRet = reinterpret_cast<LRESULT>(
707                     GetDCEx(reinterpret_cast<HWND>(wParam), nullptr, 0x00000002L));
708             }
709             break;
710         case (SAL_MSG_RELEASEDC):
711             {
712                 NoYieldLockGuard g;
713                 ReleaseDC(reinterpret_cast<HWND>(wParam), reinterpret_cast<HDC>(lParam));
714             }
715             break;
716 
717         case SAL_MSG_TIMER_CALLBACK:
718             assert( pTimer != nullptr );
719             pTimer->ImplHandleTimerEvent( wParam );
720             break;
721 
722         case WM_TIMER:
723             assert( pTimer != nullptr );
724             pTimer->ImplHandle_WM_TIMER( wParam );
725             break;
726 
727         case SAL_MSG_FORCE_REAL_TIMER:
728             assert(pTimer != nullptr);
729             pTimer->SetForceRealTimer(true);
730             break;
731 
732         case SAL_MSG_DUMMY:
733             break;
734 
735         default:
736             rDef = true;
737             break;
738     }
739 
740     return nRet;
741 }
742 
SalComWndProcW(HWND hWnd,UINT nMsg,WPARAM wParam,LPARAM lParam)743 LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
744 {
745     bool bDef = false;
746     LRESULT nRet = 0;
747     __try
748     {
749         nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
750     }
751     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
752     {
753     }
754     if ( bDef )
755     {
756         if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
757             nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
758     }
759     return nRet;
760 }
761 
AnyInput(VclInputFlags nType)762 bool WinSalInstance::AnyInput( VclInputFlags nType )
763 {
764     if ( nType & VclInputFlags::TIMER )
765     {
766         const WinSalTimer* pTimer = static_cast<WinSalTimer*>( ImplGetSVData()->maSchedCtx.mpSalTimer );
767         if ( pTimer && pTimer->HasTimerElapsed() )
768             return true;
769     }
770 
771     // Note: Do not use PeekMessage(), despite the name it may dispatch events,
772     // even with PM_NOREMOVE specified, which may lead to unwanted recursion.
773 
774     if ( (nType & VCL_INPUT_ANY) == VCL_INPUT_ANY )
775     {
776         // revert bugfix for #108919# which never reported timeouts when called from the timer handler
777         // which made the application completely unresponsive during background formatting
778         if ( GetQueueStatus( QS_ALLEVENTS ))
779             return true;
780     }
781     else
782     {
783         UINT flags = 0;
784 
785         // This code previously considered modifier keys as OTHER,
786         // but that makes this hard to do without PeekMessage,
787         // is inconsistent with the X11 backend, and I see no good reason.
788         if ( nType & VclInputFlags::KEYBOARD )
789             flags |= QS_KEY;
790 
791         if ( nType & VclInputFlags::MOUSE )
792             flags |= QS_MOUSE;
793 
794         if ( nType & VclInputFlags::PAINT )
795             flags |= QS_PAINT;
796 
797         if ( nType & VclInputFlags::TIMER )
798             flags |= QS_TIMER;
799 
800         if( nType & VclInputFlags::OTHER )
801             flags |= QS_ALLEVENTS & ~QS_KEY & ~QS_MOUSE & ~QS_PAINT & ~QS_TIMER;
802 
803         if( GetQueueStatus( flags ))
804             return true;
805     }
806 
807     return false;
808 }
809 
CreateChildFrame(SystemParentData * pSystemParentData,SalFrameStyleFlags nSalFrameStyle)810 SalFrame* WinSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, SalFrameStyleFlags nSalFrameStyle )
811 {
812     // to switch to Main-Thread
813     return reinterpret_cast<SalFrame*>(static_cast<sal_IntPtr>(SendMessageW( mhComWnd, SAL_MSG_CREATEFRAME, static_cast<WPARAM>(nSalFrameStyle), reinterpret_cast<LPARAM>(pSystemParentData->hWnd) )));
814 }
815 
CreateFrame(SalFrame * pParent,SalFrameStyleFlags nSalFrameStyle)816 SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nSalFrameStyle )
817 {
818     // to switch to Main-Thread
819     HWND hWndParent;
820     if ( pParent )
821         hWndParent = static_cast<WinSalFrame*>(pParent)->mhWnd;
822     else
823         hWndParent = nullptr;
824     return reinterpret_cast<SalFrame*>(static_cast<sal_IntPtr>(SendMessageW( mhComWnd, SAL_MSG_CREATEFRAME, static_cast<WPARAM>(nSalFrameStyle), reinterpret_cast<LPARAM>(hWndParent) )));
825 }
826 
DestroyFrame(SalFrame * pFrame)827 void WinSalInstance::DestroyFrame( SalFrame* pFrame )
828 {
829     OpenGLContext::prepareForYield();
830     SendMessageW( mhComWnd, SAL_MSG_DESTROYFRAME, 0, reinterpret_cast<LPARAM>(pFrame) );
831 }
832 
CreateObject(SalFrame * pParent,SystemWindowData *,bool)833 SalObject* WinSalInstance::CreateObject( SalFrame* pParent,
834                                          SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows
835                                          bool /*bShow*/ )
836 {
837     // to switch to Main-Thread
838     return reinterpret_cast<SalObject*>(static_cast<sal_IntPtr>(SendMessageW( mhComWnd, SAL_MSG_CREATEOBJECT, 0, reinterpret_cast<LPARAM>(static_cast<WinSalFrame*>(pParent)) )));
839 }
840 
DestroyObject(SalObject * pObject)841 void WinSalInstance::DestroyObject( SalObject* pObject )
842 {
843     SendMessageW( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, reinterpret_cast<LPARAM>(pObject) );
844 }
845 
GetConnectionIdentifier()846 OUString WinSalInstance::GetConnectionIdentifier()
847 {
848     return OUString();
849 }
850 
851 /** Add a file to the system shells recent document list if there is any.
852       This function may have no effect under Unix because there is no
853       standard API among the different desktop managers.
854 
855       @param aFileUrl
856                 The file url of the document.
857 */
AddToRecentDocumentList(const OUString & rFileUrl,const OUString &,const OUString & rDocumentService)858 void WinSalInstance::AddToRecentDocumentList(const OUString& rFileUrl, const OUString& /*rMimeType*/, const OUString& rDocumentService)
859 {
860     if (Application::IsHeadlessModeEnabled())
861         return;
862 
863     OUString system_path;
864     osl::FileBase::RC rc = osl::FileBase::getSystemPathFromFileURL(rFileUrl, system_path);
865 
866     OSL_ENSURE(osl::FileBase::E_None == rc, "Invalid file url");
867 
868     if (osl::FileBase::E_None == rc)
869     {
870         IShellItem* pShellItem = nullptr;
871 
872         HRESULT hr = SHCreateItemFromParsingName(o3tl::toW(system_path.getStr()), nullptr, IID_PPV_ARGS(&pShellItem));
873 
874         if ( SUCCEEDED(hr) && pShellItem )
875         {
876             OUString sApplicationName;
877 
878             if ( rDocumentService == "com.sun.star.text.TextDocument" ||
879                  rDocumentService == "com.sun.star.text.GlobalDocument" ||
880                  rDocumentService == "com.sun.star.text.WebDocument" ||
881                  rDocumentService == "com.sun.star.xforms.XMLFormDocument" )
882                 sApplicationName = "Writer";
883             else if ( rDocumentService == "com.sun.star.sheet.SpreadsheetDocument" ||
884                  rDocumentService == "com.sun.star.chart2.ChartDocument" )
885                 sApplicationName = "Calc";
886             else if ( rDocumentService == "com.sun.star.presentation.PresentationDocument" )
887                 sApplicationName = "Impress";
888             else if ( rDocumentService == "com.sun.star.drawing.DrawingDocument" )
889                 sApplicationName = "Draw";
890             else if ( rDocumentService == "com.sun.star.formula.FormulaProperties" )
891                 sApplicationName = "Math";
892             else if ( rDocumentService == "com.sun.star.sdb.DatabaseDocument" ||
893                  rDocumentService == "com.sun.star.sdb.OfficeDatabaseDocument" ||
894                  rDocumentService == "com.sun.star.sdb.RelationDesign" ||
895                  rDocumentService == "com.sun.star.sdb.QueryDesign" ||
896                  rDocumentService == "com.sun.star.sdb.TableDesign" ||
897                  rDocumentService == "com.sun.star.sdb.DataSourceBrowser" )
898                 sApplicationName = "Base";
899 
900             if ( !sApplicationName.isEmpty() )
901             {
902                 OUString sApplicationID("TheDocumentFoundation.LibreOffice." + sApplicationName);
903 
904                 SHARDAPPIDINFO info;
905                 info.psi = pShellItem;
906                 info.pszAppID = o3tl::toW(sApplicationID.getStr());
907 
908                 SHAddToRecentDocs ( SHARD_APPIDINFO, &info );
909                 return;
910             }
911         }
912         // For whatever reason, we could not use the SHARD_APPIDINFO semantics
913         SHAddToRecentDocs(SHARD_PATHW, system_path.getStr());
914     }
915 }
916 
CreateSalTimer()917 SalTimer* WinSalInstance::CreateSalTimer()
918 {
919     return new WinSalTimer();
920 }
921 
CreateSalBitmap()922 std::shared_ptr<SalBitmap> WinSalInstance::CreateSalBitmap()
923 {
924 #if HAVE_FEATURE_SKIA
925     if (SkiaHelper::isVCLSkiaEnabled())
926         return std::make_shared<SkiaSalBitmap>();
927     else
928 #endif
929         return std::make_shared<WinSalBitmap>();
930 }
931 
WorkaroundExceptionHandlingInUSER32Lib(int,LPEXCEPTION_POINTERS pExceptionInfo)932 int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo)
933 {
934     // Decide if an exception is a c++ (mostly UNO) exception or a process violation.
935     // Depending on this information we pass process violations directly to our signal handler ...
936     // and c++ (UNO) exceptions are sended to the following code on the current stack.
937     // Problem behind: user32.dll sometime consumes exceptions/process violations .-)
938     // see also #112221#
939 
940     static const DWORD EXCEPTION_MSC_CPP_EXCEPTION = 0xE06D7363;
941 
942     if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_MSC_CPP_EXCEPTION)
943         return EXCEPTION_CONTINUE_SEARCH;
944 
945     return UnhandledExceptionFilter( pExceptionInfo );
946 }
947 
948 typedef LONG NTSTATUS;
949 typedef NTSTATUS(WINAPI* RtlGetVersion_t)(PRTL_OSVERSIONINFOW);
950 constexpr NTSTATUS STATUS_SUCCESS = 0x00000000;
951 
getWinArch()952 static OUString getWinArch()
953 {
954     USHORT nNativeMachine = IMAGE_FILE_MACHINE_UNKNOWN;
955 
956     using LPFN_ISWOW64PROCESS2 = BOOL(WINAPI*)(HANDLE, USHORT*, USHORT*);
957     auto fnIsWow64Process2 = reinterpret_cast<LPFN_ISWOW64PROCESS2>(
958         GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process2"));
959     if (fnIsWow64Process2)
960         fnIsWow64Process2(GetCurrentProcess(), &o3tl::temporary(USHORT()), &nNativeMachine);
961 
962     if (nNativeMachine == IMAGE_FILE_MACHINE_UNKNOWN)
963     {
964 #if _WIN64
965 
966         nNativeMachine = IMAGE_FILE_MACHINE_AMD64;
967 
968 #else
969 
970         BOOL isWow64 = FALSE;
971 
972         IsWow64Process(GetCurrentProcess(), &isWow64);
973 
974         if (isWow64)
975             nNativeMachine = IMAGE_FILE_MACHINE_AMD64; // 32-bit process on 64-bit Windows
976         else
977             nNativeMachine = IMAGE_FILE_MACHINE_I386;
978 
979 #endif
980     }
981 
982     switch (nNativeMachine)
983     {
984         case IMAGE_FILE_MACHINE_I386:
985             return u" X86_32"_ustr;
986         case IMAGE_FILE_MACHINE_R3000:
987             return u" R3000"_ustr;
988         case IMAGE_FILE_MACHINE_R4000:
989             return u" R4000"_ustr;
990         case IMAGE_FILE_MACHINE_R10000:
991             return u" R10000"_ustr;
992         case IMAGE_FILE_MACHINE_WCEMIPSV2:
993             return u" WCEMIPSV2"_ustr;
994         case IMAGE_FILE_MACHINE_ALPHA:
995             return u" ALPHA"_ustr;
996         case IMAGE_FILE_MACHINE_SH3:
997             return u" SH3"_ustr;
998         case IMAGE_FILE_MACHINE_SH3DSP:
999             return u" SH3DSP"_ustr;
1000         case IMAGE_FILE_MACHINE_SH3E:
1001             return u" SH3E"_ustr;
1002         case IMAGE_FILE_MACHINE_SH4:
1003             return u" SH4"_ustr;
1004         case IMAGE_FILE_MACHINE_SH5:
1005             return u" SH5"_ustr;
1006         case IMAGE_FILE_MACHINE_ARM:
1007             return u" ARM"_ustr;
1008         case IMAGE_FILE_MACHINE_THUMB:
1009             return u" THUMB"_ustr;
1010         case IMAGE_FILE_MACHINE_ARMNT:
1011             return u" ARMNT"_ustr;
1012         case IMAGE_FILE_MACHINE_AM33:
1013             return u" AM33"_ustr;
1014         case IMAGE_FILE_MACHINE_POWERPC:
1015             return u" POWERPC"_ustr;
1016         case IMAGE_FILE_MACHINE_POWERPCFP:
1017             return u" POWERPCFP"_ustr;
1018         case IMAGE_FILE_MACHINE_IA64:
1019             return u" IA64"_ustr;
1020         case IMAGE_FILE_MACHINE_MIPS16:
1021             return u" MIPS16"_ustr;
1022         case IMAGE_FILE_MACHINE_ALPHA64:
1023             return u" ALPHA64"_ustr;
1024         case IMAGE_FILE_MACHINE_MIPSFPU:
1025             return u" MIPSFPU"_ustr;
1026         case IMAGE_FILE_MACHINE_MIPSFPU16:
1027             return u" MIPSFPU16"_ustr;
1028         case IMAGE_FILE_MACHINE_TRICORE:
1029             return u" TRICORE"_ustr;
1030         case IMAGE_FILE_MACHINE_CEF:
1031             return u" CEF"_ustr;
1032         case IMAGE_FILE_MACHINE_EBC:
1033             return u" EBC"_ustr;
1034         case IMAGE_FILE_MACHINE_AMD64:
1035             return u" X86_64"_ustr;
1036         case IMAGE_FILE_MACHINE_M32R:
1037             return u" M32R"_ustr;
1038         case IMAGE_FILE_MACHINE_ARM64:
1039             return u" ARM64"_ustr;
1040         case IMAGE_FILE_MACHINE_CEE:
1041             return u" CEE"_ustr;
1042         default:
1043             assert(!"Yet unhandled case");
1044             return OUString();
1045     }
1046 }
1047 
getOSVersionString(const OUString & aNtVersionString,DWORD nBuildNumber)1048 static OUString getOSVersionString(const OUString& aNtVersionString, DWORD nBuildNumber)
1049 {
1050     OUStringBuffer result = u"Windows";
1051     if (aNtVersionString == "6.1")
1052         result.append(" 7 Service Pack 1");
1053     else if (aNtVersionString == "6.2")
1054         result.append(" 8");
1055     else if (aNtVersionString == "6.3")
1056         result.append(" 8.1");
1057     else if (aNtVersionString == "10.0")
1058     {
1059         if (nBuildNumber >= 22000)
1060             result.append(" 11");
1061         else
1062             result.append(" 10");
1063     }
1064     else // We don't know what Windows it is
1065         result.append(" unknown");
1066 
1067     result.append(getWinArch());
1068 
1069     if (!aNtVersionString.isEmpty() || nBuildNumber)
1070     {
1071         result.append(" (");
1072         if (!aNtVersionString.isEmpty())
1073         {
1074             result.append(aNtVersionString);
1075             if (nBuildNumber)
1076                 result.append(" ");
1077         }
1078         if (nBuildNumber)
1079             result.append("build " + OUString::number(nBuildNumber));
1080         result.append(")");
1081     }
1082 
1083     return result.makeStringAndClear();
1084 }
1085 
getOSVersion()1086 OUString WinSalInstance::getOSVersion()
1087 {
1088     static const OUString result = []
1089     {
1090         // GetVersion(Ex) and VersionHelpers (based on VerifyVersionInfo) API are
1091         // subject to manifest-based behavior since Windows 8.1, so give wrong results.
1092         // Another approach would be to use NetWkstaGetInfo, but that has some small
1093         // reported delays (some milliseconds), and might get slower in domains with
1094         // poor network connections.
1095         // So go with a solution described at https://msdn.microsoft.com/en-us/library/ms724429
1096         bool bHaveVerFromKernel32 = false;
1097         OUString aNtVersion;
1098         if (HMODULE h_kernel32 = GetModuleHandleW(L"kernel32.dll"))
1099         {
1100             wchar_t szPath[MAX_PATH];
1101             DWORD dwCount = GetModuleFileNameW(h_kernel32, szPath, SAL_N_ELEMENTS(szPath));
1102             if (dwCount != 0 && dwCount < SAL_N_ELEMENTS(szPath))
1103             {
1104                 dwCount = GetFileVersionInfoSizeW(szPath, nullptr);
1105                 if (dwCount != 0)
1106                 {
1107                     std::unique_ptr<char[]> ver(new char[dwCount]);
1108                     if (GetFileVersionInfoW(szPath, 0, dwCount, ver.get()) != FALSE)
1109                     {
1110                         void* pBlock = nullptr;
1111                         UINT dwBlockSz = 0;
1112                         if (VerQueryValueW(ver.get(), L"\\", &pBlock, &dwBlockSz) != FALSE
1113                             && dwBlockSz >= sizeof(VS_FIXEDFILEINFO))
1114                         {
1115                             VS_FIXEDFILEINFO* vi1 = static_cast<VS_FIXEDFILEINFO*>(pBlock);
1116                             aNtVersion = (OUString::number(HIWORD(vi1->dwProductVersionMS)) + "."
1117                                           + OUString::number(LOWORD(vi1->dwProductVersionMS)));
1118                             bHaveVerFromKernel32 = true;
1119                         }
1120                     }
1121                 }
1122             }
1123         }
1124         // Now use RtlGetVersion (which is not subject to deprecation for GetVersion(Ex) API)
1125         // to get build number and SP info
1126         bool bHaveVerFromRtlGetVersion = false;
1127         DWORD nBuildNumber = 0;
1128         if (HMODULE h_ntdll = GetModuleHandleW(L"ntdll.dll"))
1129         {
1130             if (auto RtlGetVersion
1131                 = reinterpret_cast<RtlGetVersion_t>(GetProcAddress(h_ntdll, "RtlGetVersion")))
1132             {
1133                 RTL_OSVERSIONINFOW vi2{}; // initialize with zeroes - a better alternative to memset
1134                 vi2.dwOSVersionInfoSize = sizeof(vi2);
1135                 if (STATUS_SUCCESS == RtlGetVersion(&vi2))
1136                 {
1137                     if (!bHaveVerFromKernel32) // we failed above; let's hope this would be useful
1138                         aNtVersion = (OUString::number(vi2.dwMajorVersion) + "."
1139                                       + OUString::number(vi2.dwMinorVersion));
1140                     nBuildNumber = vi2.dwBuildNumber;
1141                     bHaveVerFromRtlGetVersion = true;
1142                 }
1143             }
1144         }
1145         return getOSVersionString(aNtVersion, nBuildNumber);
1146     }();
1147     return result;
1148 }
1149 
BeforeAbort(const OUString &,bool)1150 void WinSalInstance::BeforeAbort(const OUString&, bool)
1151 {
1152     ImplFreeSalGDI();
1153 }
1154 
ImplCreateDragSource(const SystemEnvData * pSysEnv)1155 css::uno::Reference<css::uno::XInterface> WinSalInstance::ImplCreateDragSource(const SystemEnvData* pSysEnv)
1156 {
1157     return vcl::OleDnDHelper(new DragSource(comphelper::getProcessComponentContext()),
1158                              reinterpret_cast<sal_IntPtr>(pSysEnv->hWnd), vcl::DragOrDrop::Drag);
1159 }
1160 
ImplCreateDropTarget(const SystemEnvData * pSysEnv)1161 css::uno::Reference<css::uno::XInterface> WinSalInstance::ImplCreateDropTarget(const SystemEnvData* pSysEnv)
1162 {
1163     return vcl::OleDnDHelper(new DropTarget(comphelper::getProcessComponentContext()),
1164                              reinterpret_cast<sal_IntPtr>(pSysEnv->hWnd), vcl::DragOrDrop::Drop);
1165 }
1166 
1167 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1168