1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_fpicker.hxx" 26 #include <osl/diagnose.h> 27 #include <osl/conditn.hxx> 28 29 #include "MtaFop.hxx" 30 #include <wchar.h> 31 #include <process.h> 32 #include "..\misc\resourceprovider.hxx" 33 34 #include <systools/win32/comtools.hxx> 35 36 using rtl::OUString; 37 using osl::Condition; 38 39 const sal_uInt32 MSG_BROWSEFORFOLDER = WM_USER + 1; 40 const sal_uInt32 MSG_SHUTDOWN = WM_USER + 2; 41 42 const sal_uInt32 MAX_WAITTIME = 2000; // msec 43 44 const sal_Bool MANUAL_RESET = sal_True; 45 const sal_Bool AUTO_RESET = sal_False; 46 const sal_Bool INIT_NONSIGNALED = sal_False; 47 48 typedef sal::systools::COMReference<IMalloc> IMallocPtr; 49 typedef sal::systools::COMReference<IShellFolder> IShellFolderPtr; 50 51 namespace 52 { 53 const char* FOLDERPICKER_SRV_DLL_NAME = "fop.dll"; 54 const char g_szWndClsName[] = "FopStaReqWnd###"; 55 const char* CURRENT_INSTANCE = "CurrInst"; 56 57 typedef struct _RequestContext 58 { 59 HANDLE hEvent; 60 sal_Bool bRet; 61 } RequestContext; 62 63 inline sal_Bool InitializeRequestContext( RequestContext* aRequestContext ) 64 { 65 OSL_ASSERT( aRequestContext ); 66 67 aRequestContext->hEvent = CreateEventA( 68 0, AUTO_RESET, INIT_NONSIGNALED, NULL ); 69 70 aRequestContext->bRet = sal_False; 71 72 return ( 0 != aRequestContext->hEvent ); 73 } 74 75 inline void DeinitializeRequestContext( RequestContext* aRequestContext ) 76 { 77 OSL_ASSERT( aRequestContext && aRequestContext->hEvent ); 78 CloseHandle( aRequestContext->hEvent ); 79 } 80 81 //------------------------------- 82 // Determine if current thread is 83 // an MTA or STA thread 84 //------------------------------- 85 bool IsMTA() 86 { 87 HRESULT hr = CoInitialize(NULL); 88 89 if (RPC_E_CHANGED_MODE == hr) 90 return true; 91 92 if(SUCCEEDED(hr)) 93 CoUninitialize(); 94 95 return false; 96 } 97 } 98 99 //---------------------------------------------------------------- 100 // static member initialization 101 //---------------------------------------------------------------- 102 103 ATOM CMtaFolderPicker::s_ClassAtom = 0; 104 osl::Mutex CMtaFolderPicker::s_Mutex; 105 sal_Int32 CMtaFolderPicker::s_StaRequestWndRegisterCount = 0; 106 107 //-------------------------------------------------------------------- 108 // ctor 109 //-------------------------------------------------------------------- 110 111 CMtaFolderPicker::CMtaFolderPicker( sal_uInt32 Flags ) : 112 m_hStaThread( NULL ), 113 m_uStaThreadId( 0 ), 114 m_hEvtThrdReady( NULL ), 115 m_hwndStaRequestWnd( NULL ) 116 { 117 m_hInstance = GetModuleHandleA( FOLDERPICKER_SRV_DLL_NAME ); 118 OSL_ENSURE( m_hInstance, "The name of the FolderPicker service dll must have changed" ); 119 120 ZeroMemory( &m_bi, sizeof( m_bi ) ); 121 122 // !!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!! 123 // 124 // Remember: This HACK prevents you from stepping 125 // through your code in the debugger because if you 126 // set a break point in the ctor here the debugger 127 // may become the owner of the FolderBrowse dialog 128 // and so it seems that the Visual Studio and the 129 // office are hanging 130 m_bi.hwndOwner = GetForegroundWindow( ); 131 132 /* 133 Flag Available 134 -------------------------------- 135 BIF_EDITBOX Version 4.71 136 BIF_NEWDIALOGSTYLE Version 5.0 137 BIF_SHAREABLE Version 5.0 138 BIF_VALIDATE Version 4.71 139 140 Version 4.71 - Internet Explorer 4.0 141 Version 5.0 - Internet Explorer 5.0 142 Windows 2000 143 */ 144 m_bi.ulFlags = Flags; 145 146 m_bi.lpfn = CMtaFolderPicker::FolderPickerCallback; 147 m_bi.lParam = reinterpret_cast< LPARAM >( this ); 148 149 //--------------------------------------- 150 // read the default strings for title and 151 // description from a resource file 152 153 CResourceProvider ResProvider; 154 155 m_dialogTitle = ResProvider.getResString( 500 ); 156 m_Description = ResProvider.getResString( 501 ); 157 158 // signals that the thread was successfully set up 159 m_hEvtThrdReady = CreateEventA( 160 0, 161 MANUAL_RESET, 162 INIT_NONSIGNALED, 163 NULL ); 164 165 if ( m_hEvtThrdReady ) 166 { 167 // setup the sta thread 168 m_hStaThread = (HANDLE)_beginthreadex( 169 NULL, 170 0, 171 CMtaFolderPicker::StaThreadProc, 172 this, 173 0, 174 &m_uStaThreadId ); 175 176 OSL_ASSERT( m_hStaThread ); 177 } 178 179 OSL_ASSERT( m_hEvtThrdReady ); 180 } 181 182 //-------------------------------------------------------------------- 183 // dtor 184 //-------------------------------------------------------------------- 185 186 CMtaFolderPicker::~CMtaFolderPicker( ) 187 { 188 // only if the is a valid event handle 189 // there may also be a thread a hidden 190 // target request window and so on 191 // see ctor 192 if ( m_hEvtThrdReady ) 193 { 194 // block calling threads because we 195 // are about to shutdown 196 ResetEvent( m_hEvtThrdReady ); 197 198 // force the destruction of the sta thread request window 199 // and the end of the thread 200 // remeber: DestroyWindow may only be called from within 201 // the thread that created the window 202 if ( IsWindow( m_hwndStaRequestWnd ) ) 203 { 204 SendMessageA( m_hwndStaRequestWnd, MSG_SHUTDOWN, 0, 0 ); 205 206 // we place unregister class here because 207 // if we have a valid window we must have 208 // sucessfully registered a window class 209 // if the creation of the window itself 210 // failed after registering the window 211 // class we have unregistered it immediately 212 // in createStaRequestWindow below 213 UnregisterStaRequestWindowClass( ); 214 } 215 216 if ( m_hStaThread ) 217 { 218 // wait for thread shutdown 219 sal_uInt32 dwResult = WaitForSingleObject( m_hStaThread, MAX_WAITTIME ); 220 OSL_ENSURE( dwResult == WAIT_OBJECT_0, "sta thread could not terminate" ); 221 222 // terminate the thread if it 223 // doesn't shutdown itself 224 if ( WAIT_OBJECT_0 != dwResult ) 225 TerminateThread( 226 m_hStaThread, sal::static_int_cast< DWORD >(-1) ); 227 228 CloseHandle( m_hStaThread ); 229 } 230 231 CloseHandle( m_hEvtThrdReady ); 232 } 233 } 234 235 //-------------------------------------------------------------------- 236 // 237 //-------------------------------------------------------------------- 238 239 sal_Bool CMtaFolderPicker::browseForFolder( ) 240 { 241 sal_Bool bRet = sal_False; 242 243 if (IsMTA()) 244 { 245 246 OSL_ASSERT( m_hEvtThrdReady ); 247 248 if ( WaitForSingleObject( m_hEvtThrdReady, MAX_WAITTIME ) != WAIT_OBJECT_0 ) 249 { 250 OSL_ENSURE( sal_False, "sta thread not ready" ); 251 return sal_False; 252 } 253 254 RequestContext aReqCtx; 255 256 if ( !InitializeRequestContext( &aReqCtx ) ) 257 { 258 OSL_ASSERT( sal_False ); 259 return sal_False; 260 } 261 262 // marshall request into the sta thread 263 PostMessageA( 264 m_hwndStaRequestWnd, 265 MSG_BROWSEFORFOLDER, 266 0, 267 reinterpret_cast< LPARAM >( &aReqCtx ) ); 268 269 // waiting for the event to be signaled or 270 // window messages so that we don't block 271 // our parent window 272 273 sal_Bool bContinue = sal_True; 274 275 while ( bContinue ) 276 { 277 DWORD dwResult = MsgWaitForMultipleObjects( 278 1, &aReqCtx.hEvent, sal_False, INFINITE, QS_ALLEVENTS ); 279 280 switch ( dwResult ) 281 { 282 // the request context event is signaled 283 case WAIT_OBJECT_0: 284 bContinue = sal_False; 285 break; 286 287 // a window message has arrived 288 case WAIT_OBJECT_0 + 1: 289 { 290 // dispatching all messages but we expect to 291 // receive only paint or timer messages that's 292 // why we don't need to call TranslateMessage or 293 // TranslateAccelerator, because keybord or 294 // mouse messages are for the FolderPicker which 295 // is in the foreground and should not arrive here 296 MSG msg; 297 while ( PeekMessageA( &msg, NULL, 0, 0, PM_REMOVE ) ) 298 DispatchMessageA(&msg); 299 } 300 break; 301 302 // should not happen 303 default: 304 OSL_ASSERT( sal_False ); 305 } 306 } 307 308 /*sal_Bool*/ bRet = aReqCtx.bRet; 309 DeinitializeRequestContext( &aReqCtx ); 310 } 311 else 312 { 313 bRet = onBrowseForFolder(); 314 } 315 316 return bRet; 317 } 318 319 //-------------------------------------------------------------------- 320 // 321 //-------------------------------------------------------------------- 322 323 void SAL_CALL CMtaFolderPicker::setDisplayDirectory( const OUString& aDirectory ) 324 { 325 m_displayDir = aDirectory; 326 } 327 328 //-------------------------------------------------------------------- 329 // 330 //-------------------------------------------------------------------- 331 332 OUString SAL_CALL CMtaFolderPicker::getDisplayDirectory( ) 333 { 334 return m_displayDir; 335 } 336 337 //-------------------------------------------------------------------- 338 // 339 //-------------------------------------------------------------------- 340 341 OUString SAL_CALL CMtaFolderPicker::getDirectory( ) 342 { 343 return m_SelectedDir; 344 } 345 346 //-------------------------------------------------------------------- 347 // 348 //-------------------------------------------------------------------- 349 350 void SAL_CALL CMtaFolderPicker::setDescription( const rtl::OUString& aDescription ) 351 { 352 m_Description = aDescription; 353 } 354 355 //-------------------------------------------------------------------- 356 // 357 //-------------------------------------------------------------------- 358 359 void SAL_CALL CMtaFolderPicker::setTitle( const OUString& aTitle ) 360 { 361 m_dialogTitle = aTitle; 362 } 363 364 //-------------------------------------------------------------------- 365 // 366 //-------------------------------------------------------------------- 367 368 OUString SAL_CALL CMtaFolderPicker::getTitle( ) 369 { 370 return m_dialogTitle; 371 } 372 373 //----------------------------------------------------- 374 // XCancellable 375 //----------------------------------------------------- 376 377 void SAL_CALL CMtaFolderPicker::cancel( ) 378 { 379 if ( IsWindow( m_hwnd ) ) 380 { 381 // simulate a mouse click to the 382 // cancel button 383 PostMessageA( 384 m_hwnd, 385 WM_COMMAND, 386 MAKEWPARAM( IDCANCEL, BN_CLICKED ), 387 (LPARAM)GetDlgItem( m_hwnd, IDCANCEL ) ); 388 } 389 } 390 391 //-------------------------------------------------------------------- 392 // 393 //-------------------------------------------------------------------- 394 395 sal_Bool SAL_CALL CMtaFolderPicker::onBrowseForFolder( ) 396 { 397 sal_Bool bRet; 398 LPITEMIDLIST lpiid; 399 400 // pre SHBrowseFroFolder 401 402 m_bi.pidlRoot = 0; 403 m_bi.pszDisplayName = reinterpret_cast<LPWSTR>(m_pathBuff.get()); 404 405 if ( m_Description.getLength( ) ) 406 m_bi.lpszTitle = reinterpret_cast<LPCWSTR>(m_Description.getStr( )); 407 408 lpiid = SHBrowseForFolderW( &m_bi ); 409 bRet = ( NULL != lpiid ); 410 411 // post SHBrowseForFolder 412 413 m_SelectedDir = getPathFromItemIdList( lpiid ); 414 releaseItemIdList( lpiid ); 415 416 return bRet; 417 } 418 419 //-------------------------------------------------------------------- 420 // 421 //-------------------------------------------------------------------- 422 423 void SAL_CALL CMtaFolderPicker::releaseItemIdList( LPITEMIDLIST lpItemIdList ) 424 { 425 IMallocPtr pIMalloc; 426 SHGetMalloc(&pIMalloc); 427 if (pIMalloc.is()) 428 { 429 pIMalloc->Free(lpItemIdList); 430 lpItemIdList = NULL; 431 } 432 } 433 434 //-------------------------------------------------------------------- 435 // 436 //-------------------------------------------------------------------- 437 438 LPITEMIDLIST SAL_CALL CMtaFolderPicker::getItemIdListFromPath( const rtl::OUString& aDirectory ) 439 { 440 // parameter checking 441 if ( !aDirectory.getLength( ) ) 442 return NULL; 443 444 LPITEMIDLIST lpItemIdList(NULL); 445 446 IShellFolderPtr pIShellFolder; 447 SHGetDesktopFolder(&pIShellFolder); 448 449 if (pIShellFolder.is()) 450 { 451 pIShellFolder->ParseDisplayName( 452 NULL, 453 NULL, 454 reinterpret_cast<LPWSTR>(const_cast< sal_Unicode* >( aDirectory.getStr( ) )), 455 NULL, 456 &lpItemIdList, 457 NULL ); 458 } 459 460 return lpItemIdList; 461 } 462 463 //-------------------------------------------------------------------- 464 // 465 //-------------------------------------------------------------------- 466 467 OUString SAL_CALL CMtaFolderPicker::getPathFromItemIdList( LPCITEMIDLIST lpItemIdList ) 468 { 469 OUString path; 470 471 if ( lpItemIdList ) 472 { 473 bool bRet = SHGetPathFromIDListW( lpItemIdList, reinterpret_cast<LPWSTR>(m_pathBuff.get()) ); 474 if ( bRet ) 475 path = m_pathBuff.get( ); 476 } 477 478 return path; 479 } 480 481 //-------------------------------------------------------------------- 482 // 483 //-------------------------------------------------------------------- 484 485 void SAL_CALL CMtaFolderPicker::enableOk( sal_Bool bEnable ) 486 { 487 OSL_ASSERT( IsWindow( m_hwnd ) ); 488 489 SendMessageW( 490 m_hwnd, 491 BFFM_ENABLEOK, 492 static_cast< WPARAM >( 0 ), 493 static_cast< LPARAM >( bEnable ) ); 494 } 495 496 //-------------------------------------------------------------------- 497 // 498 //-------------------------------------------------------------------- 499 500 void SAL_CALL CMtaFolderPicker::setSelection( const rtl::OUString& aDirectory ) 501 { 502 OSL_ASSERT( IsWindow( m_hwnd ) ); 503 504 #ifdef _MSC_VER 505 #pragma message( "#######################################" ) 506 #pragma message( "SendMessageW wrapper has to be extended" ) 507 #pragma message( "#######################################" ) 508 #endif 509 510 SendMessageW( 511 m_hwnd, 512 BFFM_SETSELECTIONW, 513 static_cast< WPARAM >( sal_True ), 514 reinterpret_cast< LPARAM >( aDirectory.getStr( ) ) ); 515 } 516 517 //-------------------------------------------------------------------- 518 // 519 //-------------------------------------------------------------------- 520 521 void SAL_CALL CMtaFolderPicker::setStatusText( const rtl::OUString& aStatusText ) 522 { 523 OSL_ASSERT( IsWindow( m_hwnd ) ); 524 525 SendMessageW( 526 m_hwnd, 527 BFFM_SETSTATUSTEXTW, 528 static_cast< WPARAM >( 0 ), 529 reinterpret_cast< LPARAM >( aStatusText.getStr( ) ) ); 530 } 531 532 //-------------------------------------------------------------------- 533 // 534 //-------------------------------------------------------------------- 535 536 void SAL_CALL CMtaFolderPicker::onInitialized( ) 537 { 538 LPITEMIDLIST lpiidDisplayDir = getItemIdListFromPath( m_displayDir ); 539 540 if ( lpiidDisplayDir ) 541 { 542 SendMessageA( 543 m_hwnd, 544 BFFM_SETSELECTION, 545 (WPARAM)sal_False, 546 (LPARAM) lpiidDisplayDir ); 547 548 releaseItemIdList( lpiidDisplayDir ); 549 } 550 } 551 552 //-------------------------------------------------------------------- 553 // 554 //-------------------------------------------------------------------- 555 556 sal_uInt32 CMtaFolderPicker::onValidateFailed() 557 { 558 // to be overwritten by subclasses 559 return 1; 560 } 561 562 //-------------------------------------------------------------------- 563 // 564 //-------------------------------------------------------------------- 565 566 int CALLBACK CMtaFolderPicker::FolderPickerCallback( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData ) 567 { 568 CMtaFolderPicker* pImpl = reinterpret_cast< CMtaFolderPicker* >( lpData ); 569 OSL_ASSERT( pImpl ); 570 571 int nRC = 0; 572 573 switch( uMsg ) 574 { 575 case BFFM_INITIALIZED: 576 pImpl->m_hwnd = hwnd; 577 pImpl->onInitialized( ); 578 SetWindowTextW( hwnd, reinterpret_cast<LPCWSTR>(pImpl->m_dialogTitle.getStr()) ); 579 break; 580 581 case BFFM_SELCHANGED: 582 pImpl->m_hwnd = hwnd; 583 pImpl->onSelChanged( 584 pImpl->getPathFromItemIdList( 585 reinterpret_cast< LPITEMIDLIST >( lParam ) ) ); 586 break; 587 588 case BFFM_VALIDATEFAILEDW: 589 nRC = pImpl->onValidateFailed(); 590 break; 591 592 default: 593 OSL_ASSERT( sal_False ); 594 } 595 596 return nRC; 597 } 598 599 //-------------------------------------------------------------------- 600 // the window proc 601 //-------------------------------------------------------------------- 602 603 LRESULT CALLBACK CMtaFolderPicker::StaWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 604 { 605 LRESULT lResult = 0; 606 CMtaFolderPicker* pImpl = NULL; 607 608 /* 609 we connect to the belonging class instance of this 610 window using SetProp, GetProp etc. 611 this may fail if somehow the class instance destroyed 612 before the window 613 */ 614 615 switch( uMsg ) 616 { 617 case WM_CREATE: 618 { 619 LPCREATESTRUCT lpcs = 620 reinterpret_cast< LPCREATESTRUCT >( lParam ); 621 622 OSL_ASSERT( lpcs->lpCreateParams ); 623 624 // connect the instance handle to the window 625 SetPropA( hWnd, CURRENT_INSTANCE, lpcs->lpCreateParams ); 626 } 627 break; 628 629 case WM_NCDESTROY: 630 // RemoveProp returns the saved value on success 631 pImpl = reinterpret_cast< CMtaFolderPicker* >( 632 RemovePropA( hWnd, CURRENT_INSTANCE ) ); 633 634 OSL_ASSERT( pImpl && !IsBadReadPtr( pImpl, sizeof( CMtaFolderPicker ) ) ); 635 break; 636 637 case MSG_BROWSEFORFOLDER: 638 { 639 RequestContext* aReqCtx = reinterpret_cast< RequestContext* >( lParam ); 640 OSL_ASSERT( aReqCtx ); 641 642 pImpl = reinterpret_cast< CMtaFolderPicker* >( 643 GetPropA( hWnd, CURRENT_INSTANCE ) ); 644 645 OSL_ASSERT( pImpl && !IsBadReadPtr( pImpl, sizeof( CMtaFolderPicker ) ) ); 646 647 aReqCtx->bRet = pImpl->onBrowseForFolder( ); 648 SetEvent( aReqCtx->hEvent ); 649 } 650 break; 651 652 case MSG_SHUTDOWN: 653 pImpl = reinterpret_cast< CMtaFolderPicker* >( 654 GetPropA( hWnd, CURRENT_INSTANCE ) ); 655 656 OSL_ASSERT( pImpl && !IsBadReadPtr( pImpl, sizeof( CMtaFolderPicker ) ) ); 657 658 DestroyWindow( pImpl->m_hwndStaRequestWnd ); 659 break; 660 661 case WM_DESTROY: 662 PostQuitMessage( 0 ); 663 break; 664 665 default: 666 lResult = DefWindowProcA( hWnd, uMsg, wParam, lParam ); 667 break; 668 } 669 670 return lResult; 671 } 672 673 //-------------------------------------------------------------------- 674 // 675 //-------------------------------------------------------------------- 676 677 sal_Bool SAL_CALL CMtaFolderPicker::createStaRequestWindow( ) 678 { 679 bool bIsWnd = false; 680 681 if ( RegisterStaRequestWindowClass( ) ) 682 { 683 m_hwndStaRequestWnd = CreateWindowA( 684 g_szWndClsName, NULL, 685 0, 0, 0, 0, 0, 686 NULL, NULL, m_hInstance, 687 (LPVOID)this // provide the instance of the class 688 ); 689 690 bIsWnd = IsWindow( m_hwndStaRequestWnd ); 691 692 // we do immediately unregister the window class 693 // if the creation of the window fails because we 694 // don't want to spoil the register class counter 695 if ( !bIsWnd ) 696 UnregisterStaRequestWindowClass( ); 697 698 OSL_ENSURE( bIsWnd, "sta request window creation failed" ); 699 } 700 701 return bIsWnd; 702 } 703 704 //-------------------------------------------------------------------- 705 // 706 //-------------------------------------------------------------------- 707 708 unsigned int CMtaFolderPicker::run( ) 709 { 710 OSL_ASSERT( m_hEvtThrdReady ); 711 712 // setup an sta environment 713 HRESULT hr = CoInitialize( NULL ); 714 715 // if we can't setup an sta environment 716 // we stop here and return 717 if ( FAILED( hr ) ) 718 { 719 OSL_ENSURE( sal_False, "CoInitialize failed" ); 720 return sal::static_int_cast< unsigned int >(-1); 721 } 722 723 unsigned int nRet; 724 725 if ( createStaRequestWindow( ) ) 726 { 727 SetEvent( m_hEvtThrdReady ); 728 729 // pumping messages 730 MSG msg; 731 while( GetMessageA( &msg, NULL, 0, 0 ) ) 732 DispatchMessageA( &msg ); 733 734 nRet = 0; 735 } 736 else 737 { 738 OSL_ENSURE( sal_False, "failed to create sta thread" ); 739 nRet = sal::static_int_cast< unsigned int >(-1); 740 } 741 742 // shutdown sta environment 743 CoUninitialize( ); 744 745 return nRet; 746 } 747 748 //-------------------------------------------------------------------- 749 // 750 //-------------------------------------------------------------------- 751 752 unsigned int WINAPI CMtaFolderPicker::StaThreadProc( LPVOID pParam ) 753 { 754 CMtaFolderPicker* pInst = 755 reinterpret_cast<CMtaFolderPicker*>( pParam ); 756 757 OSL_ASSERT( pInst ); 758 759 HRESULT hr = OleInitialize( NULL ); 760 761 unsigned int result = pInst->run( ); 762 763 if ( SUCCEEDED( hr ) ) 764 OleUninitialize(); 765 766 return result; 767 } 768 769 //--------------------------------------------------- 770 // 771 //--------------------------------------------------- 772 773 ATOM SAL_CALL CMtaFolderPicker::RegisterStaRequestWindowClass( ) 774 { 775 osl::MutexGuard aGuard( s_Mutex ); 776 777 if ( 0 == s_ClassAtom ) 778 { 779 WNDCLASSEXA wcex; 780 781 ZeroMemory( &wcex, sizeof( WNDCLASSEXA ) ); 782 783 wcex.cbSize = sizeof(WNDCLASSEXA); 784 wcex.style = 0; 785 wcex.lpfnWndProc = static_cast< WNDPROC >( CMtaFolderPicker::StaWndProc ); 786 wcex.cbClsExtra = 0; 787 wcex.cbWndExtra = 0; 788 wcex.hInstance = m_hInstance; 789 wcex.hIcon = NULL; 790 wcex.hCursor = NULL; 791 wcex.hbrBackground = NULL; 792 wcex.lpszMenuName = NULL; 793 wcex.lpszClassName = g_szWndClsName; 794 wcex.hIconSm = NULL; 795 796 s_ClassAtom = RegisterClassExA( &wcex ); 797 OSL_ASSERT( s_ClassAtom ); 798 } 799 800 // increment the register class counter 801 // so that we keep track of the number 802 // of class registrations 803 if ( 0 != s_ClassAtom ) 804 s_StaRequestWndRegisterCount++; 805 806 return s_ClassAtom; 807 } 808 809 //--------------------------------------------------- 810 // 811 //--------------------------------------------------- 812 813 void SAL_CALL CMtaFolderPicker::UnregisterStaRequestWindowClass( ) 814 { 815 osl::MutexGuard aGuard( s_Mutex ); 816 817 OSL_ASSERT( 0 != s_ClassAtom ); 818 819 // update the register class counter 820 // and unregister the window class if 821 // counter drops to zero 822 if ( 0 != s_ClassAtom ) 823 { 824 s_StaRequestWndRegisterCount--; 825 OSL_ASSERT( s_StaRequestWndRegisterCount >= 0 ); 826 } 827 828 if ( 0 == s_StaRequestWndRegisterCount ) 829 { 830 UnregisterClass( 831 (LPCTSTR)MAKELONG( s_ClassAtom, 0 ), m_hInstance ); 832 833 s_ClassAtom = 0; 834 } 835 } 836