Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <sal/config.h>
21 :
22 : #include <cassert>
23 :
24 : #include <osl/file.hxx>
25 : #include <osl/signal.h>
26 :
27 : #include "tools/debug.hxx"
28 : #include "tools/resmgr.hxx"
29 :
30 : #include "comphelper/processfactory.hxx"
31 :
32 : #include "unotools/syslocaleoptions.hxx"
33 : #include "vcl/svapp.hxx"
34 : #include "vcl/wrkwin.hxx"
35 : #include "vcl/cvtgrf.hxx"
36 : #include "vcl/scheduler.hxx"
37 : #include "vcl/image.hxx"
38 : #include "vcl/settings.hxx"
39 : #include "vcl/unowrap.hxx"
40 : #include "vcl/configsettings.hxx"
41 : #include "vcl/lazydelete.hxx"
42 : #include "vcl/embeddedfontshelper.hxx"
43 : #include "vcl/debugevent.hxx"
44 :
45 : #ifdef WNT
46 : #include <svsys.h>
47 : #include <process.h>
48 : #include <ole2.h>
49 : #endif
50 :
51 : #ifdef ANDROID
52 : #include <cppuhelper/bootstrap.hxx>
53 : #include <jni.h>
54 : #endif
55 :
56 : #include "salinst.hxx"
57 : #include "salwtype.hxx"
58 : #include "svdata.hxx"
59 : #include "vcl/svmain.hxx"
60 : #include "dbggui.hxx"
61 : #include "accmgr.hxx"
62 : #include "idlemgr.hxx"
63 : #include "outdev.h"
64 : #include "outfont.hxx"
65 : #include "PhysicalFontCollection.hxx"
66 : #include "print.h"
67 : #include "salgdi.hxx"
68 : #include "salsys.hxx"
69 : #include "saltimer.hxx"
70 : #include "salimestatus.hxx"
71 : #include "impimagetree.hxx"
72 : #include "xconnection.hxx"
73 :
74 : #include "vcl/opengl/OpenGLContext.hxx"
75 :
76 : #include "osl/process.h"
77 : #include "com/sun/star/lang/XMultiServiceFactory.hpp"
78 : #include "com/sun/star/lang/XComponent.hpp"
79 : #include "com/sun/star/frame/Desktop.hpp"
80 :
81 : #include "cppuhelper/implbase1.hxx"
82 : #include "uno/current_context.hxx"
83 :
84 : #if OSL_DEBUG_LEVEL > 0
85 : #include <typeinfo>
86 : #include "rtl/strbuf.hxx"
87 : #endif
88 :
89 : using namespace ::com::sun::star;
90 :
91 0 : oslSignalAction SAL_CALL VCLExceptionSignal_impl( void* /*pData*/, oslSignalInfo* pInfo)
92 : {
93 : static bool bIn = false;
94 :
95 : // if we crash again, bail out immediately
96 0 : if ( !bIn )
97 : {
98 0 : sal_uInt16 nVCLException = 0;
99 :
100 : // UAE
101 0 : if ( (pInfo->Signal == osl_Signal_AccessViolation) ||
102 0 : (pInfo->Signal == osl_Signal_IntegerDivideByZero) ||
103 0 : (pInfo->Signal == osl_Signal_FloatDivideByZero) ||
104 0 : (pInfo->Signal == osl_Signal_DebugBreak) )
105 0 : nVCLException = EXC_SYSTEM;
106 :
107 : // RC
108 0 : if ((pInfo->Signal == osl_Signal_User) &&
109 0 : (pInfo->UserSignal == OSL_SIGNAL_USER_RESOURCEFAILURE) )
110 0 : nVCLException = EXC_RSCNOTLOADED;
111 :
112 : // DISPLAY-Unix
113 0 : if ((pInfo->Signal == osl_Signal_User) &&
114 0 : (pInfo->UserSignal == OSL_SIGNAL_USER_X11SUBSYSTEMERROR) )
115 0 : nVCLException = EXC_DISPLAY;
116 :
117 : // Remote-Client
118 0 : if ((pInfo->Signal == osl_Signal_User) &&
119 0 : (pInfo->UserSignal == OSL_SIGNAL_USER_RVPCONNECTIONERROR) )
120 0 : nVCLException = EXC_REMOTE;
121 :
122 0 : if ( nVCLException )
123 : {
124 0 : bIn = true;
125 :
126 0 : SolarMutexGuard aLock;
127 :
128 : // do not stop timer because otherwise the UAE-Box will not be painted as well
129 0 : ImplSVData* pSVData = ImplGetSVData();
130 0 : if ( pSVData->mpApp )
131 : {
132 0 : SystemWindowFlags nOldMode = Application::GetSystemWindowMode();
133 0 : Application::SetSystemWindowMode( nOldMode & ~SystemWindowFlags::NOAUTOMODE );
134 0 : pSVData->mpApp->Exception( nVCLException );
135 0 : Application::SetSystemWindowMode( nOldMode );
136 : }
137 0 : bIn = false;
138 :
139 0 : return osl_Signal_ActCallNextHdl;
140 : }
141 : }
142 :
143 0 : return osl_Signal_ActCallNextHdl;
144 :
145 : }
146 :
147 127 : int ImplSVMain()
148 : {
149 : // The 'real' SVMain()
150 127 : ImplSVData* pSVData = ImplGetSVData();
151 :
152 : DBG_ASSERT( pSVData->mpApp, "no instance of class Application" );
153 :
154 127 : int nReturn = EXIT_FAILURE;
155 :
156 127 : bool bInit = InitVCL();
157 :
158 127 : if( bInit )
159 : {
160 : // call application main
161 127 : pSVData->maAppData.mbInAppMain = true;
162 127 : nReturn = pSVData->mpApp->Main();
163 127 : pSVData->maAppData.mbInAppMain = false;
164 : }
165 :
166 127 : if( pSVData->mxDisplayConnection.is() )
167 : {
168 44 : pSVData->mxDisplayConnection->terminate();
169 44 : pSVData->mxDisplayConnection.clear();
170 : }
171 :
172 : // This is a hack to work around the problem of the asynchronous nature
173 : // of bridging accessibility through Java: on shutdown there might still
174 : // be some events in the AWT EventQueue, which need the SolarMutex which
175 : // - on the other hand - is destroyed in DeInitVCL(). So empty the queue
176 : // here ..
177 127 : if( pSVData->mxAccessBridge.is() )
178 : {
179 : {
180 0 : SolarMutexReleaser aReleaser;
181 0 : pSVData->mxAccessBridge->dispose();
182 : }
183 0 : pSVData->mxAccessBridge.clear();
184 : }
185 :
186 127 : DeInitVCL();
187 127 : return nReturn;
188 : }
189 :
190 127 : int SVMain()
191 : {
192 : int nRet;
193 127 : if( !Application::IsConsoleOnly() && ImplSVMainHook( &nRet ) )
194 0 : return nRet;
195 : else
196 127 : return ImplSVMain();
197 : }
198 :
199 : // This variable is set when no Application object has been instantiated
200 : // before InitVCL is called
201 : static Application * pOwnSvApp = NULL;
202 :
203 : // Exception handler. pExceptionHandler != NULL => VCL already inited
204 : static oslSignalHandler pExceptionHandler = NULL;
205 :
206 2 : class DesktopEnvironmentContext: public cppu::WeakImplHelper1< com::sun::star::uno::XCurrentContext >
207 : {
208 : public:
209 245 : explicit DesktopEnvironmentContext( const com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > & ctx)
210 245 : : m_xNextContext( ctx ) {}
211 :
212 : // XCurrentContext
213 : virtual com::sun::star::uno::Any SAL_CALL getValueByName( const OUString& Name )
214 : throw (com::sun::star::uno::RuntimeException, std::exception) SAL_OVERRIDE;
215 :
216 : private:
217 : com::sun::star::uno::Reference< com::sun::star::uno::XCurrentContext > m_xNextContext;
218 : };
219 :
220 133 : uno::Any SAL_CALL DesktopEnvironmentContext::getValueByName( const OUString& Name) throw (uno::RuntimeException, std::exception)
221 : {
222 133 : uno::Any retVal;
223 :
224 133 : if ( Name == "system.desktop-environment" )
225 : {
226 133 : retVal = uno::makeAny( Application::GetDesktopEnvironment() );
227 : }
228 0 : else if( m_xNextContext.is() )
229 : {
230 : // Call next context in chain if found
231 0 : retVal = m_xNextContext->getValueByName( Name );
232 : }
233 133 : return retVal;
234 : }
235 :
236 413 : bool InitVCL()
237 : {
238 413 : if( pExceptionHandler != NULL )
239 168 : return false;
240 :
241 245 : EmbeddedFontsHelper::clearTemporaryFontFiles();
242 :
243 245 : if( !ImplGetSVData()->mpApp )
244 : {
245 118 : pOwnSvApp = new Application();
246 : }
247 245 : InitSalMain();
248 :
249 245 : ImplSVData* pSVData = ImplGetSVData();
250 :
251 : // remember Main-Thread-Id
252 245 : pSVData->mnMainThreadId = ::osl::Thread::getCurrentIdentifier();
253 :
254 : // Initialize Sal
255 245 : pSVData->mpDefInst = CreateSalInstance();
256 245 : if ( !pSVData->mpDefInst )
257 0 : return false;
258 :
259 : // Desktop Environment context (to be able to get value of "system.desktop-environment" as soon as possible)
260 : com::sun::star::uno::setCurrentContext(
261 245 : new DesktopEnvironmentContext( com::sun::star::uno::getCurrentContext() ) );
262 :
263 : // Initialize application instance (should be done after initialization of VCL SAL part)
264 245 : if( pSVData->mpApp )
265 : // call init to initialize application class
266 : // soffice/sfx implementation creates the global service manager
267 245 : pSVData->mpApp->Init();
268 :
269 245 : pSVData->mpDefInst->AfterAppInit();
270 :
271 : // Fetch AppFileName and make it absolute before the workdir changes...
272 245 : OUString aExeFileName;
273 245 : osl_getExecutableFile( &aExeFileName.pData );
274 :
275 : // convert path to native file format
276 490 : OUString aNativeFileName;
277 245 : osl::FileBase::getSystemPathFromFileURL( aExeFileName, aNativeFileName );
278 245 : pSVData->maAppData.mpAppFileName = new OUString( aNativeFileName );
279 :
280 : // Initialize global data
281 245 : pSVData->maGDIData.mpScreenFontList = new PhysicalFontCollection;
282 245 : pSVData->maGDIData.mpScreenFontCache = new ImplFontCache;
283 245 : pSVData->maGDIData.mpGrfConverter = new GraphicConverter;
284 :
285 : // Set exception handler
286 245 : pExceptionHandler = osl_addSignalHandler(VCLExceptionSignal_impl, NULL);
287 :
288 : DBGGUI_INIT_SOLARMUTEXCHECK();
289 :
290 : #if OSL_DEBUG_LEVEL > 0
291 : DebugEventInjector::getCreate();
292 : #endif
293 :
294 490 : return true;
295 : }
296 :
297 : namespace
298 : {
299 :
300 : /** Serves for destroying the VCL UNO wrapper as late as possible. This avoids
301 : crash at exit in some special cases when a11y is enabled (e.g., when
302 : a bundled extension is registered/deregistered during startup, forcing exit
303 : while the app is still in splash screen.)
304 : */
305 351 : class VCLUnoWrapperDeleter : public cppu::WeakImplHelper1<com::sun::star::lang::XEventListener>
306 : {
307 : virtual void SAL_CALL disposing(lang::EventObject const& rSource) throw(uno::RuntimeException, std::exception) SAL_OVERRIDE;
308 : };
309 :
310 : void
311 117 : VCLUnoWrapperDeleter::disposing(lang::EventObject const& /* rSource */)
312 : throw(uno::RuntimeException, std::exception)
313 : {
314 117 : ImplSVData* const pSVData = ImplGetSVData();
315 117 : if (pSVData && pSVData->mpUnoWrapper)
316 : {
317 117 : pSVData->mpUnoWrapper->Destroy();
318 117 : pSVData->mpUnoWrapper = NULL;
319 : }
320 117 : }
321 :
322 : }
323 :
324 242 : void DeInitVCL()
325 : {
326 242 : ImplSVData* pSVData = ImplGetSVData();
327 242 : pSVData->mbDeInit = true;
328 :
329 242 : vcl::DeleteOnDeinitBase::ImplDeleteOnDeInit();
330 :
331 : // give ime status a chance to destroy its own windows
332 242 : delete pSVData->mpImeStatus;
333 242 : pSVData->mpImeStatus = NULL;
334 :
335 : #if OSL_DEBUG_LEVEL > 0
336 : OStringBuffer aBuf( 256 );
337 : aBuf.append( "DeInitVCL: some top Windows are still alive\n" );
338 : long nTopWindowCount = Application::GetTopWindowCount();
339 : long nBadTopWindows = nTopWindowCount;
340 : for( long i = 0; i < nTopWindowCount; i++ )
341 : {
342 : vcl::Window* pWin = Application::GetTopWindow( i );
343 : // default window will be destroyed further down
344 : // but may still be useful during deinit up to that point
345 : if( pWin == pSVData->mpDefaultWin )
346 : nBadTopWindows--;
347 : else
348 : {
349 : aBuf.append( "text = \"" );
350 : aBuf.append( OUStringToOString( pWin->GetText(), osl_getThreadTextEncoding() ) );
351 : aBuf.append( "\" type = \"" );
352 : aBuf.append( typeid(*pWin).name() );
353 : aBuf.append( "\", ptr = 0x" );
354 : aBuf.append( sal_Int64( pWin ), 16 );
355 : aBuf.append( "\n" );
356 : }
357 : }
358 : DBG_ASSERT( nBadTopWindows==0, aBuf.getStr() );
359 : #endif
360 :
361 242 : ImplImageTreeSingletonRef()->shutDown();
362 :
363 242 : osl_removeSignalHandler( pExceptionHandler);
364 242 : pExceptionHandler = NULL;
365 :
366 : // free global data
367 242 : delete pSVData->maGDIData.mpGrfConverter;
368 :
369 242 : if( pSVData->mpSettingsConfigItem )
370 178 : delete pSVData->mpSettingsConfigItem, pSVData->mpSettingsConfigItem = NULL;
371 :
372 242 : if ( pSVData->maAppData.mpIdleMgr )
373 89 : delete pSVData->maAppData.mpIdleMgr;
374 242 : Scheduler::ImplDeInitScheduler();
375 :
376 242 : if ( pSVData->maWinData.mpMsgBoxImgList )
377 : {
378 0 : delete pSVData->maWinData.mpMsgBoxImgList;
379 0 : pSVData->maWinData.mpMsgBoxImgList = NULL;
380 : }
381 242 : if ( pSVData->maCtrlData.mpCheckImgList )
382 : {
383 19 : delete pSVData->maCtrlData.mpCheckImgList;
384 19 : pSVData->maCtrlData.mpCheckImgList = NULL;
385 : }
386 242 : if ( pSVData->maCtrlData.mpRadioImgList )
387 : {
388 4 : delete pSVData->maCtrlData.mpRadioImgList;
389 4 : pSVData->maCtrlData.mpRadioImgList = NULL;
390 : }
391 242 : if ( pSVData->maCtrlData.mpPinImgList )
392 : {
393 0 : delete pSVData->maCtrlData.mpPinImgList;
394 0 : pSVData->maCtrlData.mpPinImgList = NULL;
395 : }
396 242 : if ( pSVData->maCtrlData.mpSplitHPinImgList )
397 : {
398 0 : delete pSVData->maCtrlData.mpSplitHPinImgList;
399 0 : pSVData->maCtrlData.mpSplitHPinImgList = NULL;
400 : }
401 242 : if ( pSVData->maCtrlData.mpSplitVPinImgList )
402 : {
403 0 : delete pSVData->maCtrlData.mpSplitVPinImgList;
404 0 : pSVData->maCtrlData.mpSplitVPinImgList = NULL;
405 : }
406 242 : if ( pSVData->maCtrlData.mpSplitHArwImgList )
407 : {
408 0 : delete pSVData->maCtrlData.mpSplitHArwImgList;
409 0 : pSVData->maCtrlData.mpSplitHArwImgList = NULL;
410 : }
411 242 : if ( pSVData->maCtrlData.mpSplitVArwImgList )
412 : {
413 0 : delete pSVData->maCtrlData.mpSplitVArwImgList;
414 0 : pSVData->maCtrlData.mpSplitVArwImgList = NULL;
415 : }
416 242 : if ( pSVData->maCtrlData.mpDisclosurePlus )
417 : {
418 0 : delete pSVData->maCtrlData.mpDisclosurePlus;
419 0 : pSVData->maCtrlData.mpDisclosurePlus = NULL;
420 : }
421 242 : if ( pSVData->maCtrlData.mpDisclosureMinus )
422 : {
423 0 : delete pSVData->maCtrlData.mpDisclosureMinus;
424 0 : pSVData->maCtrlData.mpDisclosureMinus = NULL;
425 : }
426 242 : pSVData->mpDefaultWin.disposeAndClear();
427 :
428 : DBGGUI_DEINIT_SOLARMUTEXCHECK();
429 :
430 242 : if ( pSVData->mpUnoWrapper )
431 : {
432 : try
433 : {
434 : uno::Reference<frame::XDesktop2> const xDesktop = frame::Desktop::create(
435 121 : comphelper::getProcessComponentContext() );
436 117 : xDesktop->addEventListener(new VCLUnoWrapperDeleter());
437 : }
438 2 : catch (uno::Exception const&)
439 : {
440 : // ignore
441 : }
442 : }
443 :
444 242 : if( pSVData->mpApp || pSVData->maDeInitHook.IsSet() )
445 : {
446 242 : SolarMutexReleaser aReleaser;
447 : // call deinit to deinitialize application class
448 : // soffice/sfx implementation disposes the global service manager
449 : // Warning: After this call you can't call uno services
450 242 : if( pSVData->mpApp )
451 : {
452 242 : pSVData->mpApp->DeInit();
453 : }
454 242 : if( pSVData->maDeInitHook.IsSet() )
455 : {
456 115 : pSVData->maDeInitHook.Call(0);
457 242 : }
458 : }
459 :
460 242 : if ( pSVData->maAppData.mpSettings )
461 : {
462 223 : if ( pSVData->maAppData.mpCfgListener )
463 : {
464 223 : pSVData->maAppData.mpSettings->GetSysLocale().GetOptions().RemoveListener( pSVData->maAppData.mpCfgListener );
465 223 : delete pSVData->maAppData.mpCfgListener;
466 : }
467 :
468 223 : delete pSVData->maAppData.mpSettings;
469 223 : pSVData->maAppData.mpSettings = NULL;
470 : }
471 242 : if ( pSVData->maAppData.mpAccelMgr )
472 : {
473 0 : delete pSVData->maAppData.mpAccelMgr;
474 0 : pSVData->maAppData.mpAccelMgr = NULL;
475 : }
476 242 : if ( pSVData->maAppData.mpAppFileName )
477 : {
478 242 : delete pSVData->maAppData.mpAppFileName;
479 242 : pSVData->maAppData.mpAppFileName = NULL;
480 : }
481 242 : if ( pSVData->maAppData.mpAppName )
482 : {
483 116 : delete pSVData->maAppData.mpAppName;
484 116 : pSVData->maAppData.mpAppName = NULL;
485 : }
486 242 : if ( pSVData->maAppData.mpDisplayName )
487 : {
488 116 : delete pSVData->maAppData.mpDisplayName;
489 116 : pSVData->maAppData.mpDisplayName = NULL;
490 : }
491 242 : if ( pSVData->maAppData.mpEventListeners )
492 : {
493 120 : delete pSVData->maAppData.mpEventListeners;
494 120 : pSVData->maAppData.mpEventListeners = NULL;
495 : }
496 242 : if ( pSVData->maAppData.mpKeyListeners )
497 : {
498 0 : delete pSVData->maAppData.mpKeyListeners;
499 0 : pSVData->maAppData.mpKeyListeners = NULL;
500 : }
501 242 : if ( pSVData->maAppData.mpPostYieldListeners )
502 : {
503 0 : delete pSVData->maAppData.mpPostYieldListeners;
504 0 : pSVData->maAppData.mpPostYieldListeners = NULL;
505 : }
506 :
507 242 : if ( pSVData->maAppData.mpFirstHotKey )
508 0 : ImplFreeHotKeyData();
509 242 : if ( pSVData->maAppData.mpFirstEventHook )
510 0 : ImplFreeEventHookData();
511 :
512 242 : if (pSVData->mpBlendFrameCache)
513 0 : delete pSVData->mpBlendFrameCache, pSVData->mpBlendFrameCache = NULL;
514 :
515 242 : ImplDeletePrnQueueList();
516 242 : delete pSVData->maGDIData.mpScreenFontList;
517 242 : pSVData->maGDIData.mpScreenFontList = NULL;
518 242 : delete pSVData->maGDIData.mpScreenFontCache;
519 242 : pSVData->maGDIData.mpScreenFontCache = NULL;
520 :
521 242 : if ( pSVData->mpResMgr )
522 : {
523 105 : delete pSVData->mpResMgr;
524 105 : pSVData->mpResMgr = NULL;
525 : }
526 :
527 242 : ResMgr::DestroyAllResMgr();
528 :
529 : // destroy all Sal interfaces before destorying the instance
530 : // and thereby unloading the plugin
531 242 : delete pSVData->mpSalSystem;
532 242 : pSVData->mpSalSystem = NULL;
533 242 : delete pSVData->mpSalTimer;
534 242 : pSVData->mpSalTimer = NULL;
535 :
536 : // Deinit Sal
537 242 : DestroySalInstance( pSVData->mpDefInst );
538 :
539 242 : if( pOwnSvApp )
540 : {
541 115 : delete pOwnSvApp;
542 115 : pOwnSvApp = NULL;
543 : }
544 :
545 242 : EmbeddedFontsHelper::clearTemporaryFontFiles();
546 242 : }
547 :
548 : // only one call is allowed
549 : struct WorkerThreadData
550 : {
551 : oslWorkerFunction pWorker;
552 : void * pThreadData;
553 162 : WorkerThreadData( oslWorkerFunction pWorker_, void * pThreadData_ )
554 : : pWorker( pWorker_ )
555 162 : , pThreadData( pThreadData_ )
556 : {
557 162 : }
558 : };
559 :
560 : #ifdef WNT
561 : static HANDLE hThreadID = 0;
562 : static unsigned __stdcall _threadmain( void *pArgs )
563 : {
564 : OleInitialize( NULL );
565 : ((WorkerThreadData*)pArgs)->pWorker( ((WorkerThreadData*)pArgs)->pThreadData );
566 : delete (WorkerThreadData*)pArgs;
567 : OleUninitialize();
568 : hThreadID = 0;
569 : return 0;
570 : }
571 : #else
572 : static oslThread hThreadID = 0;
573 : extern "C"
574 : {
575 162 : static void SAL_CALL MainWorkerFunction( void* pArgs )
576 : {
577 162 : static_cast<WorkerThreadData*>(pArgs)->pWorker( static_cast<WorkerThreadData*>(pArgs)->pThreadData );
578 162 : delete static_cast<WorkerThreadData*>(pArgs);
579 162 : hThreadID = 0;
580 162 : }
581 : } // extern "C"
582 : #endif
583 :
584 162 : void CreateMainLoopThread( oslWorkerFunction pWorker, void * pThreadData )
585 : {
586 : #ifdef WNT
587 : // sal thread always call CoInitializeEx, so a sysdepen implementation is necessary
588 :
589 : unsigned uThreadID;
590 : hThreadID = (HANDLE)_beginthreadex(
591 : NULL, // no security handle
592 : 0, // stacksize 0 means default
593 : _threadmain, // thread worker function
594 : new WorkerThreadData( pWorker, pThreadData ), // arguments for worker function
595 : 0, // 0 means: create immediately otherwise use CREATE_SUSPENDED
596 : &uThreadID ); // thread id to fill
597 : #else
598 162 : hThreadID = osl_createThread( MainWorkerFunction, new WorkerThreadData( pWorker, pThreadData ) );
599 : #endif
600 162 : }
601 :
602 162 : void JoinMainLoopThread()
603 : {
604 162 : if( hThreadID )
605 : {
606 : #ifdef WNT
607 : WaitForSingleObject(hThreadID, INFINITE);
608 : #else
609 128 : osl_joinWithThread(hThreadID);
610 128 : osl_destroyThread( hThreadID );
611 : #endif
612 : }
613 963 : }
614 :
615 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|