xref: /trunk/main/vcl/win/source/app/salinst.cxx (revision 9f62ea84)
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_vcl.hxx"
26 
27 #include <string.h>
28 #include <tools/svwin.h>
29 #ifdef WNT
30 #include <process.h>
31 #endif
32 #ifdef __MINGW32__
33 #include <excpt.h>
34 #endif
35 
36 #include <osl/file.hxx>
37 
38 #include <vos/mutex.hxx>
39 
40 #include <tools/solarmutex.hxx>
41 #include <tools/debug.hxx>
42 
43 #include <vcl/timer.hxx>
44 #include <vcl/apptypes.hxx>
45 
46 #include <win/wincomp.hxx>
47 #include <win/salids.hrc>
48 #include <win/saldata.hxx>
49 #include <win/salinst.h>
50 #include <win/salframe.h>
51 #include <win/salobj.h>
52 #include <win/saltimer.h>
53 #include <win/salbmp.h>
54 
55 #include <salimestatus.hxx>
56 #include <salsys.hxx>
57 
58 #ifndef min
59 #define min(a,b)	(((a) < (b)) ? (a) : (b))
60 #endif
61 #ifndef max
62 #define max(a,b)	(((a) > (b)) ? (a) : (b))
63 #endif
64 
65 #if defined _MSC_VER
66 #pragma warning(push, 1)
67 #pragma warning( disable: 4917 )
68 #endif
69 
70 #include <GdiPlus.h>
71 #include <GdiPlusEnums.h>
72 #include <GdiPlusColor.h>
73 #include <Shlobj.h>
74 
75 #if defined _MSC_VER
76 #pragma warning(pop)
77 #endif
78 
79 // =======================================================================
80 
81 void SalAbort( const XubString& rErrorText )
82 {
83 	ImplFreeSalGDI();
84 
85 	if ( !rErrorText.Len() )
86 	{
87 		// #112255# make sure crash reporter is triggered
88 		RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
89 		FatalAppExit( 0, "Application Error" );
90 	}
91 	else
92 	{
93 		// #112255# make sure crash reporter is triggered
94 		RaiseException( 0, EXCEPTION_NONCONTINUABLE, 0, NULL );
95 		ByteString aErrorText( ImplSalGetWinAnsiString( rErrorText ) );
96 		FatalAppExit( 0, aErrorText.GetBuffer() );
97 	}
98 }
99 
100 // =======================================================================
101 
102 LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
103 LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam );
104 
105 // =======================================================================
106 
107 class SalYieldMutex : public vos::OMutex
108 {
109 public: // for ImplSalYield()
110 	WinSalInstance*             mpInstData;
111 	sal_uLong                       mnCount;
112 	DWORD                       mnThreadId;
113 
114 public:
115 								SalYieldMutex( WinSalInstance* pInstData );
116 
117 	virtual void SAL_CALL       acquire();
118 	virtual void SAL_CALL       release();
119 	virtual sal_Bool SAL_CALL   tryToAcquire();
120 
121 	sal_uLong                       GetAcquireCount( sal_uLong nThreadId );
122 };
123 
124 // -----------------------------------------------------------------------
125 
126 SalYieldMutex::SalYieldMutex( WinSalInstance* pInstData )
127 {
128 	mpInstData  = pInstData;
129 	mnCount     = 0;
130 	mnThreadId  = 0;
131 }
132 
133 // -----------------------------------------------------------------------
134 
135 void SAL_CALL SalYieldMutex::acquire()
136 {
137 	OMutex::acquire();
138 	mnCount++;
139 	mnThreadId = GetCurrentThreadId();
140 }
141 
142 // -----------------------------------------------------------------------
143 
144 void SAL_CALL SalYieldMutex::release()
145 {
146 	DWORD nThreadId = GetCurrentThreadId();
147 	if ( mnThreadId != nThreadId )
148 		OMutex::release();
149 	else
150 	{
151 		SalData* pSalData = GetSalData();
152 		if ( pSalData->mnAppThreadId != nThreadId )
153 		{
154 			if ( mnCount == 1 )
155 			{
156 				// If we don't call these message, the Output from the
157 				// Java clients doesn't come in the right order
158 				GdiFlush();
159 
160 				mpInstData->mpSalWaitMutex->acquire();
161 				if ( mpInstData->mnYieldWaitCount )
162 					ImplPostMessage( mpInstData->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
163 				mnThreadId = 0;
164 				mnCount--;
165 				OMutex::release();
166 				mpInstData->mpSalWaitMutex->release();
167 			}
168 			else
169 			{
170 				mnCount--;
171 				OMutex::release();
172 			}
173 		}
174 		else
175 		{
176 			if ( mnCount == 1 )
177 				mnThreadId = 0;
178 			mnCount--;
179 			OMutex::release();
180 		}
181 	}
182 }
183 
184 // -----------------------------------------------------------------------
185 
186 sal_Bool SAL_CALL SalYieldMutex::tryToAcquire()
187 {
188 	if( OMutex::tryToAcquire() )
189 	{
190 		mnCount++;
191 		mnThreadId = GetCurrentThreadId();
192 		return sal_True;
193 	}
194 	else
195 		return sal_False;
196 }
197 
198 // -----------------------------------------------------------------------
199 
200 sal_uLong SalYieldMutex::GetAcquireCount( sal_uLong nThreadId )
201 {
202 	if ( nThreadId == mnThreadId )
203 		return mnCount;
204 	else
205 		return 0;
206 }
207 
208 // -----------------------------------------------------------------------
209 
210 void ImplSalYieldMutexAcquireWithWait()
211 {
212 	WinSalInstance* pInst = GetSalData()->mpFirstInstance;
213 	if ( !pInst )
214 		return;
215 
216 	// If we are the main thread, then we must wait with wait, because
217 	// in if we don't reschedule, then we create deadlocks if a Windows
218 	// Function is called from another thread. If we arn't the main thread,
219 	// than we call qcquire directly.
220 	DWORD nThreadId = GetCurrentThreadId();
221 	SalData* pSalData = GetSalData();
222 	if ( pSalData->mnAppThreadId == nThreadId )
223 	{
224 		// Wenn wir den Mutex nicht bekommen, muessen wir solange
225 		// warten, bis wir Ihn bekommen
226 		sal_Bool bAcquire = FALSE;
227 		do
228 		{
229 			if ( pInst->mpSalYieldMutex->tryToAcquire() )
230 				bAcquire = TRUE;
231 			else
232 			{
233 				pInst->mpSalWaitMutex->acquire();
234 				if ( pInst->mpSalYieldMutex->tryToAcquire() )
235 				{
236 					bAcquire = TRUE;
237 					pInst->mpSalWaitMutex->release();
238 				}
239 				else
240 				{
241 					pInst->mnYieldWaitCount++;
242 					pInst->mpSalWaitMutex->release();
243 					MSG aTmpMsg;
244 					ImplGetMessage( &aTmpMsg, pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, SAL_MSG_RELEASEWAITYIELD );
245 					pInst->mnYieldWaitCount--;
246 					if ( pInst->mnYieldWaitCount )
247 						ImplPostMessage( pInst->mhComWnd, SAL_MSG_RELEASEWAITYIELD, 0, 0 );
248 				}
249 			}
250 		}
251 		while ( !bAcquire );
252 	}
253 	else
254 		pInst->mpSalYieldMutex->acquire();
255 }
256 
257 // -----------------------------------------------------------------------
258 
259 sal_Bool ImplSalYieldMutexTryToAcquire()
260 {
261 	WinSalInstance* pInst = GetSalData()->mpFirstInstance;
262 	if ( pInst )
263 		return pInst->mpSalYieldMutex->tryToAcquire();
264 	else
265 		return FALSE;
266 }
267 
268 // -----------------------------------------------------------------------
269 
270 void ImplSalYieldMutexAcquire()
271 {
272 	WinSalInstance* pInst = GetSalData()->mpFirstInstance;
273 	if ( pInst )
274 		pInst->mpSalYieldMutex->acquire();
275 }
276 
277 // -----------------------------------------------------------------------
278 
279 void ImplSalYieldMutexRelease()
280 {
281 	WinSalInstance* pInst = GetSalData()->mpFirstInstance;
282 	if ( pInst )
283 	{
284 		GdiFlush();
285 		pInst->mpSalYieldMutex->release();
286 	}
287 }
288 
289 // -----------------------------------------------------------------------
290 
291 sal_uLong ImplSalReleaseYieldMutex()
292 {
293 	WinSalInstance* pInst = GetSalData()->mpFirstInstance;
294 	if ( !pInst )
295 		return 0;
296 
297 	SalYieldMutex*  pYieldMutex = pInst->mpSalYieldMutex;
298 	sal_uLong           nCount = pYieldMutex->GetAcquireCount( GetCurrentThreadId() );
299 	sal_uLong           n = nCount;
300 	while ( n )
301 	{
302 		pYieldMutex->release();
303 		n--;
304 	}
305 
306 	return nCount;
307 }
308 
309 // -----------------------------------------------------------------------
310 
311 void ImplSalAcquireYieldMutex( sal_uLong nCount )
312 {
313 	WinSalInstance* pInst = GetSalData()->mpFirstInstance;
314 	if ( !pInst )
315 		return;
316 
317 	SalYieldMutex*  pYieldMutex = pInst->mpSalYieldMutex;
318 	while ( nCount )
319 	{
320 		pYieldMutex->acquire();
321 		nCount--;
322 	}
323 }
324 
325 // -----------------------------------------------------------------------
326 
327 bool WinSalInstance::CheckYieldMutex()
328 {
329     bool bRet = true;
330 	SalData*    pSalData = GetSalData();
331 	DWORD       nCurThreadId = GetCurrentThreadId();
332 	if ( pSalData->mnAppThreadId != nCurThreadId )
333 	{
334 		if ( pSalData->mpFirstInstance )
335 		{
336 			SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
337 			if ( pYieldMutex->mnThreadId != nCurThreadId )
338 			{
339 			    bRet = false;
340 			}
341 		}
342 	}
343 	else
344 	{
345 		if ( pSalData->mpFirstInstance )
346 		{
347 			SalYieldMutex* pYieldMutex = pSalData->mpFirstInstance->mpSalYieldMutex;
348 			if ( pYieldMutex->mnThreadId != nCurThreadId )
349 			{
350 			    bRet = false;
351 			}
352 		}
353 	}
354 	return bRet;
355 }
356 
357 // =======================================================================
358 
359 void SalData::initKeyCodeMap()
360 {
361 	UINT nKey = 0xffffffff;
362 	#define initKey( a, b )\
363 		nKey = LOWORD( VkKeyScan( a ) );\
364 		if( nKey < 0xffff )\
365 			maVKMap[ nKey ] = b;
366 
367 	initKey( '+', KEY_ADD );
368 	initKey( '-', KEY_SUBTRACT );
369 	initKey( '*', KEY_MULTIPLY );
370 	initKey( '/', KEY_DIVIDE );
371 	initKey( '.', KEY_POINT );
372 	initKey( ',', KEY_COMMA );
373 	initKey( '<', KEY_LESS );
374 	initKey( '>', KEY_GREATER );
375 	initKey( '=', KEY_EQUAL );
376 	initKey( '~', KEY_TILDE );
377 	initKey( '`', KEY_QUOTELEFT );
378 }
379 
380 // =======================================================================
381 // -------
382 // SalData
383 // -------
384 
385 SalData::SalData()
386 {
387 	mhInst = 0;                 // default instance handle
388 	mhPrevInst = 0;             // previous instance handle
389 	mnCmdShow = 0;              // default frame show style
390 	mhDitherPal = 0;            // dither palette
391 	mhDitherDIB = 0;            // dither memory handle
392 	mpDitherDIB = 0;            // dither memory
393 	mpDitherDIBData = 0;        // beginning of DIB data
394 	mpDitherDiff = 0;           // Dither mapping table
395 	mpDitherLow = 0;            // Dither mapping table
396 	mpDitherHigh = 0;           // Dither mapping table
397 	mnTimerMS = 0;              // Current Time (in MS) of the Timer
398 	mnTimerOrgMS = 0;           // Current Original Time (in MS)
399 	mnNextTimerTime = 0;
400 	mnLastEventTime = 0;
401 	mnTimerId = 0;              // windows timer id
402 	mbInTimerProc = FALSE;      // timer event is currently being dispatched
403 	mhSalObjMsgHook = 0;        // hook to get interesting msg for SalObject
404 	mhWantLeaveMsg = 0;         // window handle, that want a MOUSELEAVE message
405 	mpMouseLeaveTimer = 0;      // Timer for MouseLeave Test
406 	mpFirstInstance = 0;        // pointer of first instance
407 	mpFirstFrame = 0;           // pointer of first frame
408 	mpFirstObject = 0;          // pointer of first object window
409 	mpFirstVD = 0;              // first VirDev
410 	mpFirstPrinter = 0;         // first printing printer
411 	mpHDCCache = 0;             // Cache for three DC's
412 	mh50Bmp = 0;                // 50% Bitmap
413 	mh50Brush = 0;              // 50% Brush
414 	int i;
415 	for(i=0; i<MAX_STOCKPEN; i++)
416 	{
417 		maStockPenColorAry[i] = 0;
418 		mhStockPenAry[i] = 0;
419 	}
420 	for(i=0; i<MAX_STOCKBRUSH; i++)
421 	{
422 		maStockBrushColorAry[i] = 0;
423 		mhStockBrushAry[i] = 0;
424 	}
425 	mnStockPenCount = 0;        // count of static pens
426 	mnStockBrushCount = 0;      // count of static brushes
427 	mnSalObjWantKeyEvt = 0;     // KeyEvent, welcher vom SalObj-Hook verarbeitet werden soll
428 	mnCacheDCInUse = 0;         // count of CacheDC in use
429 	mbObjClassInit = FALSE;     // is SALOBJECTCLASS initialised
430 	mbInPalChange = FALSE;      // is in WM_QUERYNEWPALETTE
431 	mnAppThreadId = 0;          // Id from Applikation-Thread
432 	mbScrSvrEnabled = FALSE;    // ScreenSaver enabled
433 	mnSageStatus = 0;           // status of Sage-DLL (DISABLE_AGENT == nicht vorhanden)
434 	mpSageEnableProc = 0;       // funktion to deactivate the system agent
435 	mpFirstIcon = 0;            // icon cache, points to first icon, NULL if none
436 	mpTempFontItem = 0;
437 	mbThemeChanged = FALSE;     // true if visual theme was changed: throw away theme handles
438 	mbThemeMenuSupport = FALSE;
439 
440     // init with NULL
441     gdiplusToken = 0;
442     maDwmLib     = 0;
443     mpDwmIsCompositionEnabled = 0;
444 
445 	initKeyCodeMap();
446 
447 	SetSalData( this );
448 	initNWF();
449 }
450 
451 SalData::~SalData()
452 {
453 	deInitNWF();
454 	SetSalData( NULL );
455 }
456 
457 void InitSalData()
458 {
459 	SalData* pSalData = new SalData;
460 	CoInitialize(0);
461 
462     // init GDIPlus
463     static Gdiplus::GdiplusStartupInput gdiplusStartupInput;
464     Gdiplus::GdiplusStartup(&pSalData->gdiplusToken, &gdiplusStartupInput, NULL);
465 }
466 
467 
468 void DeInitSalData()
469 {
470 	CoUninitialize();
471 	SalData* pSalData = GetSalData();
472 
473     // deinit GDIPlus
474     if(pSalData)
475     {
476         Gdiplus::GdiplusShutdown(pSalData->gdiplusToken);
477     }
478 
479     delete pSalData;
480 }
481 
482 // -----------------------------------------------------------------------
483 
484 void InitSalMain()
485 {
486 	// remember data, copied from WinMain
487 	SalData* pData = GetAppSalData();
488 	if ( pData )    // Im AppServer NULL
489 	{
490 		STARTUPINFO aSI;
491 		aSI.cb = sizeof( aSI );
492 		GetStartupInfo( &aSI );
493 		pData->mhInst                   = GetModuleHandle( NULL );
494 		pData->mhPrevInst               = NULL;
495 		pData->mnCmdShow                = aSI.wShowWindow;
496 	}
497 }
498 
499 void DeInitSalMain()
500 {
501 }
502 
503 // -----------------------------------------------------------------------
504 
505 SalInstance* CreateSalInstance()
506 {
507 	SalData* pSalData = GetSalData();
508 
509 	// determine the windows version
510 	aSalShlData.mbWXP        = 0;
511     aSalShlData.mbWPrinter   = 0;
512 	WORD nVer = (WORD)GetVersion();
513 	aSalShlData.mnVersion = (((WORD)LOBYTE(nVer)) * 100) + HIBYTE(nVer);
514 	if ( aSalShlData.mnVersion >= 400 )
515 		aSalShlData.mbW40 = 1;
516     rtl_zeroMemory( &aSalShlData.maVersionInfo, sizeof(aSalShlData.maVersionInfo) );
517 	aSalShlData.maVersionInfo.dwOSVersionInfoSize = sizeof( aSalShlData.maVersionInfo );
518 	if ( GetVersionEx( &aSalShlData.maVersionInfo ) )
519 	{
520 		if ( aSalShlData.maVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
521 		{
522 			// Windows XP ?
523 			if ( aSalShlData.maVersionInfo.dwMajorVersion > 5 ||
524 			   ( aSalShlData.maVersionInfo.dwMajorVersion == 5 && aSalShlData.maVersionInfo.dwMinorVersion >= 1 ) )
525 				aSalShlData.mbWXP = 1;
526             if( aSalShlData.maVersionInfo.dwMajorVersion >= 5 )
527                 aSalShlData.mbWPrinter = 1;
528 		}
529 	}
530 
531 	pSalData->mnAppThreadId = GetCurrentThreadId();
532 
533 	// register frame class
534 	if ( !pSalData->mhPrevInst )
535 	{
536 			WNDCLASSEXW aWndClassEx;
537 			aWndClassEx.cbSize          = sizeof( aWndClassEx );
538 			aWndClassEx.style           = CS_OWNDC;
539 			aWndClassEx.lpfnWndProc     = SalFrameWndProcW;
540 			aWndClassEx.cbClsExtra      = 0;
541 			aWndClassEx.cbWndExtra      = SAL_FRAME_WNDEXTRA;
542 			aWndClassEx.hInstance       = pSalData->mhInst;
543 			aWndClassEx.hCursor         = 0;
544 			aWndClassEx.hbrBackground   = 0;
545 			aWndClassEx.lpszMenuName    = 0;
546 			aWndClassEx.lpszClassName   = SAL_FRAME_CLASSNAMEW;
547 			ImplLoadSalIcon( SAL_RESID_ICON_DEFAULT, aWndClassEx.hIcon, aWndClassEx.hIconSm );
548 			if ( !RegisterClassExW( &aWndClassEx ) )
549 				return NULL;
550 
551 			aWndClassEx.hIcon           = 0;
552 			aWndClassEx.hIconSm         = 0;
553 			aWndClassEx.style          |= CS_SAVEBITS;
554 			aWndClassEx.lpszClassName   = SAL_SUBFRAME_CLASSNAMEW;
555 			if ( !RegisterClassExW( &aWndClassEx ) )
556 				return NULL;
557 
558 			// shadow effect for popups on XP
559 			if( aSalShlData.mbWXP )
560 				aWndClassEx.style       |= CS_DROPSHADOW;
561 			aWndClassEx.lpszClassName   = SAL_TMPSUBFRAME_CLASSNAMEW;
562 			if ( !RegisterClassExW( &aWndClassEx ) )
563 				return NULL;
564 
565 			aWndClassEx.style           = 0;
566 			aWndClassEx.lpfnWndProc     = SalComWndProcW;
567 			aWndClassEx.cbWndExtra      = 0;
568 			aWndClassEx.lpszClassName   = SAL_COM_CLASSNAMEW;
569 			if ( !RegisterClassExW( &aWndClassEx ) )
570 				return NULL;
571 	}
572 
573 	HWND hComWnd = CreateWindowExW( WS_EX_TOOLWINDOW, SAL_COM_CLASSNAMEW,
574 								   L"", WS_POPUP, 0, 0, 0, 0, 0, 0,
575 								   pSalData->mhInst, NULL );
576 	if ( !hComWnd )
577 		return NULL;
578 
579 	WinSalInstance* pInst = new WinSalInstance;
580 
581 	// init instance (only one instance in this version !!!)
582 	pSalData->mpFirstInstance   = pInst;
583 	pInst->mhInst    = pSalData->mhInst;
584 	pInst->mhComWnd  = hComWnd;
585 
586 	// init static GDI Data
587 	ImplInitSalGDI();
588 
589 	return pInst;
590 }
591 
592 // -----------------------------------------------------------------------
593 
594 void DestroySalInstance( SalInstance* pInst )
595 {
596 	SalData* pSalData = GetSalData();
597 
598 	//  (only one instance in this version !!!)
599 
600 	ImplFreeSalGDI();
601 
602 	// reset instance
603 	if ( pSalData->mpFirstInstance == pInst )
604 		pSalData->mpFirstInstance = NULL;
605 
606 	delete pInst;
607 }
608 
609 // -----------------------------------------------------------------------
610 
611 WinSalInstance::WinSalInstance()
612 {
613 	mhComWnd                 = 0;
614 	mpSalYieldMutex          = new SalYieldMutex( this );
615 	mpSalWaitMutex           = new vos::OMutex;
616 	mnYieldWaitCount         = 0;
617 	mpSalYieldMutex->acquire();
618 	::tools::SolarMutex::SetSolarMutex( mpSalYieldMutex );
619 }
620 
621 // -----------------------------------------------------------------------
622 
623 WinSalInstance::~WinSalInstance()
624 {
625 	::tools::SolarMutex::SetSolarMutex( 0 );
626 	mpSalYieldMutex->release();
627 	delete mpSalYieldMutex;
628 	delete mpSalWaitMutex;
629 	DestroyWindow( mhComWnd );
630 }
631 
632 // -----------------------------------------------------------------------
633 
634 vos::IMutex* WinSalInstance::GetYieldMutex()
635 {
636 	return mpSalYieldMutex;
637 }
638 
639 // -----------------------------------------------------------------------
640 
641 sal_uLong WinSalInstance::ReleaseYieldMutex()
642 {
643 	return ImplSalReleaseYieldMutex();
644 }
645 
646 // -----------------------------------------------------------------------
647 
648 void WinSalInstance::AcquireYieldMutex( sal_uLong nCount )
649 {
650 	ImplSalAcquireYieldMutex( nCount );
651 }
652 
653 // -----------------------------------------------------------------------
654 
655 static void ImplSalDispatchMessage( MSG* pMsg )
656 {
657 	SalData* pSalData = GetSalData();
658 	if ( pSalData->mpFirstObject )
659 	{
660 		if ( ImplSalPreDispatchMsg( pMsg ) )
661 			return;
662 	}
663 	LRESULT lResult = ImplDispatchMessage( pMsg );
664 	if ( pSalData->mpFirstObject )
665 		ImplSalPostDispatchMsg( pMsg, lResult );
666 }
667 
668 // -----------------------------------------------------------------------
669 
670 void ImplSalYield( sal_Bool bWait, sal_Bool bHandleAllCurrentEvents )
671 {
672 	MSG aMsg;
673 	bool bWasMsg = false, bOneEvent = false;
674 
675     int nMaxEvents = bHandleAllCurrentEvents ? 100 : 1;
676     do
677     {
678 		if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_REMOVE ) )
679 		{
680             if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
681             {
682                 TranslateMessage( &aMsg );
683                 ImplSalDispatchMessage( &aMsg );
684             }
685 
686 			bOneEvent = bWasMsg = true;
687 		}
688         else
689             bOneEvent = false;
690     } while( --nMaxEvents && bOneEvent );
691 
692 	if ( bWait && ! bWasMsg )
693 	{
694 		if ( ImplGetMessage( &aMsg, 0, 0, 0 ) )
695 		{
696             if ( !ImplInterceptChildWindowKeyDown( aMsg ) )
697             {
698                 TranslateMessage( &aMsg );
699                 ImplSalDispatchMessage( &aMsg );
700             }
701 		}
702 	}
703 }
704 
705 // -----------------------------------------------------------------------
706 
707 void WinSalInstance::Yield( bool bWait, bool bHandleAllCurrentEvents )
708 {
709 	SalYieldMutex*  pYieldMutex = mpSalYieldMutex;
710 	SalData*        pSalData = GetSalData();
711 	DWORD           nCurThreadId = GetCurrentThreadId();
712 	sal_uLong           nCount = pYieldMutex->GetAcquireCount( nCurThreadId );
713 	sal_uLong           n = nCount;
714 	while ( n )
715 	{
716 		pYieldMutex->release();
717 		n--;
718 	}
719 	if ( pSalData->mnAppThreadId != nCurThreadId )
720 	{
721 		// #97739# A SendMessage call blocks until the called thread (here: the main thread)
722 		// returns. During a yield however, messages are processed in the main thread that might
723 		// result in a new message loop due to opening a dialog. Thus, SendMessage would not
724 		// return which will block this thread!
725 		// Solution: just give up the time slice and hope that messages are processed
726 		// by the main thread anyway (where all windows are created)
727 		// If the mainthread is not currently handling messages, then our SendMessage would
728 		// also do nothing, so this seems to be reasonable.
729 
730 		// #i18883# only sleep if potential deadlock scenario, ie, when a dialog is open
731 		if( ImplGetSVData()->maAppData.mnModalMode )
732 			Sleep(1);
733 		else
734 			ImplSendMessage( mhComWnd, SAL_MSG_THREADYIELD, (WPARAM)bWait, (LPARAM)bHandleAllCurrentEvents );
735 
736 		n = nCount;
737 		while ( n )
738 		{
739 			pYieldMutex->acquire();
740 			n--;
741 		}
742 	}
743 	else
744 	{
745 		ImplSalYield( bWait, bHandleAllCurrentEvents );
746 
747 		n = nCount;
748 		while ( n )
749 		{
750 			ImplSalYieldMutexAcquireWithWait();
751 			n--;
752 		}
753 	}
754 }
755 
756 // -----------------------------------------------------------------------
757 
758 LRESULT CALLBACK SalComWndProc( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, int& rDef )
759 {
760 	LRESULT nRet = 0;
761 
762 
763 	switch ( nMsg )
764 	{
765 		case SAL_MSG_PRINTABORTJOB:
766 			ImplSalPrinterAbortJobAsync( (HDC)wParam );
767 			rDef = FALSE;
768 			break;
769 		case SAL_MSG_THREADYIELD:
770 			ImplSalYield( (sal_Bool)wParam, (sal_Bool)lParam );
771 			rDef = FALSE;
772 			break;
773 		// If we get this message, because another GetMessage() call
774 		// has recieved this message, we must post this message to
775 		// us again, because in the other case we wait forever.
776 		case SAL_MSG_RELEASEWAITYIELD:
777 			{
778 			WinSalInstance* pInst = GetSalData()->mpFirstInstance;
779 			if ( pInst && pInst->mnYieldWaitCount )
780 				ImplPostMessage( hWnd, SAL_MSG_RELEASEWAITYIELD, wParam, lParam );
781 			}
782 			rDef = FALSE;
783 			break;
784 		case SAL_MSG_STARTTIMER:
785 			ImplSalStartTimer( (sal_uLong) lParam, FALSE );
786 			rDef = FALSE;
787 			break;
788 		case SAL_MSG_CREATEFRAME:
789 			nRet = (LRESULT)ImplSalCreateFrame( GetSalData()->mpFirstInstance, (HWND)lParam, (sal_uLong)wParam );
790 			rDef = FALSE;
791 			break;
792 		case SAL_MSG_RECREATEHWND:
793 			nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, FALSE );
794 			rDef = FALSE;
795 			break;
796 		case SAL_MSG_RECREATECHILDHWND:
797 			nRet = (LRESULT)ImplSalReCreateHWND( (HWND)wParam, (HWND)lParam, TRUE );
798 			rDef = FALSE;
799 			break;
800 		case SAL_MSG_DESTROYFRAME:
801 			delete (SalFrame*)lParam;
802 			rDef = FALSE;
803 			break;
804 		case SAL_MSG_DESTROYHWND:
805 			//We only destroy the native window here. We do NOT destroy the SalFrame contained
806 			//in the structure (GetWindowPtr()).
807 			if (DestroyWindow((HWND)lParam) == 0)
808 			{
809 				OSL_ENSURE(0, "DestroyWindow failed!");
810 				//Failure: We remove the SalFrame from the window structure. So we avoid that
811 				// the window structure may contain an invalid pointer, once the SalFrame is deleted.
812 			   SetWindowPtr((HWND)lParam, 0);
813 			}
814 			rDef = FALSE;
815 			break;
816 		case SAL_MSG_CREATEOBJECT:
817 			nRet = (LRESULT)ImplSalCreateObject( GetSalData()->mpFirstInstance, (WinSalFrame*)lParam );
818 			rDef = FALSE;
819 			break;
820 		case SAL_MSG_DESTROYOBJECT:
821 			delete (SalObject*)lParam;
822 			rDef = FALSE;
823 			break;
824 		case SAL_MSG_GETDC:
825 			nRet = (LRESULT)GetDCEx( (HWND)wParam, 0, DCX_CACHE );
826 			rDef = FALSE;
827 			break;
828 		case SAL_MSG_RELEASEDC:
829 			ReleaseDC( (HWND)wParam, (HDC)lParam );
830 			rDef = FALSE;
831 			break;
832         case SAL_MSG_POSTTIMER:
833 			SalTimerProc( 0, 0, SALTIMERPROC_RECURSIVE, lParam );
834 			break;
835 	}
836 
837 	return nRet;
838 }
839 
840 LRESULT CALLBACK SalComWndProcA( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
841 {
842 	int bDef = TRUE;
843 	LRESULT nRet = 0;
844 #ifdef __MINGW32__
845 	jmp_buf jmpbuf;
846 	__SEHandler han;
847 	if (__builtin_setjmp(jmpbuf) == 0)
848 	{
849 		han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
850 #else
851 	__try
852 	{
853 #endif
854 		nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
855 	}
856 #ifdef __MINGW32__
857 	han.Reset();
858 #else
859     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
860 	{
861 	}
862 #endif
863 	if ( bDef )
864 	{
865 		if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
866 			nRet = DefWindowProcA( hWnd, nMsg, wParam, lParam );
867 	}
868 	return nRet;
869 }
870 
871 LRESULT CALLBACK SalComWndProcW( HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
872 {
873 	int bDef = TRUE;
874 	LRESULT nRet = 0;
875 #ifdef __MINGW32__
876 	jmp_buf jmpbuf;
877 	__SEHandler han;
878 	if (__builtin_setjmp(jmpbuf) == 0)
879 	{
880 		han.Set(jmpbuf, NULL, (__SEHandler::PF)EXCEPTION_EXECUTE_HANDLER);
881 #else
882 	__try
883 	{
884 #endif
885 		nRet = SalComWndProc( hWnd, nMsg, wParam, lParam, bDef );
886 	}
887 #ifdef __MINGW32__
888 	han.Reset();
889 #else
890     __except(WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(GetExceptionCode(), GetExceptionInformation()))
891 	{
892 	}
893 #endif
894 	if ( bDef )
895 	{
896 		if ( !ImplHandleGlobalMsg( hWnd, nMsg, wParam, lParam, nRet ) )
897 			nRet = DefWindowProcW( hWnd, nMsg, wParam, lParam );
898 	}
899 	return nRet;
900 }
901 
902 // -----------------------------------------------------------------------
903 
904 bool WinSalInstance::AnyInput( sal_uInt16 nType )
905 {
906 	MSG aMsg;
907 
908 	if ( (nType & (INPUT_ANY)) == (INPUT_ANY) )
909 	{
910 		// revert bugfix for #108919# which never reported timeouts when called from the timer handler
911 		// which made the application completely unresponsive during background formatting
912 		if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
913 			return true;
914 	}
915 	else
916 	{
917 		if ( nType & INPUT_MOUSE )
918 		{
919 			// Test for mouse input
920 			if ( ImplPeekMessage( &aMsg, 0, WM_MOUSEFIRST, WM_MOUSELAST,
921 								  PM_NOREMOVE | PM_NOYIELD ) )
922 				return true;
923 		}
924 
925 		if ( nType & INPUT_KEYBOARD )
926 		{
927 			// Test for key input
928 			if ( ImplPeekMessage( &aMsg, 0, WM_KEYDOWN, WM_KEYDOWN,
929 								  PM_NOREMOVE | PM_NOYIELD ) )
930 			{
931 				if ( (aMsg.wParam == VK_SHIFT)   ||
932 					 (aMsg.wParam == VK_CONTROL) ||
933 					 (aMsg.wParam == VK_MENU) )
934 					return false;
935 				else
936 					return true;
937 			}
938 		}
939 
940 		if ( nType & INPUT_PAINT )
941 		{
942 			// Test for paint input
943 			if ( ImplPeekMessage( &aMsg, 0, WM_PAINT, WM_PAINT,
944 								  PM_NOREMOVE | PM_NOYIELD ) )
945 				return true;
946 
947 			if ( ImplPeekMessage( &aMsg, 0, WM_SIZE, WM_SIZE,
948 								  PM_NOREMOVE | PM_NOYIELD ) )
949 				return true;
950 
951 			if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTCALLSIZE, SAL_MSG_POSTCALLSIZE,
952 								  PM_NOREMOVE | PM_NOYIELD ) )
953 				return true;
954 
955 			if ( ImplPeekMessage( &aMsg, 0, WM_MOVE, WM_MOVE,
956 								  PM_NOREMOVE | PM_NOYIELD ) )
957 				return true;
958 
959 			if ( ImplPeekMessage( &aMsg, 0, SAL_MSG_POSTMOVE, SAL_MSG_POSTMOVE,
960 								  PM_NOREMOVE | PM_NOYIELD ) )
961 				return true;
962 		}
963 
964 		if ( nType & INPUT_TIMER )
965 		{
966 			// Test for timer input
967 			if ( ImplPeekMessage( &aMsg, 0, WM_TIMER, WM_TIMER,
968 								  PM_NOREMOVE | PM_NOYIELD ) )
969 				return true;
970 
971 		}
972 
973 		if ( nType & INPUT_OTHER )
974 		{
975 			// Test for any input
976 			if ( ImplPeekMessage( &aMsg, 0, 0, 0, PM_NOREMOVE | PM_NOYIELD ) )
977 				return true;
978 		}
979 	}
980 
981 	return FALSE;
982 }
983 
984 // -----------------------------------------------------------------------
985 
986 void SalTimer::Start( sal_uLong nMS )
987 {
988 	// Um auf Main-Thread umzuschalten
989 	SalData* pSalData = GetSalData();
990 	if ( pSalData->mpFirstInstance )
991 	{
992 		if ( pSalData->mnAppThreadId != GetCurrentThreadId() )
993 			ImplPostMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
994 		else
995 			ImplSendMessage( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_STARTTIMER, 0, (LPARAM)nMS );
996 	}
997 	else
998 		ImplSalStartTimer( nMS, FALSE );
999 }
1000 
1001 // -----------------------------------------------------------------------
1002 
1003 SalFrame* WinSalInstance::CreateChildFrame( SystemParentData* pSystemParentData, sal_uLong nSalFrameStyle )
1004 {
1005 	// Um auf Main-Thread umzuschalten
1006 	return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)pSystemParentData->hWnd );
1007 }
1008 
1009 // -----------------------------------------------------------------------
1010 
1011 SalFrame* WinSalInstance::CreateFrame( SalFrame* pParent, sal_uLong nSalFrameStyle )
1012 {
1013 	// Um auf Main-Thread umzuschalten
1014 	HWND hWndParent;
1015 	if ( pParent )
1016 		hWndParent = static_cast<WinSalFrame*>(pParent)->mhWnd;
1017 	else
1018 		hWndParent = 0;
1019 	return (SalFrame*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEFRAME, nSalFrameStyle, (LPARAM)hWndParent );
1020 }
1021 
1022 // -----------------------------------------------------------------------
1023 
1024 void WinSalInstance::DestroyFrame( SalFrame* pFrame )
1025 {
1026 	ImplSendMessage( mhComWnd, SAL_MSG_DESTROYFRAME, 0, (LPARAM)pFrame );
1027 }
1028 
1029 // -----------------------------------------------------------------------
1030 
1031 SalObject* WinSalInstance::CreateObject( SalFrame* pParent,
1032                                          SystemWindowData* /*pWindowData*/, // SystemWindowData meaningless on Windows
1033                                          sal_Bool /*bShow*/ )
1034 {
1035 	// Um auf Main-Thread umzuschalten
1036 	return (SalObject*)ImplSendMessage( mhComWnd, SAL_MSG_CREATEOBJECT, 0, (LPARAM)static_cast<WinSalFrame*>(pParent) );
1037 }
1038 
1039 // -----------------------------------------------------------------------
1040 
1041 void WinSalInstance::DestroyObject( SalObject* pObject )
1042 {
1043 	ImplSendMessage( mhComWnd, SAL_MSG_DESTROYOBJECT, 0, (LPARAM)pObject );
1044 }
1045 
1046 // -----------------------------------------------------------------------
1047 
1048 void* WinSalInstance::GetConnectionIdentifier( ConnectionIdentifierType& rReturnedType, int& rReturnedBytes )
1049 {
1050 	rReturnedBytes  = 1;
1051 	rReturnedType   = AsciiCString;
1052 	return const_cast<char *>("");
1053 }
1054 
1055 // -----------------------------------------------------------------------
1056 
1057 /** Add a file to the system shells recent document list if there is any.
1058       This function may have no effect under Unix because there is no
1059       standard API among the different desktop managers.
1060 
1061       @param aFileUrl
1062                 The file url of the document.
1063 */
1064 void WinSalInstance::AddToRecentDocumentList(const rtl::OUString& rFileUrl, const rtl::OUString& /*rMimeType*/)
1065 {
1066     rtl::OUString system_path;
1067     osl::FileBase::RC rc = osl::FileBase::getSystemPathFromFileURL(rFileUrl, system_path);
1068 
1069     OSL_ENSURE(osl::FileBase::E_None == rc, "Invalid file url");
1070 
1071     if (osl::FileBase::E_None == rc)
1072         SHAddToRecentDocs(SHARD_PATHW, system_path.getStr());
1073 }
1074 
1075 // -----------------------------------------------------------------------
1076 
1077 SalTimer* WinSalInstance::CreateSalTimer()
1078 {
1079 	return new WinSalTimer();
1080 }
1081 
1082 // -----------------------------------------------------------------------
1083 
1084 SalBitmap* WinSalInstance::CreateSalBitmap()
1085 {
1086 	return new WinSalBitmap();
1087 }
1088 
1089 class WinImeStatus : public SalI18NImeStatus
1090 {
1091   public:
1092 	WinImeStatus() {}
1093 	virtual ~WinImeStatus() {}
1094 
1095 	// asks whether there is a status window available
1096 	// to toggle into menubar
1097 	virtual bool canToggle() { return false; }
1098 	virtual void toggle() {}
1099 };
1100 
1101 SalI18NImeStatus* WinSalInstance::CreateI18NImeStatus()
1102 {
1103 	return new WinImeStatus();
1104 }
1105 
1106 // -----------------------------------------------------------------------
1107 
1108 const ::rtl::OUString& SalGetDesktopEnvironment()
1109 {
1110 	static ::rtl::OUString aDesktopEnvironment( RTL_CONSTASCII_USTRINGPARAM( "Windows" ) );
1111 	return aDesktopEnvironment;
1112 }
1113 
1114 SalSession* WinSalInstance::CreateSalSession()
1115 {
1116 	return NULL;
1117 }
1118 
1119 #ifndef __MINGW32__
1120 // -----------------------------------------------------------------------
1121 int WinSalInstance::WorkaroundExceptionHandlingInUSER32Lib(int, LPEXCEPTION_POINTERS pExceptionInfo)
1122 {
1123     // Decide if an exception is a c++ (mostly UNO) exception or a process violation.
1124     // Depending on this information we pass process violations directly to our signal handler ...
1125     // and c++ (UNO) exceptions are sended to the following code on the current stack.
1126     // Problem behind: user32.dll sometime consumes exceptions/process violations .-)
1127     // see also #112221#
1128 
1129     static DWORD EXCEPTION_MSC_CPP_EXCEPTION = 0xE06D7363;
1130 
1131     if (pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_MSC_CPP_EXCEPTION)
1132         return EXCEPTION_CONTINUE_SEARCH;
1133 
1134     return UnhandledExceptionFilter( pExceptionInfo );
1135 }
1136 #endif
1137