int __tmainCRTStartup( void ) { unsigned int osplatform = 0; unsigned int winver = 0; unsigned int winmajor = 0; unsigned int winminor = 0; unsigned int osver = 0; int initret; int mainret = 0; OSVERSIONINFOA* posvi; int managedapp; #ifdef _WINMAIN_ _TUCHAR* lpszCommandLine; STARTUPINFO StartupInfo; __try { /* Note: MSDN specifically notes that GetStartupInfo returns no error, and throws unspecified SEH if it fails, so the very general exception handler below is appropriate */ GetStartupInfo(&StartupInfo); } __except (EXCEPTION_EXECUTE_HANDLER) { return 255; } #endif /* _WINMAIN_ */ /* * Dynamically allocate the OSVERSIONINFOA buffer, so we avoid * triggering the /GS buffer overrun detection. That can't be * used here, since the guard cookie isn't available until we * initialize it from here! */ posvi = (OSVERSIONINFOA*)HeapAlloc(GetProcessHeap(), 0, sizeof(OSVERSIONINFOA)); if (!posvi) { fast_error_exit(_RT_HEAP); return 255; } /* * Get the full Win32 version */ posvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); if (!GetVersionExA(posvi)) { HeapFree(GetProcessHeap(), 0, posvi); return 255; } osplatform = posvi->dwPlatformId; winmajor = posvi->dwMajorVersion; winminor = posvi->dwMinorVersion; /* * The somewhat bizarre calculations of _osver and _winver are * required for backward compatibility (used to use GetVersion) */ osver = (posvi->dwBuildNumber) & 0x07fff; HeapFree(GetProcessHeap(), 0, posvi); if (osplatform != VER_PLATFORM_WIN32_NT) { osver |= 0x08000; } winver = (winmajor << 8) + winminor; _set_osplatform(osplatform); _set_winver(winver); _set_winmajor(winmajor); _set_winminor(winminor); _set_osver(osver); /* * Determine if this is a managed application */ managedapp = check_managed_app(); if (!_heap_init(1)) { /* initialize heap */ fast_error_exit(_RT_HEAPINIT); /* write message and die */ } if (!_mtinit()) { /* initialize multi-thread */ fast_error_exit(_RT_THREAD); /* write message and die */ } /* Enable buffer count checking if linking against static lib */ _CrtSetCheckCount(TRUE); /* * Initialize the Runtime Checks stuff */ #ifdef _RTC _RTC_Initialize(); #endif /* _RTC */ /* * Guard the remainder of the initialization code and the call * to user's main, or WinMain, function in a __try/__except * statement. */ __try { if (_ioinit() < 0) { /* initialize lowio */ _amsg_exit(_RT_LOWIOINIT); } /* get wide cmd line info */ _tcmdln = (_TSCHAR*)GetCommandLineT(); /* get wide environ info */ _tenvptr = (_TSCHAR*)GetEnvironmentStringsT(); if (_tsetargv() < 0) { _amsg_exit(_RT_SPACEARG); } if (_tsetenvp() < 0) { _amsg_exit(_RT_SPACEENV); } initret = _cinit(TRUE); /* do C data initialize */ if (initret != 0) { _amsg_exit(initret); } #ifdef _WINMAIN_ lpszCommandLine = _twincmdln(); mainret = _tWinMain((HINSTANCE)&__ImageBase, NULL, lpszCommandLine, StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT ); #else /* _WINMAIN_ */ _tinitenv = _tenviron; mainret = _tmain(__argc, _targv, _tenviron); #endif /* _WINMAIN_ */ if (!managedapp) { exit(mainret); } _cexit(); } __except (_XcptFilter(GetExceptionCode(), GetExceptionInformation())) { /* * Should never reach here */ mainret = GetExceptionCode(); if (!managedapp) { _exit(mainret); } _c_exit(); } /* end of try - except */ return mainret; }
int __tmainCRTStartup( void ) { #ifdef _WINMAIN_ _TUCHAR* lpszCommandLine; STARTUPINFO StartupInfo; BOOL inDoubleQuote = FALSE; __try { /* Note: MSDN specifically notes that GetStartupInfo returns no error, and throws unspecified SEH if it fails, so the very general exception handler below is appropriate */ GetStartupInfo(&StartupInfo); } __except (EXCEPTION_EXECUTE_HANDLER) { return 255; } #endif /* _WINMAIN_ */ /* * Guard the initialization code and the call to user's main, or * WinMain, function in a __try/__except statement. */ __try { /* * There is a possiblity that the module where this object is * linked into is a mixed module. In all the cases we gurantee that * native initialization will occur before managed initialization. * Also in anycase this code should never be called when some other * code is initializing native code, that's why we exit in that case. * * Do runtime startup initializers. * * Note: the only possible entry we'll be executing here is for * __lconv_init, pulled in from charmax.obj only if the EXE was * compiled with -J. All other .CRT$XI* initializers are only * run as part of the CRT itself, and so for the CRT DLL model * are not found in the EXE. For that reason, we call _initterm, * not _initterm_e, because __lconv_init will never return failure, * and _initterm_e is not exported from the CRT DLL. * * Note further that, when using the CRT DLL, executing the * .CRT$XI* initializers is only done for an EXE, not for a DLL * using the CRT DLL. That is to make sure the -J setting for * the EXE is not overriden by that of any DLL. */ void* lock_free = 0; void* fiberid = ((PNT_TIB)NtCurrentTeb())->StackBase; int nested = FALSE; while ((lock_free = InterlockedCompareExchangePointer((volatile PVOID*)&__native_startup_lock, fiberid, 0)) != 0) { if (lock_free == fiberid) { nested = TRUE; break; } /* some other thread is running native startup/shutdown during a cctor/domain unload. Should only happen if this DLL was built using the Everett-compat loader lock fix in vcclrit.h */ /* wait for the other thread to complete init before we return */ Sleep(1000); } if (__native_startup_state == __initializing) { _amsg_exit(_RT_CRT_INIT_CONFLICT); } else if (__native_startup_state == __uninitialized) { __native_startup_state = __initializing; #ifndef _SYSCRT if (_initterm_e(__xi_a, __xi_z) != 0) { return 255; } #else /* _SYSCRT */ _initterm((_PVFV*)(void*)__xi_a, (_PVFV*)(void*)__xi_z); #endif /* _SYSCRT */ } else { has_cctor = 1; } /* * do C++ constructors (initializers) specific to this EXE */ if (__native_startup_state == __initializing) { _initterm(__xc_a, __xc_z); __native_startup_state = __initialized; } _ASSERTE(__native_startup_state == __initialized); if (!nested) { /* For X86, the definition of InterlockedExchangePointer wrongly causes warning C4312 */ #pragma warning(push) #pragma warning(disable:4312) InterlockedExchangePointer((volatile PVOID*)&__native_startup_lock, 0); #pragma warning(pop) } /* * If we have any dynamically initialized __declspec(thread) * variables, then invoke their initialization for the primary * thread used to start the process, by calling __dyn_tls_init * through a callback defined in tlsdyn.obj. */ if (__dyn_tls_init_callback != NULL && _IsNonwritableInCurrentImage((PBYTE)&__dyn_tls_init_callback)) { __dyn_tls_init_callback(NULL, DLL_THREAD_ATTACH, NULL); } /* Enable buffer count checking if linking against static lib */ _CrtSetCheckCount(TRUE); #ifdef _WINMAIN_ /* * Skip past program name (first token in command line). * Check for and handle quoted program name. */ #ifdef WPRFLAG /* OS may not support "W" flavors */ if (_wcmdln == NULL) { return 255; } lpszCommandLine = (wchar_t*)_wcmdln; #else /* WPRFLAG */ lpszCommandLine = (unsigned char*)_acmdln; #endif /* WPRFLAG */ while (*lpszCommandLine > SPACECHAR || (*lpszCommandLine && inDoubleQuote)) { /* * Flip the count from 1 to 0 or 0 to 1 if current character * is DOUBLEQUOTE */ if (*lpszCommandLine == DQUOTECHAR) { inDoubleQuote = !inDoubleQuote; } #ifdef _MBCS if (_ismbblead(*lpszCommandLine)) { if (lpszCommandLine) { lpszCommandLine++; } } #endif /* _MBCS */ ++lpszCommandLine; } /* * Skip past any white space preceeding the second token. */ while (*lpszCommandLine && (*lpszCommandLine <= SPACECHAR)) { lpszCommandLine++; } #ifdef WPRFLAG mainret = wWinMain( #else /* WPRFLAG */ mainret = WinMain( #endif /* WPRFLAG */ (HINSTANCE)&__ImageBase, NULL, lpszCommandLine, StartupInfo.dwFlags & STARTF_USESHOWWINDOW ? StartupInfo.wShowWindow : SW_SHOWDEFAULT ); #else /* _WINMAIN_ */ #ifdef WPRFLAG __winitenv = envp; mainret = wmain(argc, argv, envp); #else /* WPRFLAG */ __initenv = envp; mainret = main(argc, argv, envp); #endif /* WPRFLAG */ #endif /* _WINMAIN_ */ /* * Note that if the exe is managed app, we don't really need to * call exit or _c_exit. .cctor should be able to take care of * this. */ if (!managedapp) exit(mainret); if (has_cctor == 0) _cexit(); } __except (_XcptFilter(GetExceptionCode(), GetExceptionInformation())) { /* * Should never reach here */ mainret = GetExceptionCode(); /* * Note that if the exe is managed app, we don't really need to * call exit or _c_exit. .cctor should be able to take care of * this. */ if (!managedapp) { _exit(mainret); } if (has_cctor == 0) { _cexit(); } } /* end of try - except */ return mainret; }
BOOL WINAPI _CRT_INIT( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) { unsigned int osplatform = 0; unsigned int winver = 0; unsigned int winmajor = 0; unsigned int winminor = 0; unsigned int osver = 0; /* * Start-up code only gets executed when the process is initialized */ if (dwReason == DLL_PROCESS_ATTACH) { /* * Dynamically allocate the OSVERSIONINFOA buffer, so we avoid * triggering the /GS buffer overrun detection. That can't be * used here, since the guard cookie isn't available until we * initialize it from here! */ OSVERSIONINFOA* posvi = (OSVERSIONINFOA*)HeapAlloc(GetProcessHeap(), 0, sizeof(OSVERSIONINFOA)); if (!posvi) { return FALSE; } /* * Get the full Win32 version */ posvi->dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); if (!GetVersionExA(posvi)) { HeapFree(GetProcessHeap(), 0, posvi); return FALSE; } osplatform = posvi->dwPlatformId; winmajor = posvi->dwMajorVersion; winminor = posvi->dwMinorVersion; /* * The somewhat bizarre calculations of _osver and _winver are * required for backward compatibility (used to use GetVersion) */ osver = (posvi->dwBuildNumber) & 0x07fff; HeapFree(GetProcessHeap(), 0, posvi); if (osplatform != VER_PLATFORM_WIN32_NT) { osver |= 0x08000; } winver = (winmajor << 8) + winminor; _set_osplatform(osplatform); _set_winver(winver); _set_winmajor(winmajor); _set_winminor(winminor); _set_osver(osver); if (!_heap_init(1)) { /* initialize heap */ return FALSE; /* fail to load DLL */ } if (!_mtinit()) { /* initialize multi-thread */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail to load DLL */ } /* * Initialize the Runtime Checks stuff */ #ifdef _RTC _RTC_Initialize(); #endif /* _RTC */ _acmdln = (char*)GetCommandLineA(); _aenvptr = (char*)__crtGetEnvironmentStringsA(); if (_ioinit() < 0) { /* initialize lowio */ _mtterm(); /* free TLS index, call _mtdeletelocks() */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail to load DLL */ } if (_setargv() < 0 || /* get cmd line info */ _setenvp() < 0 || /* get environ info */ _cinit(FALSE) != 0) { /* do C data initialize, but don't init floating point */ _ioterm(); /* shut down lowio */ _mtterm(); /* free TLS index, call _mtdeletelocks() */ _heap_term(); /* heap is now invalid! */ return FALSE; /* fail to load DLL */ } /* Enable buffer count checking if linking against static lib */ _CrtSetCheckCount(TRUE); /* * increment flag to indicate process attach notification * has been received */ __proc_attached++; } else if (dwReason == DLL_PROCESS_DETACH) { if (__proc_attached > 0) { __proc_attached--; /* * Any basic clean-up code that goes here must be duplicated * below in _DllMainCRTStartup for the case where the user's * DllMain() routine fails on a Process Attach notification. * This does not include calling user C++ destructors, etc. */ if (_C_Termination_Done == FALSE) { _cexit(); } #ifdef _DEBUG /* Dump all memory leaks */ if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF) { _CrtDumpMemoryLeaks(); } #endif /* _DEBUG */ /* * What remains is to clean up the system resources we have * used (handles, critical sections, memory,...,etc.). This * needs to be done if the whole process is NOT terminating. */ #ifndef _DEBUG if (lpreserved == NULL) { #endif /* _DEBUG */ /* * The process is NOT terminating so we must clean up... */ /* Shut down lowio */ _ioterm(); _mtterm(); /* This should be the last thing the C run-time does */ _heap_term(); /* heap is now invalid! */ #ifndef _DEBUG } #endif /* _DEBUG */ } else /* no prior process attach, just return */ { return FALSE; } } else if (dwReason == DLL_THREAD_ATTACH) { _ptiddata ptd; /* Initialize FlsGetValue function pointer */ __set_flsgetvalue(); if (((ptd = _calloc_crt(1, sizeof(struct _tiddata))) != NULL)) { if (FLS_SETVALUE(__flsindex, (LPVOID)ptd)) { /* * Initialize of per-thread data */ _initptd(ptd, NULL); ptd->_tid = GetCurrentThreadId(); ptd->_thandle = (uintptr_t)(-1); } else { _free_crt(ptd); return FALSE; } } else { return FALSE; } } else if (dwReason == DLL_THREAD_DETACH) { _freeptd(NULL); /* free up per-thread CRT data */ } return TRUE ; }
BOOL WINAPI _CRT_INIT( HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved ) { /* * If this is a process detach notification, check that there has * been a prior (successful) process attachment. */ if ( dwReason == DLL_PROCESS_DETACH ) { if ( __proc_attached > 0 ) __proc_attached--; else /* * no prior process attach. just return failure. */ return FALSE; } #ifdef _M_IX86 /* * Set the local copy of the Pentium FDIV adjustment flag */ _adjust_fdiv = * _imp___adjust_fdiv; #endif /* _M_IX86 */ /* * do C++ constructors (initializers) specific to this DLL */ if ( dwReason == DLL_PROCESS_ATTACH ) { /* * There is a possiblity that the module where this object is * linked into is a mixed module. In all the cases we gurantee * that native initialization will occur before managed * initialization. Also in anycase this code should never be * called when some other code is initializing native code, * that's why we exit in that case. * * The case that is illegal is when managed code is executed for * the first time in loader lock. But there can be case when dll is * loaded in LoadLibrary and CLR could be already loaded in this * case it is perfectly OK to execute .cctor. */ void *lock_free=0; void *fiberid=((PNT_TIB)NtCurrentTeb())->StackBase; int nested=FALSE; while((lock_free=InterlockedCompareExchangePointer((volatile PVOID *)&__native_startup_lock, fiberid, 0))!=0) { if(lock_free==fiberid) { nested=TRUE; break; } /* some other thread is running native startup/shutdown during a cctor/domain unload. Should only happen if this DLL was built using the Everett-compat loader lock fix in vcclrit.h */ /* wait for the other thread to complete init before we return */ Sleep(1000); } if (__native_startup_state != __uninitialized) { _amsg_exit( _RT_CRT_INIT_CONFLICT); } else { /* * Set the native startup state to initializing. */ __native_startup_state = __initializing; /* * Invoke C initializers. */ #ifndef _SYSCRT if (_initterm_e( __xi_a, __xi_z ) != 0) return FALSE; #else /* _SYSCRT */ _initterm((_PVFV *)(void *)__xi_a, (_PVFV *)(void *)__xi_z); #endif /* _SYSCRT */ /* * Invoke C++ constructors */ _initterm(__xc_a,__xc_z); /* * Set the native initialization state to initialized. */ __native_startup_state = __initialized; } if(!nested) { /* For X86, the definition of InterlockedExchangePointer wrongly causes warning C4312 */ #pragma warning(push) #pragma warning(disable:4312) InterlockedExchangePointer((volatile PVOID *)&__native_startup_lock,0); #pragma warning(pop) } /* * If we have any dynamically initialized __declspec(thread) * variables, then invoke their initialization for the thread on * which the DLL is being loaded, by calling __dyn_tls_init through * a callback defined in tlsdyn.obj. We can't rely on the OS * calling __dyn_tls_init with DLL_PROCESS_ATTACH because, on * Win2K3 and before, that call happens before the CRT is * initialized. */ if (__dyn_tls_init_callback != NULL && _IsNonwritableInCurrentImage((PBYTE)&__dyn_tls_init_callback)) { __dyn_tls_init_callback(hDllHandle, DLL_THREAD_ATTACH, lpreserved); } /* Enable buffer count checking if linking against static lib */ _CrtSetCheckCount(TRUE); /* * Increment the process attached flag. */ __proc_attached++; } else if ( dwReason == DLL_PROCESS_DETACH ) { /* * Any basic clean-up code that goes here must be * duplicated below in _DllMainCRTStartup for the * case where the user's DllMain() routine fails on a * Process Attach notification. This does not include * calling user C++ destructors, etc. */ /* * do _onexit/atexit() terminators * (if there are any) * * These terminators MUST be executed in * reverse order (LIFO)! * * NOTE: * This code assumes that __onexitbegin * points to the first valid onexit() * entry and that __onexitend points * past the last valid entry. If * __onexitbegin == __onexitend, the * table is empty and there are no * routines to call. */ void *lock_free=0; while((lock_free=InterlockedCompareExchangePointer((volatile PVOID *)&__native_startup_lock, (PVOID)1, 0))!=0) { /* some other thread is running native startup/shutdown during a cctor/domain unload. Should only happen if this DLL was built using the Everett-compat loader lock fix in vcclrit.h */ /* wait for the other thread to complete init before we return */ Sleep(1000); } if(__native_startup_state!=__initialized) { /* somehow we are in a very bad state running shutdown when we have not started */ _amsg_exit( _RT_CRT_INIT_CONFLICT); } else { _PVFV * onexitbegin = (_PVFV *)_decode_pointer(__onexitbegin); if (onexitbegin) { _PVFV * onexitend = (_PVFV *)_decode_pointer(__onexitend); while ( --onexitend >= onexitbegin ) /* * if current table entry is not * NULL, call thru it. */ if ( *onexitend != NULL ) (**onexitend)(); /* * free the block holding onexit table to * avoid memory leaks. Also zero the ptr * variables so that they are clearly cleaned up. */ _free_crt ( onexitbegin ) ; __onexitbegin = __onexitend = (_PVFV *)_encoded_null(); } __native_startup_state = __uninitialized; /* For X86, the definition of InterlockedExchangePointer wrongly causes warning C4312 */ #pragma warning(push) #pragma warning(disable:4312) InterlockedExchangePointer((volatile PVOID *)&__native_startup_lock,0); #pragma warning(pop) } } return TRUE; }