1. 프로그램의 시작점 WinMain
int32 WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ char* pCmdLine, _In_ int32 nCmdShow)
{
// LaunchWidnowsStartup으로부터 엔진 루프까지
int32 Result = LaunchWindowsStartup(hInInstance, hPrevInstance, pCmdLine, nCmdShow, nullptr);
// 종료 전 해야할 일 처리
LaunchWindowsShutdown();
// 실행 결과 반환
return Result;
}
2. 엔진 시작점 LaunchWindowsStartup
LAUNCH_API int32 LaunchWindowsStartup( HINSTANCE hInInstance, HINSTANCE hPrevInstance, char*, int32 nCmdShow, const TCHAR* CmdLine )
{
// 로깅을 위한 매크로 호출
TRACE_BOOKMARK(TEXT("WinMain.Enter"));
// 메모리 주소 취약점과 메모리 오류를 감지하기 위한 매크로가 선언된 경우의 처리
#if USING_ADDRESS_SANITISER
__asan_set_error_report_callback(ASanErrorCallback);
#endif
// Setup common Windows settings - 실행 인자 검증 및 Debug모드인 경우 메모리 누수 검출 활성화
SetupWindowsEnvironment();
int32 ErrorLevel = 0;
hInstance = hInInstance;
if (!CmdLine)
{
CmdLine = ::GetCommandLineW();
// Attempt to process the command-line arguments using the standard Windows implementation
// (This ensures behavior parity with other platforms where argc and argv are used.)
if ( ProcessCommandLine() )
{
CmdLine = *GSavedCommandLine;
}
}
// If we're running in unattended mode, make sure we never display error dialogs if we crash.
if ( FParse::Param( CmdLine, TEXT("unattended") ) )
{
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
}
if ( FParse::Param( CmdLine,TEXT("crashreports") ) )
{
GAlwaysReportCrash = true;
}
uint32 LogicalCoreAffinity = 0;
uint32 PhysicalCoreAffinity = 0;
FParse::Value(CmdLine, TEXT("-processaffinity="), LogicalCoreAffinity);
FParse::Value(CmdLine, TEXT("-processaffinityphysical="), PhysicalCoreAffinity);
if (LogicalCoreAffinity > 0)
{
FWindowsPlatformProcess::SetProcessAffinity(LogicalCoreAffinity, false);
}
else if (PhysicalCoreAffinity > 0)
{
FWindowsPlatformProcess::SetProcessAffinity(PhysicalCoreAffinity, true);
}
bool bNoExceptionHandler = FParse::Param(CmdLine,TEXT("noexceptionhandler"));
(void)bNoExceptionHandler;
bool bIgnoreDebugger = FParse::Param(CmdLine, TEXT("IgnoreDebugger"));
(void)bIgnoreDebugger;
bool bIsDebuggerPresent = FPlatformMisc::IsDebuggerPresent() && !bIgnoreDebugger;
(void)bIsDebuggerPresent;
// Using the -noinnerexception parameter will disable the exception handler within native C++, which is call from managed code,
// which is called from this function.
// The default case is to have three wrapped exception handlers
// Native: WinMain() -> Native: GuardedMainWrapper().
// The inner exception handler in GuardedMainWrapper() catches crashes/asserts in native C++ code and is the only way to get the
// correct callstack when running a 64-bit executable. However, XAudio2 sometimes (?) don't like this and it may result in no sound.
#ifdef _WIN64
if ( FParse::Param(CmdLine,TEXT("noinnerexception")) || FApp::IsBenchmarking() || bNoExceptionHandler)
{
GEnableInnerException = false;
}
#endif
// When we're running embedded, assume that the outer application is going to be handling crash reporting
#if UE_BUILD_DEBUG
if (GUELibraryOverrideSettings.bIsEmbedded || !GAlwaysReportCrash)
#else
if (GUELibraryOverrideSettings.bIsEmbedded || bNoExceptionHandler || (bIsDebuggerPresent && !GAlwaysReportCrash))
#endif
{
// Don't use exception handling when a debugger is attached to exactly trap the crash. This does NOT check
// whether we are the first instance or not!
ErrorLevel = GuardedMain( CmdLine );
}
else
{
// Use structured exception handling to trap any crashes, walk the the stack and display a crash dialog box.
#if !PLATFORM_SEH_EXCEPTIONS_DISABLED
__try
#endif
{
GIsGuarded = 1;
// Run the guarded code.
ErrorLevel = GuardedMainWrapper( CmdLine );
GIsGuarded = 0;
}
#if !PLATFORM_SEH_EXCEPTIONS_DISABLED
__except( FPlatformMisc::GetCrashHandlingType() == ECrashHandlingType::Default
? ( GEnableInnerException ? EXCEPTION_EXECUTE_HANDLER : ReportCrash(GetExceptionInformation()) )
: EXCEPTION_CONTINUE_SEARCH )
{
// Crashed.
ErrorLevel = 1;
if(GError)
{
GError->HandleError();
}
LaunchStaticShutdownAfterError();
FPlatformMallocCrash::Get().PrintPoolsUsage();
FPlatformMisc::RequestExit( true, TEXT("LaunchWindowsStartup.ExceptionHandler"));
}
#endif
}
TRACE_BOOKMARK(TEXT("WinMain.Exit"));
return ErrorLevel;
}