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