Files
video-v1/vav2/Vav2Player/Vav2Player/App.xaml.cpp
2025-09-20 00:45:20 +09:00

282 lines
11 KiB
C++

#include "pch.h"
#include "App.xaml.h"
#include "MainWindow.xaml.h"
#include "src/Console/HeadlessDecoder.h"
#include <iostream>
#include <fstream>
#include <signal.h>
#include <crtdbg.h>
using namespace winrt;
// using namespace Microsoft::UI::Xaml; // 충돌 방지를 위해 명시적으로 사용
// 헤드리스 모드용 에러 핸들러
void HeadlessAbortHandler(int signal) {
std::cerr << "\n*** FATAL ERROR ***" << std::endl;
switch (signal) {
case SIGABRT:
std::cerr << "Program aborted (SIGABRT)" << std::endl;
break;
case SIGFPE:
std::cerr << "Floating point exception (SIGFPE)" << std::endl;
break;
case SIGILL:
std::cerr << "Illegal instruction (SIGILL)" << std::endl;
break;
case SIGINT:
std::cerr << "Interrupt signal (SIGINT)" << std::endl;
break;
case SIGSEGV:
std::cerr << "Segmentation violation (SIGSEGV)" << std::endl;
break;
case SIGTERM:
std::cerr << "Termination request (SIGTERM)" << std::endl;
break;
default:
std::cerr << "Unknown signal: " << signal << std::endl;
break;
}
std::cerr << "Application will exit now." << std::endl;
std::cerr.flush();
// 즉시 종료 (UI 팝업 방지)
TerminateProcess(GetCurrentProcess(), 1);
}
// abort() 후킹을 위한 사용자 정의 함수
void custom_abort() {
std::cerr << "\n*** CUSTOM ABORT CALLED ***" << std::endl;
std::cerr << "Terminating process without UI..." << std::endl;
std::cerr.flush();
TerminateProcess(GetCurrentProcess(), 1);
}
// 헤드리스 모드용 assertion 핸들러
int HeadlessAssertHandler(int reportType, char* message, int* returnValue) {
// 즉시 종료하여 어떤 UI도 표시하지 않음
std::cerr << "\n*** CRT ERROR INTERCEPTED ***" << std::endl;
std::cerr << "Type: ";
switch (reportType) {
case _CRT_WARN:
std::cerr << "Warning";
break;
case _CRT_ERROR:
std::cerr << "Error";
break;
case _CRT_ASSERT:
std::cerr << "Assertion";
break;
default:
std::cerr << "Unknown (" << reportType << ")";
break;
}
std::cerr << std::endl;
std::cerr << "Message: " << (message ? message : "Unknown") << std::endl;
std::cerr << "Terminating immediately..." << std::endl;
std::cerr.flush();
// 강제 즉시 종료 (UI 팝업 완전 방지)
TerminateProcess(GetCurrentProcess(), 1);
return TRUE; // 이 라인은 실행되지 않음
}
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace winrt::Vav2Player::implementation
{
/// <summary>
/// Initializes the singleton application object. This is the first line of authored code
/// executed, and as such is the logical equivalent of main() or WinMain().
/// </summary>
App::App()
{
// Xaml objects should not call InitializeComponent during construction.
// See https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
#if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException([](Windows::Foundation::IInspectable const&, winrt::Microsoft::UI::Xaml::UnhandledExceptionEventArgs const& e)
{
if (IsDebuggerPresent())
{
auto errorMessage = e.Message();
__debugbreak();
}
});
#endif
}
/// <summary>
/// Invoked when the application is launched.
/// </summary>
/// <param name="e">Details about the launch request and process.</param>
void App::OnLaunched([[maybe_unused]] winrt::Microsoft::UI::Xaml::LaunchActivatedEventArgs const& e)
{
// 명령줄 인자 확인
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
// 인자가 있으면 헤드리스 모드로 실행
if (argc >= 2) {
// 헤드리스 모드용 에러 처리 설정
// 1. 크래시 리포트 UI 비활성화 (더 강력한 설정)
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX | SEM_NOALIGNMENTFAULTEXCEPT);
// 2. Windows Error Reporting 비활성화
typedef BOOL(WINAPI* tGetPolicy)(LPDWORD lpFlags);
typedef BOOL(WINAPI* tSetPolicy)(DWORD dwFlags);
HMODULE hMod = LoadLibraryA("kernel32.dll");
if (hMod) {
tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(hMod, "SetErrorMode");
if (pSetPolicy) {
pSetPolicy(SEM_NOGPFAULTERRORBOX);
}
FreeLibrary(hMod);
}
// 3. CRT 에러 리포트 모드 설정 (Debug 빌드용 특별 처리)
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
// Debug 빌드에서 abort() UI 완전 비활성화
#ifdef _DEBUG
_CrtSetReportMode(_CRT_WARN, 0);
_CrtSetReportMode(_CRT_ERROR, 0);
_CrtSetReportMode(_CRT_ASSERT, 0);
// Debug CRT의 abort 동작 완전 비활성화
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
// Debug heap의 assertion 비활성화
int tmpFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
tmpFlag &= ~_CRTDBG_ALLOC_MEM_DF;
tmpFlag &= ~_CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(tmpFlag);
#endif
// 4. 사용자 정의 에러 핸들러 설정 (모든 CRT 에러 가로채기)
_CrtSetReportHook(HeadlessAssertHandler);
// 5. abort() 동작 설정 (Release 빌드용)
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
// 6. 시그널 핸들러 설정 (즉시 종료)
signal(SIGABRT, HeadlessAbortHandler);
signal(SIGFPE, HeadlessAbortHandler);
signal(SIGILL, HeadlessAbortHandler);
signal(SIGINT, HeadlessAbortHandler);
signal(SIGSEGV, HeadlessAbortHandler);
signal(SIGTERM, HeadlessAbortHandler);
// 7. Windows 구조화된 예외 처리 설정
SetUnhandledExceptionFilter([](EXCEPTION_POINTERS* ExceptionInfo) -> LONG {
std::cerr << "\n*** UNHANDLED EXCEPTION ***" << std::endl;
std::cerr << "Exception Code: 0x" << std::hex << ExceptionInfo->ExceptionRecord->ExceptionCode << std::endl;
std::cerr << "Terminating process without UI..." << std::endl;
std::cerr.flush();
TerminateProcess(GetCurrentProcess(), 1);
return EXCEPTION_EXECUTE_HANDLER;
});
// 8. CRT가 terminate를 호출할 때의 처리
std::set_terminate([]() {
std::cerr << "\n*** TERMINATE CALLED ***" << std::endl;
std::cerr << "Terminating process without UI..." << std::endl;
std::cerr.flush();
TerminateProcess(GetCurrentProcess(), 1);
});
// 콘솔 창 할당 (강제 설정)
AllocConsole();
// 표준 입출력 스트림을 콘솔로 리디렉션
FILE* pCout;
FILE* pCerr;
FILE* pCin;
freopen_s(&pCout, "CONOUT$", "w", stdout);
freopen_s(&pCerr, "CONOUT$", "w", stderr);
freopen_s(&pCin, "CONIN$", "r", stdin);
// C++ 스트림도 동기화
std::ios::sync_with_stdio(true);
// 즉시 테스트 출력
std::cout << "Console initialized successfully!" << std::endl;
std::cout.flush();
std::cerr << "Error stream working!" << std::endl;
std::cerr.flush();
// 디버그 로그 파일 생성
std::ofstream debug_log("headless_debug.log");
debug_log << "=== HEADLESS DEBUG LOG ===" << std::endl;
debug_log << "Starting headless mode..." << std::endl;
debug_log.flush();
// UTF-16 to UTF-8 변환 (더 안전한 방법)
std::string input_file;
int size_needed = WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, NULL, 0, NULL, NULL);
if (size_needed > 0) {
input_file.resize(size_needed - 1);
WideCharToMultiByte(CP_UTF8, 0, argv[1], -1, &input_file[0], size_needed, NULL, NULL);
}
// 헤드리스 디코더 실행 (try-catch로 보호)
bool success = false;
try {
debug_log << "Creating HeadlessDecoder..." << std::endl;
debug_log.flush();
std::cout << "Creating HeadlessDecoder..." << std::endl;
std::cout.flush();
::Vav2Player::HeadlessDecoder decoder;
debug_log << "HeadlessDecoder created successfully" << std::endl;
debug_log.flush();
std::cout << "HeadlessDecoder created successfully" << std::endl;
std::cout.flush();
debug_log << "Calling ProcessFile with: " << input_file << std::endl;
debug_log.flush();
std::cout << "Calling ProcessFile..." << std::endl;
std::cout.flush();
success = decoder.ProcessFile(input_file);
debug_log << "ProcessFile completed with result: " << (success ? "SUCCESS" : "FAILURE") << std::endl;
debug_log.flush();
std::cout << "ProcessFile completed with result: " << (success ? "SUCCESS" : "FAILURE") << std::endl;
}
catch (const std::exception& e) {
debug_log << "\n*** EXCEPTION in main: " << e.what() << std::endl;
debug_log.flush();
std::cerr << "\n*** EXCEPTION in main: " << e.what() << std::endl;
success = false;
}
catch (...) {
debug_log << "\n*** UNKNOWN EXCEPTION in main" << std::endl;
debug_log.flush();
std::cerr << "\n*** UNKNOWN EXCEPTION in main" << std::endl;
success = false;
}
debug_log << "Closing debug log..." << std::endl;
debug_log.close();
// 결과에 따른 종료 코드
int exit_code = success ? 0 : 1;
// 사용자 입력 대기 (디버그용)
std::cout << "\nPress Enter to exit...";
std::cin.get();
// 프로그램 종료
LocalFree(argv);
ExitProcess(exit_code);
}
// 명령줄 인자가 없으면 일반 UI 모드
LocalFree(argv);
window = make<MainWindow>();
window.Activate();
}
}