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