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