xref: /trunk/main/sal/osl/w32/dllentry.c (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #ifdef _MSC_VER
29 #pragma warning(push,1) /* disable warnings within system headers */
30 #endif
31 #include <windows.h>
32 #ifdef _MSC_VER
33 #pragma warning(pop)
34 #endif
35 #include <tlhelp32.h>
36 #include <systools/win32/uwinapi.h>
37 #include <winsock.h>
38 #include <osl/diagnose.h>
39 #include <sal/types.h>
40 #include <float.h>
41 
42 #include <osl/diagnose.h>
43 #include <osl/mutex.h>
44 #include <sal/types.h>
45 
46 //------------------------------------------------------------------------------
47 // externals
48 //------------------------------------------------------------------------------
49 
50 extern DWORD            g_dwTLSTextEncodingIndex;
51 extern void SAL_CALL    _osl_callThreadKeyCallbackOnThreadDetach(void);
52 extern CRITICAL_SECTION g_ThreadKeyListCS;
53 extern oslMutex         g_Mutex;
54 extern oslMutex         g_CurrentDirectoryMutex;
55 
56 extern void rtl_locale_fini (void);
57 extern void rtl_memory_fini (void);
58 extern void rtl_cache_fini (void);
59 extern void rtl_arena_fini (void);
60 
61 #ifdef __MINGW32__
62 
63 typedef void (*func_ptr) (void);
64 extern func_ptr __CTOR_LIST__[];
65 extern func_ptr __DTOR_LIST__[];
66 
67 static void do_startup(void);
68 static void do_cleanup(void);
69 
70 #else
71 
72 /*
73 This is needed because DllMain is called after static constructors. A DLL's
74 startup and shutdown sequence looks like this:
75 
76 _pRawDllMain()
77 _CRT_INIT()
78 DllMain()
79 ....
80 DllMain()
81 _CRT_INIT()
82 _pRawDllMain()
83 
84 */
85 
86 static BOOL WINAPI _RawDllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved );
87 extern BOOL (WINAPI *_pRawDllMain)(HANDLE, DWORD, LPVOID) = _RawDllMain;
88 
89 #endif
90 
91 //------------------------------------------------------------------------------
92 // globales
93 //------------------------------------------------------------------------------
94 
95 DWORD         g_dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; // remember plattform
96 
97 //------------------------------------------------------------------------------
98 // DllMain
99 //------------------------------------------------------------------------------
100 #ifdef _M_IX86
101 int osl_isSingleCPU = 0;
102 #endif
103 
104 #ifdef __MINGW32__
105 
106 void
107 __do_global_dtors (void)
108 {
109   static func_ptr *p = __DTOR_LIST__ + 1;
110 
111   /*
112    * Call each destructor in the destructor list until a null pointer
113    * is encountered.
114    */
115   while (*p)
116     {
117       (*(p)) ();
118       p++;
119     }
120 }
121 
122 void
123 __do_global_ctors (void)
124 {
125   unsigned long nptrs = (unsigned long) __CTOR_LIST__[0];
126   unsigned i;
127 
128   /*
129    * If the first entry in the constructor list is -1 then the list
130    * is terminated with a null entry. Otherwise the first entry was
131    * the number of pointers in the list.
132    */
133   if (nptrs == -1)
134     {
135       for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++)
136 	;
137     }
138 
139   /*
140    * Go through the list backwards calling constructors.
141    */
142   for (i = nptrs; i >= 1; i--)
143     {
144       __CTOR_LIST__[i] ();
145     }
146 
147   /*
148    * Register the destructors for processing on exit.
149    */
150   atexit (__do_global_dtors);
151 }
152 
153 static int initialized = 0;
154 
155 void
156 __main (void)
157 {
158   if (!initialized)
159     {
160       initialized = 1;
161       do_startup();
162       __do_global_ctors ();
163     }
164 }
165 
166 static void do_startup( void )
167 {
168 #else
169 static BOOL WINAPI _RawDllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
170 {
171     (void)hinstDLL; /* avoid warnings */
172     (void)lpvReserved; /* avoid warnings */
173 
174     switch (fdwReason)
175     {
176         case DLL_PROCESS_ATTACH:
177             {
178 #endif
179                 OSVERSIONINFO aInfo;
180 
181 #ifdef _M_IX86
182                 SYSTEM_INFO SystemInfo;
183 
184                 GetSystemInfo(&SystemInfo);
185 
186                 /* Determine if we are on a multiprocessor/multicore/HT x86/x64 system
187                  *
188                  * The lock prefix for atomic operations in osl_[inc|de]crementInterlockedCount()
189                  * comes with a cost and is especially expensive on pre HT x86 single processor
190                  * systems, where it isn't needed at all.
191                  */
192                 if ( SystemInfo.dwNumberOfProcessors == 1 ) {
193                     osl_isSingleCPU = 1;
194                 }
195 #endif
196                 /* Suppress file error messages from system like "Floppy A: not inserted" */
197                 SetErrorMode( SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS );
198 
199                 /* initialize global mutex */
200                 g_Mutex = osl_createMutex();
201 
202                 /* initialize "current directory" mutex */
203                 g_CurrentDirectoryMutex = osl_createMutex();
204 
205 
206                 /* initialize Win9x unicode functions */
207                 aInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
208 
209                 if ( GetVersionEx(&aInfo) )
210                     g_dwPlatformId = aInfo.dwPlatformId;
211 
212                 g_dwTLSTextEncodingIndex = TlsAlloc();
213                 InitializeCriticalSection( &g_ThreadKeyListCS );
214 
215                 //We disable floating point exceptions. This is the usual state at program startup
216                 //but on Windows 98 and ME this is not always the case.
217                 _control87(_MCW_EM, _MCW_EM);
218 #ifdef __MINGW32__
219 		atexit(do_cleanup);
220 }
221 
222 void do_cleanup( void )
223 {
224 #else
225                 break;
226             }
227 
228         case DLL_PROCESS_DETACH:
229 #endif
230 
231             WSACleanup( );
232 
233             TlsFree( g_dwTLSTextEncodingIndex );
234             DeleteCriticalSection( &g_ThreadKeyListCS );
235 
236             osl_destroyMutex( g_Mutex );
237 
238             osl_destroyMutex( g_CurrentDirectoryMutex );
239 
240 #ifndef __MINGW32__
241 
242 			/*
243 
244 			On a product build memory management finalization might
245 			cause a crash without assertion (assertions off) if heap is
246 			corrupted. But a crash report won't help here because at
247 			this point all other threads have been terminated and only
248 			ntdll is on the stack. No chance to find the reason for the
249 			corrupted heap if so.
250 
251 			So annoying the user with a crash report is completly useless.
252 
253 			*/
254 
255 #ifndef DBG_UTIL
256 			__try
257 #endif
258 			{
259 				/* cleanup locale hashtable */
260 				rtl_locale_fini();
261 
262 				/* finalize memory management */
263 				rtl_memory_fini();
264 				rtl_cache_fini();
265 				rtl_arena_fini();
266 			}
267 #ifndef DBG_UTIL
268 			__except( EXCEPTION_EXECUTE_HANDLER )
269 			{
270 			}
271 #endif
272             break;
273     }
274 
275     return TRUE;
276 #endif
277 }
278 
279 static DWORD GetParentProcessId()
280 {
281     DWORD   dwParentProcessId = 0;
282     HANDLE  hSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
283 
284     if ( IsValidHandle( hSnapshot ) )
285     {
286         PROCESSENTRY32  pe;
287         BOOL            fSuccess;
288 
289         ZeroMemory( &pe, sizeof(pe) );
290         pe.dwSize = sizeof(pe);
291         fSuccess = Process32First( hSnapshot, &pe );
292 
293         while( fSuccess )
294         {
295             if ( GetCurrentProcessId() == pe.th32ProcessID )
296             {
297                 dwParentProcessId = pe.th32ParentProcessID;
298                 break;
299             }
300 
301             fSuccess = Process32Next( hSnapshot, &pe );
302         }
303 
304         CloseHandle( hSnapshot );
305     }
306 
307     return dwParentProcessId;
308 }
309 
310 static DWORD WINAPI ParentMonitorThreadProc( LPVOID lpParam )
311 {
312     DWORD   dwParentProcessId = (DWORD)lpParam;
313 
314     HANDLE  hParentProcess = OpenProcess( SYNCHRONIZE, FALSE, dwParentProcessId );
315     if ( IsValidHandle( hParentProcess ) )
316     {
317         if ( WAIT_OBJECT_0 == WaitForSingleObject( hParentProcess, INFINITE ) )
318         {
319             TerminateProcess( GetCurrentProcess(), 0 );
320         }
321         CloseHandle( hParentProcess );
322     }
323     return 0;
324 }
325 
326 BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved )
327 {
328     (void)hinstDLL; /* avoid warning */
329     (void)lpvReserved; /* avoid warning */
330     switch (fdwReason)
331     {
332         case DLL_PROCESS_ATTACH:
333         {
334             TCHAR   szBuffer[64];
335 
336             // This code will attach the process to it's parent process
337             // if the parent process had set the environment variable.
338             // The corresponding code (setting the environment variable)
339             // is is desktop/win32/source/officeloader.cxx
340 
341 
342             DWORD   dwResult = GetEnvironmentVariable( "ATTACHED_PARENT_PROCESSID", szBuffer, sizeof(szBuffer) );
343 
344             if ( dwResult && dwResult < sizeof(szBuffer) )
345             {
346                 DWORD   dwThreadId = 0;
347 
348                 DWORD   dwParentProcessId = (DWORD)atol( szBuffer );
349 
350                 if ( dwParentProcessId && GetParentProcessId() == dwParentProcessId )
351                 {
352                     // No error check, it works or it does not
353                     // Thread should only be started for headless mode, see desktop/win32/source/officeloader.cxx
354                     CreateThread( NULL, 0, ParentMonitorThreadProc, (LPVOID)dwParentProcessId, 0, &dwThreadId ); //
355                 }
356             }
357 
358             return TRUE;
359         }
360 
361         case DLL_THREAD_ATTACH:
362             break;
363 
364         case DLL_THREAD_DETACH:
365             _osl_callThreadKeyCallbackOnThreadDetach( );
366             break;
367     }
368 
369     return TRUE;
370 }
371