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_vcl.hxx"
26
27 #include "rtl/logfile.hxx"
28
29 #include "osl/file.hxx"
30
31 #include "vos/signal.hxx"
32 #include "vos/process.hxx"
33
34 #include "tools/tools.h"
35 #include "tools/debug.hxx"
36 #include "tools/unqid.hxx"
37 #include "tools/resmgr.hxx"
38
39 #include "comphelper/processfactory.hxx"
40
41 #include "unotools/syslocaleoptions.hxx"
42 #include "unotools/fontcfg.hxx"
43
44 #include "vcl/svapp.hxx"
45 #include "vcl/wrkwin.hxx"
46 #include "vcl/cvtgrf.hxx"
47 #include "vcl/image.hxx"
48 #include "vcl/settings.hxx"
49 #include "vcl/unowrap.hxx"
50 #include "vcl/configsettings.hxx"
51 #include "vcl/lazydelete.hxx"
52
53 #ifdef WNT
54 #include <tools/prewin.h>
55 #include <process.h> // for _beginthreadex
56 #include <ole2.h> // for _beginthreadex
57 #include <tools/postwin.h>
58 #include <com/sun/star/accessibility/XMSAAService.hpp>
59 #include <win/g_msaasvc.h>
60 using namespace com::sun::star::accessibility;
61 #endif
62
63 // [ed 5/14/02 Add in explicit check for quartz graphics. OS X will define
64 // unx for both quartz and X11 graphics, but we include svunx.h only if we're
65 // building X11 graphics layers.
66
67 #if defined UNX && ! defined QUARTZ
68 //#include "svunx.h"
69 #endif
70
71 //#include "svsys.h"
72
73 #include "salinst.hxx"
74 #include "salwtype.hxx"
75 #include "svdata.hxx"
76 #include "dbggui.hxx"
77 #include "accmgr.hxx"
78 #include "idlemgr.hxx"
79 #include "outdev.h"
80 #include "outfont.hxx"
81 #include "print.h"
82 #include "salsys.hxx"
83 #include "saltimer.hxx"
84 #include "salimestatus.hxx"
85 #include "impimagetree.hxx"
86 #include "xconnection.hxx"
87
88 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
89 #include "com/sun/star/lang/XComponent.hpp"
90
91 #include "cppuhelper/implbase1.hxx"
92 #include "uno/current_context.hxx"
93
94 #if OSL_DEBUG_LEVEL > 0
95 #include <typeinfo>
96 #include "rtl/strbuf.hxx"
97 #endif
98
99 namespace {
100
101 namespace css = com::sun::star;
102
103 }
104
105 using namespace ::rtl;
106 using namespace ::com::sun::star::uno;
107 using namespace ::com::sun::star::lang;
108
109
110
111 // =======================================================================
112
113 class ImplVCLExceptionHandler : public ::vos::OSignalHandler
114 {
115 public:
116 virtual ::vos::OSignalHandler::TSignalAction SAL_CALL signal( ::vos::OSignalHandler::TSignalInfo* pInfo );
117 };
118
119 // -----------------------------------------------------------------------
120
signal(::vos::OSignalHandler::TSignalInfo * pInfo)121 ::vos::OSignalHandler::TSignalAction SAL_CALL ImplVCLExceptionHandler::signal( ::vos::OSignalHandler::TSignalInfo* pInfo )
122 {
123 static sal_Bool bIn = sal_False;
124
125 // Wenn wir nocheinmal abstuerzen, verabschieden wir uns gleich
126 if ( !bIn )
127 {
128 sal_uInt16 nVCLException = 0;
129
130 // UAE
131 if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
132 (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
133 (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
134 (pInfo->Signal == osl_Signal_DebugBreak) )
135 nVCLException = EXC_SYSTEM;
136
137 // RC
138 if ((pInfo->Signal == osl_Signal_User) &&
139 (pInfo->UserSignal == OSL_SIGNAL_USER_RESOURCEFAILURE) )
140 nVCLException = EXC_RSCNOTLOADED;
141
142 // DISPLAY-Unix
143 if ((pInfo->Signal == osl_Signal_User) &&
144 (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
145 nVCLException = EXC_DISPLAY;
146
147 // Remote-Client
148 if ((pInfo->Signal == osl_Signal_User) &&
149 (pInfo->UserSignal == OSL_SIGNAL_USER_RVPCONNECTIONERROR) )
150 nVCLException = EXC_REMOTE;
151
152 if ( nVCLException )
153 {
154 bIn = sal_True;
155
156 ::vos::OGuard aLock(&Application::GetSolarMutex());
157
158 // Timer nicht mehr anhalten, da ansonsten die UAE-Box
159 // auch nicht mehr gepaintet wird
160 ImplSVData* pSVData = ImplGetSVData();
161 if ( pSVData->mpApp )
162 {
163 sal_uInt16 nOldMode = Application::GetSystemWindowMode();
164 Application::SetSystemWindowMode( nOldMode & ~SYSTEMWINDOW_MODE_NOAUTOMODE );
165 pSVData->mpApp->Exception( nVCLException );
166 Application::SetSystemWindowMode( nOldMode );
167 }
168 bIn = sal_False;
169
170 return vos::OSignalHandler::TAction_CallNextHandler;
171 }
172 }
173
174 return vos::OSignalHandler::TAction_CallNextHandler;
175 }
176
177 // =======================================================================
ImplSVMain()178 sal_Bool ImplSVMain()
179 {
180 // The 'real' SVMain()
181 RTL_LOGFILE_CONTEXT( aLog, "vcl (ss112471) ::SVMain" );
182
183 ImplSVData* pSVData = ImplGetSVData();
184
185 DBG_ASSERT( pSVData->mpApp, "no instance of class Application" );
186
187 css::uno::Reference<XMultiServiceFactory> xMS;
188
189
190 sal_Bool bInit = InitVCL( xMS );
191
192 if( bInit )
193 {
194 // Application-Main rufen
195 pSVData->maAppData.mbInAppMain = sal_True;
196 pSVData->mpApp->Main();
197 pSVData->maAppData.mbInAppMain = sal_False;
198 }
199
200 if( pSVData->mxDisplayConnection.is() )
201 {
202 pSVData->mxDisplayConnection->terminate();
203 pSVData->mxDisplayConnection.clear();
204 }
205
206 // This is a hack to work around the problem of the asynchronous nature
207 // of bridging accessibility through Java: on shutdown there might still
208 // be some events in the AWT EventQueue, which need the SolarMutex which
209 // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
210 // here ..
211 css::uno::Reference< XComponent > xComponent(pSVData->mxAccessBridge, UNO_QUERY);
212 if( xComponent.is() )
213 {
214 sal_uLong nCount = Application::ReleaseSolarMutex();
215 xComponent->dispose();
216 Application::AcquireSolarMutex(nCount);
217 pSVData->mxAccessBridge.clear();
218 }
219
220 DeInitVCL();
221 #ifdef WNT
222 if( g_acc_manager1 )
223 g_acc_manager1->release();
224 #endif
225 return bInit;
226 }
227
SVMain()228 sal_Bool SVMain()
229 {
230 // #i47888# allow for alternative initialization as required for e.g. MacOSX
231 extern sal_Bool ImplSVMainHook( sal_Bool* );
232
233 sal_Bool bInit;
234 if( ImplSVMainHook( &bInit ) )
235 return bInit;
236 else
237 return ImplSVMain();
238 }
239 // This variable is set, when no Application object is instantiated
240 // before SVInit is called
241 static Application * pOwnSvApp = NULL;
242 // Exception handler. pExceptionHandler != NULL => VCL already inited
243 ImplVCLExceptionHandler * pExceptionHandler = NULL;
244
245 class Application_Impl : public Application
246 {
247 public:
Main()248 void Main(){};
249 };
250
251 class DesktopEnvironmentContext: public cppu::WeakImplHelper1< com::sun::star::uno::XCurrentContext >
252 {
253 public:
DesktopEnvironmentContext(const com::sun::star::uno::Reference<com::sun::star::uno::XCurrentContext> & ctx)254 DesktopEnvironmentContext( const com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > & ctx)
255 : m_xNextContext( ctx ) {}
256
257 // XCurrentContext
258 virtual com::sun::star::uno::Any SAL_CALL getValueByName( const rtl::OUString& Name )
259 throw (com::sun::star::uno::RuntimeException);
260
261 private:
262 com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > m_xNextContext;
263 };
264
getValueByName(const rtl::OUString & Name)265 Any SAL_CALL DesktopEnvironmentContext::getValueByName( const rtl::OUString& Name) throw (RuntimeException)
266 {
267 Any retVal;
268
269 if ( 0 == Name.compareToAscii( "system.desktop-environment" ) )
270 {
271 retVal = makeAny( Application::GetDesktopEnvironment() );
272 }
273 else if( m_xNextContext.is() )
274 {
275 // Call next context in chain if found
276 retVal = m_xNextContext->getValueByName( Name );
277 }
278 return retVal;
279 }
280
InitVCL(const::com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> & rSMgr)281 sal_Bool InitVCL( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & rSMgr )
282 {
283 RTL_LOGFILE_CONTEXT( aLog, "vcl (ss112471) ::InitVCL" );
284
285 if( pExceptionHandler != NULL )
286 return sal_False;
287
288 if( ! ImplGetSVData() )
289 ImplInitSVData();
290
291 if( !ImplGetSVData()->mpApp )
292 {
293 pOwnSvApp = new Application_Impl();
294 }
295 InitSalMain();
296
297 /*AllSettings aAS;
298 Application::SetSettings( aAS );// ???
299 */
300 ImplSVData* pSVData = ImplGetSVData();
301
302 // SV bei den Tools anmelden
303 InitTools();
304
305 DBG_ASSERT( !pSVData->maAppData.mxMSF.is(), "VCL service factory already set" );
306 pSVData->maAppData.mxMSF = rSMgr;
307
308 // Main-Thread-Id merken
309 pSVData->mnMainThreadId = ::vos::OThread::getCurrentIdentifier();
310
311 vos::OStartupInfo aStartInfo;
312 rtl::OUString aExeFileName;
313
314
315 // Sal initialisieren
316 RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ ::CreateSalInstance" );
317 pSVData->mpDefInst = CreateSalInstance();
318 if ( !pSVData->mpDefInst )
319 return sal_False;
320 RTL_LOGFILE_CONTEXT_TRACE( aLog, "} ::CreateSalInstance" );
321
322 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
323 com::sun::star::uno::setCurrentContext(
324 new DesktopEnvironmentContext( com::sun::star::uno::getCurrentContext() ) );
325
326 // Initialize application instance (should be done after initialization of VCL SAL part)
327 if( pSVData->mpApp )
328 // call init to initialize application class
329 // soffice/sfx implementation creates the global service manager
330 pSVData->mpApp->Init();
331
332 // Den AppFileName gleich holen und absolut machen, bevor das
333 // WorkingDirectory sich aendert...
334 aStartInfo.getExecutableFile( aExeFileName );
335
336 // convert path to native file format
337 rtl::OUString aNativeFileName;
338 osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
339 pSVData->maAppData.mpAppFileName = new String( aNativeFileName );
340
341 // Initialize global data
342 pSVData->maGDIData.mpScreenFontList = new ImplDevFontList;
343 pSVData->maGDIData.mpScreenFontCache = new ImplFontCache( sal_False );
344 pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
345
346 // Exception-Handler setzen
347 pExceptionHandler = new ImplVCLExceptionHandler();
348
349 // Debug-Daten initialisieren
350 DBGGUI_INIT();
351
352 return sal_True;
353 }
354
DeInitVCL()355 void DeInitVCL()
356 {
357 ImplSVData* pSVData = ImplGetSVData();
358 pSVData->mbDeInit = sal_True;
359
360 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
361
362 // give ime status a chance to destroy its own windows
363 delete pSVData->mpImeStatus;
364 pSVData->mpImeStatus = NULL;
365
366 #if OSL_DEBUG_LEVEL > 0
367 rtl::OStringBuffer aBuf( 256 );
368 aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
369 long nTopWindowCount = Application::GetTopWindowCount();
370 long nBadTopWindows = nTopWindowCount;
371 for( long i = 0; i < nTopWindowCount; i++ )
372 {
373 Window* pWin = Application::GetTopWindow( i );
374 // default window will be destroyed further down
375 // but may still be useful during deinit up to that point
376 if( pWin == pSVData->mpDefaultWin )
377 nBadTopWindows--;
378 else
379 {
380 aBuf.append( "text = \"" );
381 aBuf.append( rtl::OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
382 aBuf.append( "\" type = \"" );
383 aBuf.append( typeid(*pWin).name() );
384 aBuf.append( "\", ptr = 0x" );
385 aBuf.append( sal_Int64( pWin ), 16 );
386 aBuf.append( "\n" );
387 }
388 }
389 DBG_ASSERT( nBadTopWindows==0, aBuf.getStr() );
390 #endif
391
392 ImplImageTreeSingletonRef()->shutDown();
393
394 delete pExceptionHandler;
395 pExceptionHandler = NULL;
396
397 // Debug Daten zuruecksetzen
398 DBGGUI_DEINIT();
399
400 // free global data
401 delete pSVData->maGDIData.mpGrfConverter;
402
403 if( pSVData->mpSettingsConfigItem )
404 delete pSVData->mpSettingsConfigItem, pSVData->mpSettingsConfigItem = NULL;
405 if( pSVData->maGDIData.mpDefaultFontConfiguration )
406 delete pSVData->maGDIData.mpDefaultFontConfiguration, pSVData->maGDIData.mpDefaultFontConfiguration = NULL;
407 if( pSVData->maGDIData.mpFontSubstConfiguration )
408 delete pSVData->maGDIData.mpFontSubstConfiguration, pSVData->maGDIData.mpFontSubstConfiguration = NULL;
409
410 if ( pSVData->maAppData.mpIdleMgr )
411 delete pSVData->maAppData.mpIdleMgr;
412 Timer::ImplDeInitTimer();
413
414 if ( pSVData->maWinData.mpMsgBoxImgList )
415 {
416 delete pSVData->maWinData.mpMsgBoxImgList;
417 pSVData->maWinData.mpMsgBoxImgList = NULL;
418 }
419 if ( pSVData->maWinData.mpMsgBoxHCImgList )
420 {
421 delete pSVData->maWinData.mpMsgBoxHCImgList;
422 pSVData->maWinData.mpMsgBoxHCImgList = NULL;
423 }
424 if ( pSVData->maCtrlData.mpCheckImgList )
425 {
426 delete pSVData->maCtrlData.mpCheckImgList;
427 pSVData->maCtrlData.mpCheckImgList = NULL;
428 }
429 if ( pSVData->maCtrlData.mpRadioImgList )
430 {
431 delete pSVData->maCtrlData.mpRadioImgList;
432 pSVData->maCtrlData.mpRadioImgList = NULL;
433 }
434 if ( pSVData->maCtrlData.mpPinImgList )
435 {
436 delete pSVData->maCtrlData.mpPinImgList;
437 pSVData->maCtrlData.mpPinImgList = NULL;
438 }
439 if ( pSVData->maCtrlData.mpSplitHPinImgList )
440 {
441 delete pSVData->maCtrlData.mpSplitHPinImgList;
442 pSVData->maCtrlData.mpSplitHPinImgList = NULL;
443 }
444 if ( pSVData->maCtrlData.mpSplitVPinImgList )
445 {
446 delete pSVData->maCtrlData.mpSplitVPinImgList;
447 pSVData->maCtrlData.mpSplitVPinImgList = NULL;
448 }
449 if ( pSVData->maCtrlData.mpSplitHArwImgList )
450 {
451 delete pSVData->maCtrlData.mpSplitHArwImgList;
452 pSVData->maCtrlData.mpSplitHArwImgList = NULL;
453 }
454 if ( pSVData->maCtrlData.mpSplitVArwImgList )
455 {
456 delete pSVData->maCtrlData.mpSplitVArwImgList;
457 pSVData->maCtrlData.mpSplitVArwImgList = NULL;
458 }
459 if ( pSVData->maCtrlData.mpDisclosurePlus )
460 {
461 delete pSVData->maCtrlData.mpDisclosurePlus;
462 pSVData->maCtrlData.mpDisclosurePlus = NULL;
463 }
464 if ( pSVData->maCtrlData.mpDisclosurePlusHC )
465 {
466 delete pSVData->maCtrlData.mpDisclosurePlusHC;
467 pSVData->maCtrlData.mpDisclosurePlusHC = NULL;
468 }
469 if ( pSVData->maCtrlData.mpDisclosureMinus )
470 {
471 delete pSVData->maCtrlData.mpDisclosureMinus;
472 pSVData->maCtrlData.mpDisclosureMinus = NULL;
473 }
474 if ( pSVData->maCtrlData.mpDisclosureMinusHC )
475 {
476 delete pSVData->maCtrlData.mpDisclosureMinusHC;
477 pSVData->maCtrlData.mpDisclosureMinusHC = NULL;
478 }
479 if ( pSVData->mpDefaultWin )
480 {
481 delete pSVData->mpDefaultWin;
482 pSVData->mpDefaultWin = NULL;
483 }
484
485 // #114285# Moved here from ImplDeInitSVData...
486 if ( pSVData->mpUnoWrapper )
487 {
488 pSVData->mpUnoWrapper->Destroy();
489 pSVData->mpUnoWrapper = NULL;
490 }
491
492 pSVData->maAppData.mxMSF.clear();
493
494 if( pSVData->mpApp )
495 // call deinit to deinitialize application class
496 // soffice/sfx implementation disposes the global service manager
497 // Warning: After this call you can't call uno services
498 pSVData->mpApp->DeInit();
499
500 if ( pSVData->maAppData.mpSettings )
501 {
502 if ( pSVData->maAppData.mpCfgListener )
503 {
504 pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
505 delete pSVData->maAppData.mpCfgListener;
506 }
507
508 delete pSVData->maAppData.mpSettings;
509 pSVData->maAppData.mpSettings = NULL;
510 }
511 if ( pSVData->maAppData.mpAccelMgr )
512 {
513 delete pSVData->maAppData.mpAccelMgr;
514 pSVData->maAppData.mpAccelMgr = NULL;
515 }
516 if ( pSVData->maAppData.mpUniqueIdCont )
517 {
518 delete pSVData->maAppData.mpUniqueIdCont;
519 pSVData->maAppData.mpUniqueIdCont = NULL;
520 }
521 if ( pSVData->maAppData.mpAppFileName )
522 {
523 delete pSVData->maAppData.mpAppFileName;
524 pSVData->maAppData.mpAppFileName = NULL;
525 }
526 if ( pSVData->maAppData.mpAppName )
527 {
528 delete pSVData->maAppData.mpAppName;
529 pSVData->maAppData.mpAppName = NULL;
530 }
531 if ( pSVData->maAppData.mpDisplayName )
532 {
533 delete pSVData->maAppData.mpDisplayName;
534 pSVData->maAppData.mpDisplayName = NULL;
535 }
536 if ( pSVData->maAppData.mpEventListeners )
537 {
538 delete pSVData->maAppData.mpEventListeners;
539 pSVData->maAppData.mpEventListeners = NULL;
540 }
541 if ( pSVData->maAppData.mpKeyListeners )
542 {
543 delete pSVData->maAppData.mpKeyListeners;
544 pSVData->maAppData.mpKeyListeners = NULL;
545 }
546
547 if ( pSVData->maAppData.mpFirstHotKey )
548 ImplFreeHotKeyData();
549 if ( pSVData->maAppData.mpFirstEventHook )
550 ImplFreeEventHookData();
551
552 ImplDeletePrnQueueList();
553 delete pSVData->maGDIData.mpScreenFontList;
554 pSVData->maGDIData.mpScreenFontList = NULL;
555 delete pSVData->maGDIData.mpScreenFontCache;
556 pSVData->maGDIData.mpScreenFontCache = NULL;
557 ImplFreeOutDevFontData();
558
559 if ( pSVData->mpResMgr )
560 {
561 delete pSVData->mpResMgr;
562 pSVData->mpResMgr = NULL;
563 }
564
565 ResMgr::DestroyAllResMgr();
566
567 // destroy all Sal interfaces before destorying the instance
568 // and thereby unloading the plugin
569 delete pSVData->mpSalSystem;
570 pSVData->mpSalSystem = NULL;
571 delete pSVData->mpSalTimer;
572 pSVData->mpSalTimer = NULL;
573
574 // Sal deinitialisieren
575 DestroySalInstance( pSVData->mpDefInst );
576
577 DeInitTools();
578
579 DeInitSalMain();
580
581 if( pOwnSvApp )
582 {
583 delete pOwnSvApp;
584 pOwnSvApp = NULL;
585 }
586 }
587
588 // only one call is allowed
589 struct WorkerThreadData
590 {
591 oslWorkerFunction pWorker;
592 void * pThreadData;
WorkerThreadDataWorkerThreadData593 WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
594 : pWorker( pWorker_ )
595 , pThreadData( pThreadData_ )
596 {
597 }
598 };
599
600 #ifdef WNT
601 static HANDLE hThreadID = 0;
_threadmain(void * pArgs)602 static unsigned __stdcall _threadmain( void *pArgs )
603 {
604 OleInitialize( NULL );
605 ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
606 delete (WorkerThreadData*)pArgs;
607 OleUninitialize();
608 hThreadID = 0;
609 return 0;
610 }
611 #else
612 static oslThread hThreadID = 0;
613 extern "C"
614 {
MainWorkerFunction(void * pArgs)615 static void SAL_CALL MainWorkerFunction( void* pArgs )
616 {
617 ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
618 delete (WorkerThreadData*)pArgs;
619 hThreadID = 0;
620 }
621 } // extern "C"
622 #endif
623
CreateMainLoopThread(oslWorkerFunction pWorker,void * pThreadData)624 void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
625 {
626 #ifdef WNT
627 // sal thread alway call CoInitializeEx, so a sysdepen implementation is necessary
628
629 unsigned uThreadID;
630 hThreadID = (HANDLE)_beginthreadex(
631 NULL, // no security handle
632 0, // stacksize 0 means default
633 _threadmain, // thread worker function
634 new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
635 0, // 0 means: create immediatly otherwise use CREATE_SUSPENDED
636 &uThreadID ); // thread id to fill
637 #else
638 hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
639 #endif
640 }
641
JoinMainLoopThread()642 void JoinMainLoopThread()
643 {
644 if( hThreadID )
645 {
646 #ifdef WNT
647 WaitForSingleObject(hThreadID, INFINITE);
648 #else
649 osl_joinWithThread(hThreadID);
650 osl_destroyThread( hThreadID );
651 #endif
652 }
653 }
654