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_automation.hxx" 30 #include <tools/time.hxx> 31 #include <vcl/splitwin.hxx> 32 #include <vcl/wrkwin.hxx> 33 #ifndef _BASIC_TTRESHLP_HXX 34 #include <basic/ttstrhlp.hxx> 35 #endif 36 #include "statemnt.hxx" 37 38 #ifndef _RETSRTM_HXX 39 #include "retstrm.hxx" 40 #endif 41 #include "rcontrol.hxx" 42 43 #if OSL_DEBUG_LEVEL > 1 44 #include "editwin.hxx" 45 #endif 46 47 #include "profiler.hxx" 48 #include <vcl/floatwin.hxx> 49 #include <vcl/toolbox.hxx> 50 51 // only needed for dynamic_cast in wintree 52 #include <svtools/editbrowsebox.hxx> 53 #include <svtools/valueset.hxx> 54 #include <svtools/roadmap.hxx> 55 #include <svtools/extensionlistbox.hxx> 56 #include <svtools/table/tablecontrol.hxx> 57 58 #define WINDOW_ANYTYPE WINDOW_BASE 59 60 61 TTProfiler *StatementList::pProfiler = NULL; 62 StatementList *StatementList::pFirst = NULL; 63 sal_Bool StatementList::bReadingCommands = sal_False; 64 sal_Bool StatementList::bIsInReschedule = sal_False; 65 sal_uInt16 StatementList::nModalCount = 0; 66 Window *StatementList::pLastFocusWindow = NULL; 67 sal_Bool StatementList::bWasDragManager = sal_False; 68 sal_Bool StatementList::bWasPopupMenu = sal_False; 69 sal_Bool StatementList::bBasicWasRunning = sal_False; 70 RetStream *StatementList::pRet = NULL; 71 sal_Bool StatementList::IsError = sal_False; 72 sal_Bool StatementList::bDying = sal_False; 73 sal_Bool StatementList::bExecuting = sal_False; 74 StatementList *StatementList::pCurrentProfileStatement = NULL; 75 sal_Bool StatementList::bUsePostEvents = sal_True; 76 #if OSL_DEBUG_LEVEL > 1 77 EditWindow *StatementList::m_pDbgWin; 78 #endif 79 80 81 rtl::OString StatementList::aWindowWaitUId = rtl::OString(); 82 Window *StatementList::pWindowWaitPointer = NULL; 83 rtl::OString StatementList::aWindowWaitOldHelpId = rtl::OString(); 84 rtl::OString StatementList::aWindowWaitOldUniqueId = rtl::OString(); 85 sal_uInt16 StatementList::nUseBindings = 0; 86 87 sal_uInt16 StatementList::aSubMenuId1 = 0; // Untermen�s bei PopupMenus 88 sal_uInt16 StatementList::aSubMenuId2 = 0; // erstmal 2-Stufig 89 sal_uInt16 StatementList::aSubMenuId3 = 0; // and now even 3 levels #i31512# 90 SystemWindow *StatementList::pMenuWindow = NULL; 91 TTProperties *StatementList::pTTProperties = NULL; 92 93 sal_uInt16 StatementList::nMinTypeKeysDelay = 0; // Verz�gerung der einzelnen Anschl�ge f�r TypeKeys 94 sal_uInt16 StatementList::nMaxTypeKeysDelay = 0; 95 sal_Bool StatementList::bDoTypeKeysDelay = sal_False; 96 97 Window* StatementList::pFirstDocFrame = NULL; 98 99 sal_Bool StatementList::bIsSlotInExecute = sal_False; 100 101 sal_Bool StatementList::bCatchGPF = sal_True; 102 103 104 IMPL_GEN_RES_STR; 105 106 107 static TTSettings* pTTSettings = NULL; 108 109 TTSettings* GetTTSettings() 110 { 111 if ( !pTTSettings ) 112 { 113 pTTSettings = new TTSettings; 114 115 // DisplayHID 116 pTTSettings->pDisplayInstance = NULL; 117 pTTSettings->pDisplayHidWin = NULL; 118 pTTSettings->Old = NULL; 119 pTTSettings->Act = NULL; 120 pTTSettings->aOriginalCaption.Erase(); 121 122 // Translate 123 pTTSettings->pTranslateWin = NULL; 124 pTTSettings->bToTop = sal_True; 125 } 126 127 return pTTSettings; 128 } 129 130 131 132 133 // FIXME: HELPID 134 #define IS_WINP_CLOSING(pWin) (pWin->GetHelpId().equals( "TT_Win_is_closing_HID" ) && pWin->GetUniqueId().equals( "TT_Win_is_closing_UID" )) 135 136 /* 137 UniString GEN_RES_STR0( sal_uLong nResId ) { return ResString( nResId ); } 138 UniString GEN_RES_STR1( sal_uLong nResId, const UniString &Text1 ) { return GEN_RES_STR0( nResId ).Append( ArgString( 1, Text1 ) ); } 139 UniString GEN_RES_STR2( sal_uLong nResId, const UniString &Text1, const UniString &Text2 ) { return GEN_RES_STR1( nResId, Text1 ).Append( ArgString( 2, Text2 ) ); } 140 UniString GEN_RES_STR3( sal_uLong nResId, const UniString &Text1, const UniString &Text2, const UniString &Text3 ) { return GEN_RES_STR2( nResId, Text1, Text2 ).Append( ArgString( 3, Text3 ) );} 141 */ 142 StatementList::StatementList() 143 : nRetryCount(MAX_RETRIES) 144 , bStatementInQue(sal_False) 145 { 146 if (!pRet) 147 pRet = new RetStream; // so Sp�t wie m�glich, aber dennoch Zentral und auf jeden Fall rechtzeitig, da pRet private ist. 148 } 149 150 void StatementList::InitProfile() 151 { 152 if ( pProfiler ) 153 { 154 if ( pProfiler->IsProfilingPerCommand() || pProfiler->IsPartitioning() ) 155 pProfiler->StartProfileInterval( pCurrentProfileStatement != this ); 156 157 #if OSL_DEBUG_LEVEL > 1 158 if ( pCurrentProfileStatement != NULL && pCurrentProfileStatement != this ) 159 pRet->GenReturn( RET_ProfileInfo, 0, CUniString("InitProfile von anderem Statement gerufen ohne SendProfile\n") ); 160 #endif 161 pCurrentProfileStatement = this; 162 } 163 } 164 165 void StatementList::SendProfile( String aText ) 166 { 167 if ( pProfiler ) 168 { 169 if ( pCurrentProfileStatement == this ) 170 { 171 if ( pProfiler->IsProfilingPerCommand() || pProfiler->IsPartitioning() ) 172 pProfiler->EndProfileInterval(); 173 174 if ( pProfiler->IsProfilingPerCommand() ) 175 pRet->GenReturn( RET_ProfileInfo, 0, pProfiler->GetProfileLine( aText ) ); 176 177 if ( pProfiler->IsPartitioning() ) 178 // FIXME: HELPID 179 pRet->GenReturn( RET_ProfileInfo, S_ProfileTime, static_cast<comm_ULONG>(pProfiler->GetPartitioningTime()) ); // GetPartitioningTime() sal_uLong != comm_ULONG on 64bit 180 } 181 182 if ( pProfiler->IsAutoProfiling() ) 183 pRet->GenReturn( RET_ProfileInfo, 0, pProfiler->GetAutoProfiling() ); 184 185 #if OSL_DEBUG_LEVEL > 1 186 if ( pCurrentProfileStatement == NULL ) 187 pRet->GenReturn( RET_ProfileInfo, 0, CUniString("SendProfile ohne InitProfile\n") ); 188 #endif 189 pCurrentProfileStatement = NULL; 190 } 191 } 192 193 void StatementList::QueStatement(StatementList *pAfterThis) 194 { 195 DBG_ASSERT(!bStatementInQue,"QueStatement f�r bereits eingetragenes Statement -> Abgebrochen"); 196 if ( bStatementInQue ) 197 return; 198 199 bStatementInQue = sal_True; 200 if ( pAfterThis ) 201 { 202 if ( pAfterThis->bStatementInQue ) 203 { 204 pNext = pAfterThis->pNext; 205 pAfterThis->pNext = this; 206 } 207 else 208 { // pAfterThis not in que -> already dequed -> add to front of list 209 pNext = pFirst; 210 pFirst = this; 211 } 212 } 213 else // am Ende einf�gen 214 { 215 pNext = NULL; 216 if( !pFirst ) 217 pFirst = this; 218 else 219 { 220 StatementList *pList; 221 pList = pFirst; 222 while( pList->pNext ) 223 pList = pList->pNext; 224 pList->pNext = this; 225 } 226 } 227 } 228 229 void StatementList::Advance() 230 { // pFirst ist static! 231 pFirst = pNext; 232 bStatementInQue = sal_False; 233 pNext = NULL; 234 } 235 236 237 StatementList::~StatementList() 238 { 239 #if OSL_DEBUG_LEVEL > 1 240 m_pDbgWin->AddText( "Deleting \n" ); 241 #endif 242 DBG_ASSERT(!bReadingCommands,"Deleting commands while reading them!"); 243 } 244 245 Window* StatementList::GetDocWin( sal_uInt16 nNr ) 246 { 247 Window* pBase = Application::GetFirstTopLevelWindow(); 248 249 while ( pBase ) 250 { 251 if ( IsDocWin( pBase ) ) 252 { 253 if ( !nNr ) 254 return pBase; 255 nNr--; 256 } 257 pBase = Application::GetNextTopLevelWindow( pBase ); 258 } 259 return NULL; 260 } 261 262 sal_uInt16 StatementList::GetDocFrameCount() 263 { 264 Window* pBase = Application::GetFirstTopLevelWindow(); 265 sal_uInt16 nCount = 0; 266 267 while ( pBase ) 268 { 269 if ( IsDocFrame( pBase ) ) 270 nCount++; 271 pBase = Application::GetNextTopLevelWindow( pBase ); 272 } 273 return nCount; 274 } 275 276 sal_uInt16 StatementList::GetDocWinCount() 277 { 278 Window* pBase = Application::GetFirstTopLevelWindow(); 279 sal_uInt16 nCount = 0; 280 281 while ( pBase ) 282 { 283 if ( IsDocWin( pBase ) ) 284 nCount++; 285 pBase = Application::GetNextTopLevelWindow( pBase ); 286 } 287 return nCount; 288 } 289 290 Window* StatementList::SearchAllWin( Window *pBase, Search &aSearch, sal_Bool MaybeBase ) 291 { 292 293 if ( !pBase && !aSearch.HasSearchFlag( SEARCH_NO_TOPLEVEL_WIN ) ) 294 { 295 sal_Bool bSearchFocusFirst = aSearch.HasSearchFlag( SEARCH_FOCUS_FIRST ); 296 297 Window *pControl = NULL; 298 if ( bSearchFocusFirst ) 299 { 300 // first test Parent of Focus Window 301 pBase = Application::GetFocusWindow(); 302 if ( pBase ) 303 { 304 DBG_ASSERT( WinPtrValid( pBase ), "GetFocusWindow is no valid WindowPointer" ); 305 Window *pPParent = pBase; 306 while ( pPParent->GET_REAL_PARENT() ) 307 pPParent = pPParent->GET_REAL_PARENT(); 308 309 // if ( !IsFirstDocFrame( pPParent ) ) 310 // { 311 // get overlap window. Will be dialog else document itself 312 pBase = pBase->GetWindow( WINDOW_OVERLAP ); 313 314 // set flag to find disabled elements. 315 // This is better than an enabled one on another Window 316 aSearch.AddSearchFlags( SEARCH_FIND_DISABLED ); 317 318 // search on current Dialog first 319 pControl = SearchAllWin( pBase, aSearch ); 320 321 // search on current Document 322 if ( !pControl && pBase != pPParent ) 323 pControl = SearchAllWin( pPParent, aSearch ); 324 325 aSearch.RemoveSearchFlags( SEARCH_FIND_DISABLED ); 326 327 if ( pControl ) 328 return pControl; 329 // } 330 } 331 } 332 333 pBase = Application::GetFirstTopLevelWindow(); 334 335 // Skip FirstDocFrame 336 // if ( bSearchFocusFirst && IsFirstDocFrame( pBase ) ) 337 // pBase = Application::GetNextTopLevelWindow( pBase ); 338 339 while ( pBase ) 340 { 341 pControl = SearchAllWin( pBase, aSearch ); 342 if ( pControl ) 343 return pControl; 344 345 pBase = Application::GetNextTopLevelWindow( pBase ); 346 // Skip FirstDocFrame 347 // if ( bSearchFocusFirst && IsFirstDocFrame( pBase ) ) 348 // pBase = Application::GetNextTopLevelWindow( pBase ); 349 } 350 return NULL; 351 } 352 353 354 Window *pResult = NULL; 355 pResult = SearchClientWin( pBase, aSearch, MaybeBase ); 356 if ( pResult ) 357 return pResult; 358 359 // if ( pBase->GetType() != WINDOW_BORDERWINDOW ) 360 // return NULL; 361 362 if ( !aSearch.HasSearchFlag( SEARCH_NOOVERLAP ) ) 363 { 364 if ( pBase->GetWindow( WINDOW_FIRSTOVERLAP ) ) 365 pResult = SearchAllWin( pBase->GetWindow( WINDOW_FIRSTOVERLAP ), aSearch ); 366 367 if ( !pResult && pBase->GetWindow( WINDOW_NEXT ) ) 368 pResult = SearchAllWin( pBase->GetWindow( WINDOW_NEXT ), aSearch ); 369 } 370 371 return pResult; 372 } 373 374 375 Window* StatementList::SearchClientWin( Window *pBase, Search &aSearch, sal_Bool MaybeBase ) 376 { 377 if ( !pBase ) 378 return NULL; 379 380 if ( MaybeBase && aSearch.IsWinOK( pBase ) ) 381 return pBase; 382 383 Window *pResult = NULL; 384 385 sal_uInt16 i; 386 for( i = 0 ; i < pBase->GetChildCount() && !pResult; i++ ) 387 pResult = SearchClientWin( pBase->GetChild(i), aSearch ); 388 389 return pResult; 390 } 391 392 393 sal_Bool SearchUID::IsWinOK( Window *pWin ) 394 { 395 if ( aUId.equals( pWin->GetUniqueOrHelpId() ) ) 396 { 397 if ( ( pWin->IsEnabled() || HasSearchFlag( SEARCH_FIND_DISABLED ) ) && pWin->IsVisible() ) 398 return sal_True; 399 else 400 { 401 if ( !pMaybeResult ) 402 pMaybeResult = pWin; 403 return sal_False; 404 } 405 } 406 else if ( pWin->GetType() == WINDOW_TOOLBOX ) // Buttons and Controls on ToolBox. 407 { 408 ToolBox *pTB = ((ToolBox*)pWin); 409 sal_uInt16 i; 410 for ( i = 0; i < pTB->GetItemCount() ; i++ ) 411 { 412 if ( aUId.equals( Str2Id( pTB->GetItemCommand(pTB->GetItemId( i )) ) ) || aUId.equals( pTB->GetHelpId(pTB->GetItemId( i )) ) ) 413 { // ID matches. 414 Window *pItemWin; 415 pItemWin = pTB->GetItemWindow( pTB->GetItemId( i ) ); 416 417 if ( bSearchButtonOnToolbox && pTB->GetItemType( i ) == TOOLBOXITEM_BUTTON && !pItemWin ) 418 { // We got a Control, see if its valid also. 419 // Same as above. 420 if ( ( pTB->IsEnabled() || HasSearchFlag( SEARCH_FIND_DISABLED ) ) && pTB->IsVisible() ) 421 { // We got a Button, see if its valid also. 422 if ( ( pTB->IsItemEnabled(pTB->GetItemId(i)) || HasSearchFlag( SEARCH_FIND_DISABLED ) ) 423 && pTB->IsItemVisible(pTB->GetItemId(i)) ) 424 return sal_True; // We got a Button. 425 else 426 { // better a disabled Button on a valid ToolBox than an invalid ToolBox as below 427 pMaybeResult = pTB; 428 return sal_False; 429 } 430 } 431 else if ( !pMaybeResult ) 432 { // invalid ToolBox 433 pMaybeResult = pTB; 434 return sal_False; 435 } 436 } 437 if ( pItemWin ) 438 { // We got a Control, see if its valid also. 439 // Same as above. 440 if ( ( pItemWin->IsEnabled() || HasSearchFlag( SEARCH_FIND_DISABLED ) ) && pItemWin->IsVisible() ) 441 { 442 if ( !pAlternateResult ) // only take the first found ItemWindow #i35365 443 pAlternateResult = pItemWin; // since we cannot return a Window here 444 return sal_False; // continue searching to prefer a window with the right ID #i32292 445 } 446 else if ( !pMaybeResult ) 447 { 448 pMaybeResult = pItemWin; 449 return sal_False; 450 } 451 } 452 } 453 } 454 return sal_False; 455 } 456 else 457 return sal_False; 458 } 459 460 Window* StatementList::SearchTree( rtl::OString aUId ,sal_Bool bSearchButtonOnToolbox ) 461 { 462 SearchUID aSearch(aUId,bSearchButtonOnToolbox); 463 464 Window *pResult = SearchAllWin( NULL, aSearch ); 465 if ( pResult ) 466 return pResult; 467 else if ( aSearch.GetAlternateResultWin() ) 468 return aSearch.GetAlternateResultWin(); 469 else 470 return aSearch.GetMaybeWin(); 471 } 472 473 474 sal_Bool SearchWinPtr::IsWinOK( Window *pWin ) 475 { 476 return pWin == pTest; 477 } 478 479 sal_Bool StatementList::WinPtrValid(Window *pTest) 480 { 481 SearchWinPtr aSearch( pTest ); 482 return SearchAllWin( NULL, aSearch ) != NULL; 483 } 484 485 486 sal_Bool SearchRT::IsWinOK( Window *pWin ) 487 { 488 if ( pWin->IsVisible() && pWin->GetType() == mnRT ) 489 { 490 mnCount++; 491 if ( mnSkip ) 492 { 493 mnSkip--; 494 return sal_False; 495 } 496 else 497 return sal_True; 498 } 499 return sal_False; 500 } 501 502 Window* StatementList::GetWinByRT( Window *pBase, WindowType nRT, sal_Bool MaybeBase, sal_uInt16 nSkip, sal_Bool bSearchAll ) 503 { 504 SearchRT aSearch( nRT, 0, nSkip ); 505 if ( bSearchAll ) 506 aSearch.AddSearchFlags( SEARCH_FOCUS_FIRST | SEARCH_FIND_DISABLED ); 507 else 508 aSearch.AddSearchFlags( SEARCH_NOOVERLAP | SEARCH_NO_TOPLEVEL_WIN ); 509 510 return SearchAllWin( pBase, aSearch, MaybeBase ); 511 } 512 513 sal_uInt16 StatementList::CountWinByRT( Window *pBase, WindowType nRT, sal_Bool MaybeBase ) 514 { 515 SearchRT aSearch( nRT, SEARCH_NOOVERLAP | SEARCH_NO_TOPLEVEL_WIN, 0xFFFF ); 516 517 SearchAllWin( pBase, aSearch, MaybeBase ); 518 return aSearch.GetCount(); 519 } 520 521 sal_Bool SearchScroll::IsWinOK( Window *pWin ) 522 { 523 if ( SearchRT::IsWinOK( pWin ) ) 524 { 525 DBG_ASSERT( pWin->GetStyle() & ( WB_HORZ | WB_VERT ), "Nither WB_HORZ nor WB_VERT set on ScrollBar"); 526 return (( pWin->GetStyle() & WB_HORZ ) && ( nDirection == CONST_ALIGN_BOTTOM )) 527 || (( pWin->GetStyle() & WB_VERT ) && ( nDirection == CONST_ALIGN_RIGHT )); 528 } 529 return sal_False; 530 } 531 532 ScrollBar* StatementList::GetScrollBar( Window *pBase, sal_uInt16 nDirection, sal_Bool MaybeBase ) 533 { 534 SearchScroll aSearch( nDirection, SEARCH_NOOVERLAP | SEARCH_NO_TOPLEVEL_WIN ); 535 536 return (ScrollBar*)SearchAllWin( pBase, aSearch, MaybeBase ); 537 } 538 539 540 sal_Bool SearchPopupFloatingWin::IsWinOK( Window *pWin ) 541 { 542 return pWin->IsVisible() && pWin->GetType() == WINDOW_FLOATINGWINDOW && ((FloatingWindow*)pWin)->IsInPopupMode(); 543 } 544 545 Window* StatementList::GetPopupFloatingWin( sal_Bool MaybeBase ) 546 { 547 SearchPopupFloatingWin aSearch; 548 549 return SearchAllWin( NULL, aSearch, MaybeBase ); 550 } 551 552 553 Menu* StatementList::GetMatchingMenu( Window* pWin, Menu* pBaseMenu ) 554 { 555 if ( pBaseMenu ) 556 { 557 if ( pBaseMenu->GetWindow() == pWin ) 558 return pBaseMenu; 559 560 sal_uInt16 i; 561 // while ( pBaseMenu ) 562 // { 563 i = 0; 564 while ( i < pBaseMenu->GetItemCount() ) 565 { 566 PopupMenu* pPopup = pBaseMenu->GetPopupMenu( pBaseMenu->GetItemId( i ) ); 567 if ( pPopup && pPopup->GetWindow() ) 568 { 569 if ( pPopup->GetWindow() == pWin ) 570 return pPopup; 571 else 572 { 573 pBaseMenu = pPopup; 574 i = 0; 575 } 576 } 577 else 578 i++; 579 } 580 // } 581 } 582 else 583 { 584 if ( PopupMenu::GetActivePopupMenu() ) 585 { 586 Menu* pMenu = GetMatchingMenu( pWin, PopupMenu::GetActivePopupMenu() ); 587 if ( pMenu ) 588 return pMenu; 589 } 590 591 sal_uInt16 nSkip = 0; 592 Window* pMenuBarWin = NULL; 593 while ( (pMenuBarWin = GetWinByRT( NULL, WINDOW_MENUBARWINDOW, sal_True, nSkip++, sal_True )) != NULL ) 594 { 595 Window* pParent = pMenuBarWin->GET_REAL_PARENT(); 596 if ( pParent && pParent->GetType() == WINDOW_BORDERWINDOW && pParent->IsVisible() ) 597 { 598 Menu* pMenu = NULL; 599 // find Menu of MenuBarWindow 600 sal_uInt16 nCount; 601 for ( nCount = 0 ; nCount < pParent->GetChildCount() ; nCount++ ) 602 { 603 if ( pParent->GetChild( nCount )->GetType() == WINDOW_WORKWINDOW ) 604 pMenu = ((WorkWindow*)(pParent->GetChild( nCount )))->GetMenuBar(); 605 } 606 if ( pMenu ) 607 { 608 // check for menu bar in Task Window 609 if ( pMenuBarWin == pWin ) 610 return pMenu; 611 612 // search submenues 613 pMenu = GetMatchingMenu( pWin, pMenu ); 614 if ( pMenu ) 615 return pMenu; 616 } 617 } 618 } 619 } 620 return NULL; 621 } 622 623 624 sal_Bool SearchActive::IsWinOK( Window *pWin ) 625 { 626 // return pWin->IsVisible() && ( (nRT == WINDOW_ANYTYPE && IsDialog(pWin) ) || pWin->GetType() == nRT ) && (nRT == WINDOW_FILEDIALOG || nRT == WINDOW_PATHDIALOG || nRT == WINDOW_PRINTDIALOG || nRT == WINDOW_PRINTERSETUPDIALOG || nRT == WINDOW_COLORDIALOG || ((SystemWindow*)pWin)->IsActive()); 627 // only matches ResID due to problems with UNIX Window Managers 628 return pWin->IsVisible() && ( (nRT == WINDOW_ANYTYPE && IsDialog(pWin) ) || pWin->GetType() == nRT ); 629 } 630 631 Window* StatementList::GetActive( WindowType nRT, sal_Bool MaybeBase ) 632 { 633 SearchActive aSearch( nRT ); 634 635 return SearchAllWin( NULL, aSearch, MaybeBase ); 636 } 637 638 sal_Bool SearchFadeSplitWin::IsWinOK( Window *pWin ) 639 { 640 #if OSL_DEBUG_LEVEL > 1 641 if ( pWin->GetType() == WINDOW_SPLITWINDOW ) 642 { 643 sal_Bool bResult; 644 WindowAlign aAlign; 645 bResult = pWin->IsVisible(); 646 bResult = ((SplitWindow*)pWin)->IsFadeInButtonVisible(); 647 bResult = ((SplitWindow*)pWin)->IsFadeOutButtonVisible(); 648 bResult = ((SplitWindow*)pWin)->IsAutoHideButtonVisible(); 649 aAlign = ((SplitWindow*)pWin)->GetAlign(); 650 } 651 #endif 652 return pWin->IsVisible() && ( pWin->GetType() == WINDOW_SPLITWINDOW ) 653 && (((SplitWindow*)pWin)->IsFadeInButtonVisible() || ((SplitWindow*)pWin)->IsFadeOutButtonVisible() ) 654 /*&& ((SplitWindow*)pWin)->IsAutoHideButtonVisible()*/ && ((SplitWindow*)pWin)->GetAlign() == nAlign; 655 } 656 657 Window* StatementList::GetFadeSplitWin( Window *pBase, WindowAlign nAlign, sal_Bool MaybeBase ) 658 { 659 SearchFadeSplitWin aSearch( nAlign ); 660 661 if ( GetpApp()->GetAppWindow() == pBase && pBase->GetType() != WINDOW_BORDERWINDOW ) 662 pBase = pBase->GetWindow( WINDOW_OVERLAP ); 663 664 return SearchAllWin( pBase, aSearch, MaybeBase ); 665 } 666 667 Window* StatementList::GetMouseWin() 668 { 669 Window *pBase = Application::GetFirstTopLevelWindow(); 670 Window *pControl = NULL; 671 while ( pBase ) 672 { 673 Window *pBaseFrame = pBase->GetWindow( WINDOW_OVERLAP ); 674 675 Point aP = pBaseFrame->GetPointerPosPixel(); 676 pControl = pBaseFrame->FindWindow( aP ); 677 if ( pControl ) 678 return pControl; 679 680 pBase = Application::GetNextTopLevelWindow( pBase ); 681 } 682 return NULL; 683 } 684 685 Window* StatementList::GetFocus( WindowType nRT, sal_Bool MaybeBase ) 686 { 687 688 if ( nRT == WINDOW_TABCONTROL ) 689 { 690 Window *pResult = GetActive( WINDOW_TABDIALOG, MaybeBase); 691 for( sal_uInt16 i = 0 ; pResult && i < pResult->GetChildCount(); i++ ) 692 if ( pResult->GetChild(i)->GetType() == nRT ) 693 return pResult->GetChild(i); 694 } 695 696 return NULL; 697 } 698 699 Window* StatementList::GetAnyActive( sal_Bool MaybeBase ) 700 { 701 Window *pControl; 702 703 pControl = GetActive( WINDOW_MESSBOX, MaybeBase); 704 if ( !pControl ) 705 { 706 pControl = GetActive( WINDOW_INFOBOX, MaybeBase); 707 } 708 if ( !pControl ) 709 { 710 pControl = GetActive( WINDOW_WARNINGBOX, MaybeBase); 711 } 712 if ( !pControl ) 713 { 714 pControl = GetActive( WINDOW_ERRORBOX, MaybeBase); 715 } 716 if ( !pControl ) 717 { 718 pControl = GetActive( WINDOW_QUERYBOX, MaybeBase); 719 } 720 if ( !pControl ) 721 { 722 pControl = GetActive( WINDOW_BUTTONDIALOG, MaybeBase); 723 } 724 if ( !pControl ) 725 { 726 pControl = GetActive( WINDOW_FILEDIALOG, MaybeBase); 727 } 728 if ( !pControl ) 729 { 730 pControl = GetActive( WINDOW_PATHDIALOG, MaybeBase); 731 } 732 if ( !pControl ) 733 { 734 pControl = GetActive( WINDOW_PRINTDIALOG, MaybeBase); 735 } 736 if ( !pControl ) 737 { 738 pControl = GetActive( WINDOW_PRINTERSETUPDIALOG, MaybeBase); 739 } 740 if ( !pControl ) 741 { 742 pControl = GetActive( WINDOW_COLORDIALOG, MaybeBase); 743 } 744 if ( !pControl ) 745 { 746 pControl = GetFocus( WINDOW_TABCONTROL, MaybeBase); 747 } 748 749 return pControl; 750 } 751 752 void StatementList::SetFirstDocFrame( Window* pWin ) 753 { 754 DBG_ASSERT( IsDocFrame( pWin ), "Non Document Frame set as first Document Frame" ); 755 pFirstDocFrame = pWin; 756 } 757 758 Window* StatementList::GetFirstDocFrame() 759 { 760 761 if ( pFirstDocFrame && !WinPtrValid( pFirstDocFrame ) ) 762 pFirstDocFrame = NULL; 763 if ( pFirstDocFrame && !pFirstDocFrame->IsVisible() ) 764 pFirstDocFrame = NULL; 765 if ( pFirstDocFrame && !IsDocFrame( pFirstDocFrame ) ) 766 pFirstDocFrame = NULL; 767 if ( !pFirstDocFrame ) 768 { 769 Window* pBase = Application::GetFirstTopLevelWindow(); 770 while ( pBase && !IsDocFrame( pBase ) ) 771 pBase = Application::GetNextTopLevelWindow( pBase ); 772 773 if ( pBase ) 774 SetFirstDocFrame( pBase ); 775 776 if ( !pBase ) // find just something 777 { 778 pBase = Application::GetFirstTopLevelWindow(); 779 while ( pBase && !pBase->IsVisible() ) 780 pBase = Application::GetNextTopLevelWindow( pBase ); 781 782 return pBase; // just for now, later we will hopefully have a Window 783 } 784 } 785 return pFirstDocFrame; 786 } 787 788 sal_Bool StatementList::IsFirstDocFrame( Window* pWin ) 789 { 790 return pWin && ( pWin == GetFirstDocFrame() || ( GetFirstDocFrame() && pWin == GetFirstDocFrame()->GetWindow( WINDOW_CLIENT ) ) ) && ( GetFirstDocFrame() && IsDocFrame( GetFirstDocFrame() ) ); 791 } 792 793 MenuBar* StatementList::GetDocFrameMenuBar( Window* pWin ) 794 { 795 if ( pWin && pWin->IsVisible() && pWin->GetType() == WINDOW_BORDERWINDOW ) 796 { 797 sal_uInt16 nCount; 798 for ( nCount = 0 ; nCount < pWin->GetChildCount() ; nCount++ ) 799 { 800 if ( pWin->GetChild( nCount )->GetType() == WINDOW_WORKWINDOW ) 801 return ((WorkWindow*)(pWin->GetChild( nCount )))->GetMenuBar(); 802 } 803 } 804 return NULL; 805 } 806 807 // a Doc Frame is a Document or the Backing Window 808 sal_Bool StatementList::IsDocFrame( Window* pWin ) 809 { 810 if ( pWin && pWin->IsVisible() && pWin->GetType() == WINDOW_BORDERWINDOW ) 811 { 812 sal_uInt16 nCount; 813 sal_Bool bHasWorkWindow = sal_False; 814 sal_Bool bHasMenuBar = sal_False; 815 // #91724# it is now necessary to sort out the IME WIndow in Solaris as well. 816 // so now we check for existence of WINDOW_WORKWINDOW and newly for 817 // WINDOW_MENUBARWINDOW which contains the Menu and the close/min/max buttons 818 for ( nCount = 0 ; nCount < pWin->GetChildCount() ; nCount++ ) 819 { 820 if ( pWin->GetChild( nCount )->GetType() == WINDOW_WORKWINDOW ) 821 bHasWorkWindow = sal_True; 822 if ( pWin->GetChild( nCount )->GetType() == WINDOW_MENUBARWINDOW ) 823 bHasMenuBar = sal_True; 824 } 825 return bHasWorkWindow && bHasMenuBar; 826 } 827 return sal_False; 828 } 829 830 // a Doc Win is a real document (not the Backing Window) 831 sal_Bool StatementList::IsDocWin( Window* pWin ) 832 { 833 if ( pWin && IsDocFrame( pWin ) ) 834 { 835 if ( GetDocFrameCount() != 1 ) 836 return sal_True; 837 else 838 { 839 // check for the close button to see if we are the last one or only the backing Window 840 if ( GetDocFrameMenuBar( pWin ) ) 841 return GetDocFrameMenuBar( pWin )->HasCloser(); 842 } 843 } 844 return sal_False; 845 } 846 847 sal_Bool StatementList::IsIMEWin( Window* pWin ) // Input Window for CJK under Solaris 848 { 849 if ( pWin && pWin->IsVisible() && pWin->GetType() == WINDOW_BORDERWINDOW ) 850 { 851 sal_uInt16 nCount; 852 sal_Bool bHasWorkWindow = sal_False; 853 sal_Bool bHasWindow = sal_False; 854 // #91724# it is now necessary to sort out the IME WIndow in Solaris as well. 855 // so now we check for existence of WINDOW_WORKWINDOW and newly for 856 // WINDOW_WINDOW which contains the Menu and the close/min/max buttons 857 for ( nCount = 0 ; nCount < pWin->GetChildCount() ; nCount++ ) 858 if ( pWin->GetChild( nCount )->GetType() == WINDOW_WORKWINDOW ) 859 bHasWorkWindow = sal_True; 860 for ( nCount = 0 ; nCount < pWin->GetChildCount() ; nCount++ ) 861 if ( pWin->GetChild( nCount )->GetType() == WINDOW_WINDOW ) 862 bHasWindow = sal_True; 863 return bHasWorkWindow && !bHasWindow; 864 } 865 return sal_False; 866 } 867 868 UniString StatementList::Tree(Window *pBase, int Indent) 869 { 870 871 String aReturn, aSep; 872 if ( !pBase ) 873 { 874 aSep.AssignAscii("============================\n"); 875 aSep.ConvertLineEnd(); 876 pBase = Application::GetFirstTopLevelWindow(); 877 while ( pBase ) 878 { 879 Window *pBaseFrame = pBase->GetWindow( WINDOW_OVERLAP ); 880 881 aReturn += aSep; 882 aReturn += Tree( pBaseFrame, Indent+1 ); 883 884 pBase = Application::GetNextTopLevelWindow( pBase ); 885 } 886 return aReturn; 887 } 888 889 890 aSep.AssignAscii("----------------------------\n"); 891 aSep.ConvertLineEnd(); 892 893 aReturn += ClientTree( pBase, Indent ); 894 895 if ( pBase->GetWindow( WINDOW_FIRSTOVERLAP ) ) 896 { 897 aReturn += aSep; 898 aReturn += Tree( pBase->GetWindow( WINDOW_FIRSTOVERLAP ), Indent+1 ); 899 } 900 901 if ( pBase->GetWindow( WINDOW_NEXT ) ) 902 { 903 aReturn += aSep; 904 aReturn += Tree( pBase->GetWindow( WINDOW_NEXT ), Indent ); 905 } 906 907 return aReturn; 908 } 909 910 String StatementList::ClientTree(Window *pBase, int Indent) 911 { 912 #if OSL_DEBUG_LEVEL > 1 913 #define WRITE(Text) { m_pDbgWin->AddText(Text); aReturn += Text; } 914 #define WRITEc(Text) { m_pDbgWin->AddText(Text); aReturn.AppendAscii(Text); } 915 #else 916 #define WRITE(Text) { aReturn += Text; } 917 #define WRITEc(Text) { aReturn.AppendAscii(Text); } 918 #endif 919 920 String sIndent,aText,aReturn; 921 sIndent.Expand(sal::static_int_cast< xub_StrLen >(2*Indent)); 922 923 aText = pBase->GetText(); 924 925 926 UniString t1,t2;t1 = CUniString("\n"); t2 = CUniString("\\n"); 927 aText.SearchAndReplaceAll(t1,t2 ); 928 929 WRITE(sIndent); 930 931 if (pBase->IsDialog()) 932 { 933 WRITEc("*(Dialog(TH))"); 934 } 935 if (IsDialog( pBase )) 936 { 937 WRITEc("*(Dialog(GH))"); 938 } 939 if (pBase->HasFocus()) 940 { 941 WRITEc("*(Focus)"); 942 } 943 if (!pBase->IsEnabled()) 944 { 945 WRITEc("*(Disab)"); 946 } 947 if (pBase->IsVisible()) 948 { 949 WRITEc("*(Visible)"); 950 } 951 if ( IsDialog(pBase) && ((SystemWindow*)pBase)->IsActive() ) 952 { 953 WRITEc("*(Active)"); 954 } 955 if ( pBase->GetStyle() & WB_CLOSEABLE ) 956 { 957 WRITEc("*(Closable)"); 958 } 959 if ( pBase->GetType() == WINDOW_DOCKINGWINDOW && 960 ((((DockingWindow*)pBase)->GetFloatStyle()) & WB_CLOSEABLE) ) 961 { 962 WRITEc("*(Closable Docking in Floatingstyle)"); 963 } 964 if ( pBase->GetStyle() & WB_DOCKABLE ) 965 { 966 WRITEc("*(Dockable)"); 967 } 968 if ( pBase->GetType() == WINDOW_SPLITWINDOW && 969 (((SplitWindow*)pBase)->IsFadeInButtonVisible() || ((SplitWindow*)pBase)->IsFadeOutButtonVisible()) ) 970 { 971 WRITEc("*(FadeIn/Out)"); 972 } 973 WRITEc("Text: "); 974 WRITE(aText); 975 WRITEc("\n"); 976 977 WRITE(sIndent); 978 WRITEc("UId : "); 979 WRITE(Id2Str(pBase->GetUniqueOrHelpId())); 980 WRITEc(":0x"); 981 WRITE( 982 String::CreateFromInt64( 983 sal::static_int_cast< sal_Int64 >( 984 reinterpret_cast< sal_IntPtr >(pBase)), 985 16 )); 986 WRITEc(":"); 987 WRITE(pBase->GetQuickHelpText()); 988 WRITEc(":"); 989 WRITE(pBase->GetHelpText()); 990 WRITEc("\n"); 991 992 WRITE(sIndent); 993 WRITEc("RTyp: "); 994 WRITE(MakeStringNumber(TypeKenn,pBase->GetType())); 995 if ( pBase->GetType() == WINDOW_CONTROL ) 996 { 997 if ( dynamic_cast< svt::EditBrowseBox* >(pBase) ) 998 WRITEc("/BrowseBox") 999 else if ( dynamic_cast< ValueSet* >(pBase) ) 1000 WRITEc("/ValueSet") 1001 else if ( dynamic_cast< svt::ORoadmap* >(pBase) ) 1002 WRITEc("/RoadMap") 1003 else if ( dynamic_cast< svt::IExtensionListBox* >(pBase) ) 1004 WRITEc("/ExtensionListBox") 1005 else if ( dynamic_cast< svt::table::TableControl* >(pBase) ) 1006 WRITEc("/TableControl") 1007 else 1008 WRITEc("/Unknown") 1009 } 1010 WRITEc("\n"); 1011 1012 aReturn.ConvertLineEnd(); 1013 sal_uInt16 i; 1014 for (i = 0 ; i < pBase->GetChildCount() ; i++) 1015 { 1016 aReturn += ClientTree(pBase->GetChild(i),Indent+1); 1017 } 1018 return aReturn; 1019 } 1020 1021 1022 sal_Bool StatementList::CheckWindowWait() 1023 { 1024 static Time StartTime = Time(0L); // Abbruch wenn Fenster absolut nicht schliesst. 1025 if ( StartTime == Time(0L) ) 1026 StartTime = Time(); 1027 1028 if ( pWindowWaitPointer ) 1029 { 1030 #if OSL_DEBUG_LEVEL > 1 1031 m_pDbgWin->AddText( "Waiting for Window to close ... " ); 1032 #endif 1033 if ( WinPtrValid(pWindowWaitPointer) && IS_WINP_CLOSING(pWindowWaitPointer) ) 1034 { 1035 #if OSL_DEBUG_LEVEL > 1 1036 m_pDbgWin->AddText( Id2Str(aWindowWaitUId).AppendAscii(" Still Open. RType=") ); 1037 m_pDbgWin->AddText( String::CreateFromInt32( pWindowWaitPointer->GetType() ).AppendAscii("\n") ); 1038 #endif 1039 1040 // Ist die Zeit schonn abgelaufen? 1041 if ( StartTime + Time(0,0,10) < Time() ) // 10 Sekunden reichen wohl 1042 { 1043 #if OSL_DEBUG_LEVEL > 1 1044 m_pDbgWin->AddText( "Close timed out. Going on!! " ); 1045 #endif 1046 pWindowWaitPointer->SetHelpId(aWindowWaitOldHelpId); 1047 pWindowWaitPointer->SetUniqueId(aWindowWaitOldUniqueId); 1048 1049 aWindowWaitUId = rtl::OString(); 1050 pWindowWaitPointer = NULL; 1051 StartTime = Time(0L); 1052 return sal_True; 1053 } 1054 1055 return sal_False; 1056 } 1057 pWindowWaitPointer = NULL; 1058 aWindowWaitUId = rtl::OString(); 1059 #if OSL_DEBUG_LEVEL > 1 1060 m_pDbgWin->AddText( "Closed, Going on.\n" ); 1061 #endif 1062 } 1063 StartTime = Time(0L); 1064 return sal_True; 1065 } 1066 1067 void StatementList::ReportError(String aMessage) 1068 { 1069 ReportError ( rtl::OString(), aMessage ); 1070 } 1071 1072 void StatementList::ReportError(rtl::OString aUId, String aMessage) 1073 { 1074 pRet->GenError ( aUId, aMessage ); 1075 IsError = sal_True; 1076 } 1077 1078 void StatementList::ReportError(String aMessage, sal_uLong nWhatever) 1079 { 1080 ReportError ( aMessage.AppendAscii(" ").Append(UniString::CreateFromInt32(nWhatever))); 1081 } 1082 1083 void StatementList::DirectLog( sal_uLong nType, String aMessage ) 1084 { 1085 if ( pRet ) 1086 pRet->GenReturn( RET_DirectLoging, (sal_uInt16) nType, aMessage ); 1087 } 1088 1089 1090 #define CALL_EVENT_WITH_NOTIFY( EventType, Event, WinP, Method ) \ 1091 { \ 1092 if ( StatementList::WinPtrValid( WinP ) ) \ 1093 { \ 1094 NotifyEvent aNEvt( EventType, WinP, &Event ); \ 1095 if ( !WinP->PreNotify( aNEvt ) ) \ 1096 WinP->Method( Event ); \ 1097 } \ 1098 } 1099 1100 void ImplKeyInput( Window* pWin, KeyEvent &aKEvnt, sal_Bool bForceDirect ) 1101 { 1102 1103 if ( StatementList::bUsePostEvents && !bForceDirect ) 1104 { 1105 if ( StatementList::WinPtrValid( pWin ) ) 1106 { 1107 sal_uLong nID1; 1108 sal_uLong nID2; 1109 nID1 = Application::PostKeyEvent( VCLEVENT_WINDOW_KEYINPUT, pWin, &aKEvnt ); 1110 nID2 = Application::PostKeyEvent( VCLEVENT_WINDOW_KEYUP, pWin, &aKEvnt ); 1111 // wait after posting both events so deleting pWin will remove the second event also 1112 ImplEventWait( nID1 ); 1113 ImplEventWait( nID2 ); 1114 } 1115 } 1116 else 1117 { 1118 if ( !Application::CallAccel( aKEvnt.GetKeyCode() ) ) 1119 { 1120 CALL_EVENT_WITH_NOTIFY( EVENT_KEYINPUT, aKEvnt, pWin, KeyInput ) 1121 1122 KeyCode aCode = aKEvnt.GetKeyCode(); 1123 if ( (aCode.GetCode() == KEY_CONTEXTMENU) || ((aCode.GetCode() == KEY_F10) && aCode.IsShift()) ) 1124 { 1125 if ( StatementList::WinPtrValid( pWin ) ) 1126 { 1127 Point aPos; 1128 // simulate mouseposition at center of window 1129 Size aSize = pWin->GetOutputSize(); 1130 aPos = Point( aSize.getWidth()/2, aSize.getHeight()/2 ); 1131 1132 CommandEvent aEvent( aPos, COMMAND_CONTEXTMENU, sal_False ); 1133 ImplCommand( pWin, aEvent ); 1134 } 1135 } 1136 } 1137 1138 CALL_EVENT_WITH_NOTIFY( EVENT_KEYUP, aKEvnt, pWin, KeyUp ) 1139 } 1140 }; 1141 1142 void ImplMouseMove( Window* pWin, MouseEvent &aMEvnt, sal_Bool bForceDirect ) 1143 { 1144 if ( StatementList::bUsePostEvents && !bForceDirect ) 1145 { 1146 if ( StatementList::WinPtrValid( pWin ) ) 1147 { 1148 sal_uLong nID; 1149 nID = Application::PostMouseEvent( VCLEVENT_WINDOW_MOUSEMOVE, pWin, &aMEvnt ); 1150 ImplEventWait( nID ); 1151 } 1152 } 1153 else 1154 { 1155 // DragManager* pDragManager = DragManager::GetDragManager(); 1156 // if ( pDragManager ) 1157 // pDragManager->MouseMove( aMEvnt, pWin ); 1158 // else 1159 if ( pWin->IsTracking() ) 1160 { 1161 TrackingEvent aTEvt( aMEvnt ); 1162 pWin->Tracking( aTEvt ); 1163 } 1164 else 1165 CALL_EVENT_WITH_NOTIFY( EVENT_MOUSEMOVE, aMEvnt, pWin, MouseMove ) 1166 } 1167 }; 1168 1169 void ImplMouseButtonDown( Window* pWin, MouseEvent &aMEvnt, sal_Bool bForceDirect ) 1170 { 1171 if ( StatementList::bUsePostEvents && !bForceDirect ) 1172 { 1173 if ( StatementList::WinPtrValid( pWin ) ) 1174 { 1175 sal_uLong nID; 1176 nID = Application::PostMouseEvent( VCLEVENT_WINDOW_MOUSEBUTTONDOWN, pWin, &aMEvnt ); 1177 ImplEventWait( nID ); 1178 } 1179 } 1180 else 1181 { 1182 CALL_EVENT_WITH_NOTIFY( EVENT_MOUSEBUTTONDOWN, aMEvnt, pWin, MouseButtonDown ) 1183 } 1184 }; 1185 1186 void ImplMouseButtonUp( Window* pWin, MouseEvent &aMEvnt, sal_Bool bForceDirect ) 1187 { 1188 if ( StatementList::bUsePostEvents && !bForceDirect ) 1189 { 1190 if ( StatementList::WinPtrValid( pWin ) ) 1191 { 1192 sal_uLong nID; 1193 nID = Application::PostMouseEvent( VCLEVENT_WINDOW_MOUSEBUTTONUP, pWin, &aMEvnt ); 1194 ImplEventWait( nID ); 1195 } 1196 } 1197 else 1198 { 1199 // DragManager* pDragManager = DragManager::GetDragManager(); 1200 // if ( pDragManager ) 1201 // pDragManager->ButtonUp( aMEvnt, pWin ); 1202 // else 1203 if ( pWin->IsTracking() ) 1204 { 1205 // siehe #64693 die Position ist f�r Toolboxen relevant 1206 // #60020 Jetzt hoffentlich kein GPF mehr 1207 // Zuerst Tracking beenden ohne Event 1208 pWin->EndTracking( ENDTRACK_DONTCALLHDL ); 1209 // dann eigenen Event mit richtigem Maus-Event senden 1210 TrackingEvent aTEvt( aMEvnt, ENDTRACK_END ); 1211 pWin->Tracking( aTEvt ); 1212 } 1213 else 1214 CALL_EVENT_WITH_NOTIFY( EVENT_MOUSEBUTTONUP, aMEvnt, pWin, MouseButtonUp ) 1215 } 1216 }; 1217 1218 void ImplEventWait( sal_uLong nID ) 1219 { 1220 while ( !Application::IsProcessedMouseOrKeyEvent( nID ) ) 1221 Application::Yield(); 1222 } 1223 1224 void ImplCommand( Window* pWin, CommandEvent &aCmdEvnt ) 1225 { 1226 CALL_EVENT_WITH_NOTIFY( EVENT_COMMAND, aCmdEvnt, pWin, Command ) 1227 }; 1228 1229