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