xref: /AOO41X/main/fpicker/source/win32/folderpicker/MtaFop.cxx (revision b557fc96600fce3029f73c89748b6c08fd00b34d)
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 
InitializeRequestContext(RequestContext * aRequestContext)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 
DeinitializeRequestContext(RequestContext * aRequestContext)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     //-------------------------------
IsMTA()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 
CMtaFolderPicker(sal_uInt32 Flags)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 
~CMtaFolderPicker()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 
browseForFolder()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 
setDisplayDirectory(const OUString & aDirectory)323 void SAL_CALL CMtaFolderPicker::setDisplayDirectory( const OUString& aDirectory )
324 {
325     m_displayDir = aDirectory;
326 }
327 
328 //--------------------------------------------------------------------
329 //
330 //--------------------------------------------------------------------
331 
getDisplayDirectory()332 OUString SAL_CALL CMtaFolderPicker::getDisplayDirectory( )
333 {
334     return m_displayDir;
335 }
336 
337 //--------------------------------------------------------------------
338 //
339 //--------------------------------------------------------------------
340 
getDirectory()341 OUString SAL_CALL CMtaFolderPicker::getDirectory( )
342 {
343     return m_SelectedDir;
344 }
345 
346 //--------------------------------------------------------------------
347 //
348 //--------------------------------------------------------------------
349 
setDescription(const rtl::OUString & aDescription)350 void SAL_CALL CMtaFolderPicker::setDescription( const rtl::OUString& aDescription )
351 {
352     m_Description = aDescription;
353 }
354 
355 //--------------------------------------------------------------------
356 //
357 //--------------------------------------------------------------------
358 
setTitle(const OUString & aTitle)359 void SAL_CALL CMtaFolderPicker::setTitle( const OUString& aTitle )
360 {
361     m_dialogTitle = aTitle;
362 }
363 
364 //--------------------------------------------------------------------
365 //
366 //--------------------------------------------------------------------
367 
getTitle()368 OUString SAL_CALL CMtaFolderPicker::getTitle( )
369 {
370     return m_dialogTitle;
371 }
372 
373 //-----------------------------------------------------
374 // XCancellable
375 //-----------------------------------------------------
376 
cancel()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 
onBrowseForFolder()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 
releaseItemIdList(LPITEMIDLIST lpItemIdList)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 
getItemIdListFromPath(const rtl::OUString & aDirectory)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 
getPathFromItemIdList(LPCITEMIDLIST lpItemIdList)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 
enableOk(sal_Bool bEnable)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 
setSelection(const rtl::OUString & aDirectory)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 
setStatusText(const rtl::OUString & aStatusText)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 
onInitialized()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 
onValidateFailed()556 sal_uInt32 CMtaFolderPicker::onValidateFailed()
557 {
558     // to be overwritten by subclasses
559     return 1;
560 }
561 
562 //--------------------------------------------------------------------
563 //
564 //--------------------------------------------------------------------
565 
FolderPickerCallback(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData)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 
StaWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)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 
createStaRequestWindow()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 
run()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 
StaThreadProc(LPVOID pParam)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 
RegisterStaRequestWindowClass()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 
UnregisterStaRequestWindowClass()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