xref: /trunk/main/fpicker/source/win32/folderpicker/MtaFop.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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