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
260 private:
261 com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > m_xNextContext;
262 };
263
getValueByName(const rtl::OUString & Name)264 Any SAL_CALL DesktopEnvironmentContext::getValueByName( const rtl::OUString& Name)
265 {
266 Any retVal;
267
268 if ( 0 == Name.compareToAscii( "system.desktop-environment" ) )
269 {
270 retVal = makeAny( Application::GetDesktopEnvironment() );
271 }
272 else if( m_xNextContext.is() )
273 {
274 // Call next context in chain if found
275 retVal = m_xNextContext->getValueByName( Name );
276 }
277 return retVal;
278 }
279
InitVCL(const::com::sun::star::uno::Reference<::com::sun::star::lang::XMultiServiceFactory> & rSMgr)280 sal_Bool InitVCL( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > & rSMgr )
281 {
282 RTL_LOGFILE_CONTEXT( aLog, "vcl (ss112471) ::InitVCL" );
283
284 if( pExceptionHandler != NULL )
285 return sal_False;
286
287 if( ! ImplGetSVData() )
288 ImplInitSVData();
289
290 if( !ImplGetSVData()->mpApp )
291 {
292 pOwnSvApp = new Application_Impl();
293 }
294 InitSalMain();
295
296 /*AllSettings aAS;
297 Application::SetSettings( aAS );// ???
298 */
299 ImplSVData* pSVData = ImplGetSVData();
300
301 // SV bei den Tools anmelden
302 InitTools();
303
304 DBG_ASSERT( !pSVData->maAppData.mxMSF.is(), "VCL service factory already set" );
305 pSVData->maAppData.mxMSF = rSMgr;
306
307 // Main-Thread-Id merken
308 pSVData->mnMainThreadId = ::vos::OThread::getCurrentIdentifier();
309
310 vos::OStartupInfo aStartInfo;
311 rtl::OUString aExeFileName;
312
313
314 // Sal initialisieren
315 RTL_LOGFILE_CONTEXT_TRACE( aLog, "{ ::CreateSalInstance" );
316 pSVData->mpDefInst = CreateSalInstance();
317 if ( !pSVData->mpDefInst )
318 return sal_False;
319 RTL_LOGFILE_CONTEXT_TRACE( aLog, "} ::CreateSalInstance" );
320
321 // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
322 com::sun::star::uno::setCurrentContext(
323 new DesktopEnvironmentContext( com::sun::star::uno::getCurrentContext() ) );
324
325 // Initialize application instance (should be done after initialization of VCL SAL part)
326 if( pSVData->mpApp )
327 // call init to initialize application class
328 // soffice/sfx implementation creates the global service manager
329 pSVData->mpApp->Init();
330
331 // Den AppFileName gleich holen und absolut machen, bevor das
332 // WorkingDirectory sich aendert...
333 aStartInfo.getExecutableFile( aExeFileName );
334
335 // convert path to native file format
336 rtl::OUString aNativeFileName;
337 osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
338 pSVData->maAppData.mpAppFileName = new String( aNativeFileName );
339
340 // Initialize global data
341 pSVData->maGDIData.mpScreenFontList = new ImplDevFontList;
342 pSVData->maGDIData.mpScreenFontCache = new ImplFontCache( sal_False );
343 pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
344
345 // Exception-Handler setzen
346 pExceptionHandler = new ImplVCLExceptionHandler();
347
348 // Debug-Daten initialisieren
349 DBGGUI_INIT();
350
351 return sal_True;
352 }
353
DeInitVCL()354 void DeInitVCL()
355 {
356 ImplSVData* pSVData = ImplGetSVData();
357 pSVData->mbDeInit = sal_True;
358
359 vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
360
361 // give ime status a chance to destroy its own windows
362 delete pSVData->mpImeStatus;
363 pSVData->mpImeStatus = NULL;
364
365 #if OSL_DEBUG_LEVEL > 0
366 rtl::OStringBuffer aBuf( 256 );
367 aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
368 long nTopWindowCount = Application::GetTopWindowCount();
369 long nBadTopWindows = nTopWindowCount;
370 for( long i = 0; i < nTopWindowCount; i++ )
371 {
372 Window* pWin = Application::GetTopWindow( i );
373 // default window will be destroyed further down
374 // but may still be useful during deinit up to that point
375 if( pWin == pSVData->mpDefaultWin )
376 nBadTopWindows--;
377 else
378 {
379 aBuf.append( "text = \"" );
380 aBuf.append( rtl::OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
381 aBuf.append( "\" type = \"" );
382 aBuf.append( typeid(*pWin).name() );
383 aBuf.append( "\", ptr = 0x" );
384 aBuf.append( sal_Int64( pWin ), 16 );
385 aBuf.append( "\n" );
386 }
387 }
388 DBG_ASSERT( nBadTopWindows==0, aBuf.getStr() );
389 #endif
390
391 ImplImageTreeSingletonRef()->shutDown();
392
393 delete pExceptionHandler;
394 pExceptionHandler = NULL;
395
396 // Debug Daten zuruecksetzen
397 DBGGUI_DEINIT();
398
399 // free global data
400 delete pSVData->maGDIData.mpGrfConverter;
401
402 if( pSVData->mpSettingsConfigItem )
403 delete pSVData->mpSettingsConfigItem, pSVData->mpSettingsConfigItem = NULL;
404 if( pSVData->maGDIData.mpDefaultFontConfiguration )
405 delete pSVData->maGDIData.mpDefaultFontConfiguration, pSVData->maGDIData.mpDefaultFontConfiguration = NULL;
406 if( pSVData->maGDIData.mpFontSubstConfiguration )
407 delete pSVData->maGDIData.mpFontSubstConfiguration, pSVData->maGDIData.mpFontSubstConfiguration = NULL;
408
409 if ( pSVData->maAppData.mpIdleMgr )
410 delete pSVData->maAppData.mpIdleMgr;
411 Timer::ImplDeInitTimer();
412
413 if ( pSVData->maWinData.mpMsgBoxImgList )
414 {
415 delete pSVData->maWinData.mpMsgBoxImgList;
416 pSVData->maWinData.mpMsgBoxImgList = NULL;
417 }
418 if ( pSVData->maWinData.mpMsgBoxHCImgList )
419 {
420 delete pSVData->maWinData.mpMsgBoxHCImgList;
421 pSVData->maWinData.mpMsgBoxHCImgList = NULL;
422 }
423 if ( pSVData->maCtrlData.mpCheckImgList )
424 {
425 delete pSVData->maCtrlData.mpCheckImgList;
426 pSVData->maCtrlData.mpCheckImgList = NULL;
427 }
428 if ( pSVData->maCtrlData.mpRadioImgList )
429 {
430 delete pSVData->maCtrlData.mpRadioImgList;
431 pSVData->maCtrlData.mpRadioImgList = NULL;
432 }
433 if ( pSVData->maCtrlData.mpPinImgList )
434 {
435 delete pSVData->maCtrlData.mpPinImgList;
436 pSVData->maCtrlData.mpPinImgList = NULL;
437 }
438 if ( pSVData->maCtrlData.mpSplitHPinImgList )
439 {
440 delete pSVData->maCtrlData.mpSplitHPinImgList;
441 pSVData->maCtrlData.mpSplitHPinImgList = NULL;
442 }
443 if ( pSVData->maCtrlData.mpSplitVPinImgList )
444 {
445 delete pSVData->maCtrlData.mpSplitVPinImgList;
446 pSVData->maCtrlData.mpSplitVPinImgList = NULL;
447 }
448 if ( pSVData->maCtrlData.mpSplitHArwImgList )
449 {
450 delete pSVData->maCtrlData.mpSplitHArwImgList;
451 pSVData->maCtrlData.mpSplitHArwImgList = NULL;
452 }
453 if ( pSVData->maCtrlData.mpSplitVArwImgList )
454 {
455 delete pSVData->maCtrlData.mpSplitVArwImgList;
456 pSVData->maCtrlData.mpSplitVArwImgList = NULL;
457 }
458 if ( pSVData->maCtrlData.mpDisclosurePlus )
459 {
460 delete pSVData->maCtrlData.mpDisclosurePlus;
461 pSVData->maCtrlData.mpDisclosurePlus = NULL;
462 }
463 if ( pSVData->maCtrlData.mpDisclosurePlusHC )
464 {
465 delete pSVData->maCtrlData.mpDisclosurePlusHC;
466 pSVData->maCtrlData.mpDisclosurePlusHC = NULL;
467 }
468 if ( pSVData->maCtrlData.mpDisclosureMinus )
469 {
470 delete pSVData->maCtrlData.mpDisclosureMinus;
471 pSVData->maCtrlData.mpDisclosureMinus = NULL;
472 }
473 if ( pSVData->maCtrlData.mpDisclosureMinusHC )
474 {
475 delete pSVData->maCtrlData.mpDisclosureMinusHC;
476 pSVData->maCtrlData.mpDisclosureMinusHC = NULL;
477 }
478 if ( pSVData->mpDefaultWin )
479 {
480 delete pSVData->mpDefaultWin;
481 pSVData->mpDefaultWin = NULL;
482 }
483
484 // #114285# Moved here from ImplDeInitSVData...
485 if ( pSVData->mpUnoWrapper )
486 {
487 pSVData->mpUnoWrapper->Destroy();
488 pSVData->mpUnoWrapper = NULL;
489 }
490
491 pSVData->maAppData.mxMSF.clear();
492
493 if( pSVData->mpApp )
494 // call deinit to deinitialize application class
495 // soffice/sfx implementation disposes the global service manager
496 // Warning: After this call you can't call uno services
497 pSVData->mpApp->DeInit();
498
499 if ( pSVData->maAppData.mpSettings )
500 {
501 if ( pSVData->maAppData.mpCfgListener )
502 {
503 pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
504 delete pSVData->maAppData.mpCfgListener;
505 }
506
507 delete pSVData->maAppData.mpSettings;
508 pSVData->maAppData.mpSettings = NULL;
509 }
510 if ( pSVData->maAppData.mpAccelMgr )
511 {
512 delete pSVData->maAppData.mpAccelMgr;
513 pSVData->maAppData.mpAccelMgr = NULL;
514 }
515 if ( pSVData->maAppData.mpUniqueIdCont )
516 {
517 delete pSVData->maAppData.mpUniqueIdCont;
518 pSVData->maAppData.mpUniqueIdCont = NULL;
519 }
520 if ( pSVData->maAppData.mpAppFileName )
521 {
522 delete pSVData->maAppData.mpAppFileName;
523 pSVData->maAppData.mpAppFileName = NULL;
524 }
525 if ( pSVData->maAppData.mpAppName )
526 {
527 delete pSVData->maAppData.mpAppName;
528 pSVData->maAppData.mpAppName = NULL;
529 }
530 if ( pSVData->maAppData.mpDisplayName )
531 {
532 delete pSVData->maAppData.mpDisplayName;
533 pSVData->maAppData.mpDisplayName = NULL;
534 }
535 if ( pSVData->maAppData.mpEventListeners )
536 {
537 delete pSVData->maAppData.mpEventListeners;
538 pSVData->maAppData.mpEventListeners = NULL;
539 }
540 if ( pSVData->maAppData.mpKeyListeners )
541 {
542 delete pSVData->maAppData.mpKeyListeners;
543 pSVData->maAppData.mpKeyListeners = NULL;
544 }
545
546 if ( pSVData->maAppData.mpFirstHotKey )
547 ImplFreeHotKeyData();
548 if ( pSVData->maAppData.mpFirstEventHook )
549 ImplFreeEventHookData();
550
551 ImplDeletePrnQueueList();
552 delete pSVData->maGDIData.mpScreenFontList;
553 pSVData->maGDIData.mpScreenFontList = NULL;
554 delete pSVData->maGDIData.mpScreenFontCache;
555 pSVData->maGDIData.mpScreenFontCache = NULL;
556 ImplFreeOutDevFontData();
557
558 if ( pSVData->mpResMgr )
559 {
560 delete pSVData->mpResMgr;
561 pSVData->mpResMgr = NULL;
562 }
563
564 ResMgr::DestroyAllResMgr();
565
566 // destroy all Sal interfaces before destorying the instance
567 // and thereby unloading the plugin
568 delete pSVData->mpSalSystem;
569 pSVData->mpSalSystem = NULL;
570 delete pSVData->mpSalTimer;
571 pSVData->mpSalTimer = NULL;
572
573 // Sal deinitialisieren
574 DestroySalInstance( pSVData->mpDefInst );
575
576 DeInitTools();
577
578 DeInitSalMain();
579
580 if( pOwnSvApp )
581 {
582 delete pOwnSvApp;
583 pOwnSvApp = NULL;
584 }
585 }
586
587 // only one call is allowed
588 struct WorkerThreadData
589 {
590 oslWorkerFunction pWorker;
591 void * pThreadData;
WorkerThreadDataWorkerThreadData592 WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
593 : pWorker( pWorker_ )
594 , pThreadData( pThreadData_ )
595 {
596 }
597 };
598
599 #ifdef WNT
600 static HANDLE hThreadID = 0;
_threadmain(void * pArgs)601 static unsigned __stdcall _threadmain( void *pArgs )
602 {
603 OleInitialize( NULL );
604 ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
605 delete (WorkerThreadData*)pArgs;
606 OleUninitialize();
607 hThreadID = 0;
608 return 0;
609 }
610 #else
611 static oslThread hThreadID = 0;
612 extern "C"
613 {
MainWorkerFunction(void * pArgs)614 static void SAL_CALL MainWorkerFunction( void* pArgs )
615 {
616 ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
617 delete (WorkerThreadData*)pArgs;
618 hThreadID = 0;
619 }
620 } // extern "C"
621 #endif
622
CreateMainLoopThread(oslWorkerFunction pWorker,void * pThreadData)623 void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
624 {
625 #ifdef WNT
626 // sal thread alway call CoInitializeEx, so a sysdepen implementation is necessary
627
628 unsigned uThreadID;
629 hThreadID = (HANDLE)_beginthreadex(
630 NULL, // no security handle
631 0, // stacksize 0 means default
632 _threadmain, // thread worker function
633 new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
634 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
635 &uThreadID ); // thread id to fill
636 #else
637 hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
638 #endif
639 }
640
JoinMainLoopThread()641 void JoinMainLoopThread()
642 {
643 if( hThreadID )
644 {
645 #ifdef WNT
646 WaitForSingleObject(hThreadID, INFINITE);
647 #else
648 osl_joinWithThread(hThreadID);
649 osl_destroyThread( hThreadID );
650 #endif
651 }
652 }
653