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