#include #include // _dup2/_fileno (senaryo log) #include #include #include #include #include #include #include #include "arac_kayitlari.hpp" // fiko::aracKomutSatiriAyarla (--arac=) #include "ayar_kalici.hpp" // ayarOku — kalıcı ayar (VulkanBaglam kurulmadan önce okunur) #include "belge_penceresi.hpp" // fiko::calistir + fiko::g_sonAdim #include "com_sunucu.hpp" // fiko::comEmbeddingKomutuMu/comSunucusuCalistir/Kaydet #include "fiko/cekirdek/gorev.hpp" // GorevSistemi::isciBaslatmaKancasiAyarla #include "fiko/core/gunluk.hpp" // fiko::gunluk::g_teshisAdim #include "fiko/geometri/brep.hpp" // geometri::occtSinyalKur #include "fiko/render/vulkan_aygit.hpp" // VulkanAygit::msaaOrnekSayisi — MSAA erken kurulum #ifdef FIKO_CEF #include "yardim_cef.hpp" // CEF yardım görüntüleyici (alt-süreç + init/shutdown) #endif // Uygulama giris noktasi. Tum belge/pencere mantigi belge_penceresi.cpp'de. // "cokme.log" yaz (istisna kodu + adres). SEH filter AV/stack-fastfail'i de yakalar. static std::wstring cokmeLogYolu() { wchar_t exeYol[MAX_PATH]{}; GetModuleFileNameW(nullptr, exeYol, MAX_PATH); return std::filesystem::path(exeYol).replace_filename(L"cokme.log").wstring(); } static LONG WINAPI cokmeYakala(EXCEPTION_POINTERS* bilgi) { FILE* f = nullptr; _wfopen_s(&f, cokmeLogYolu().c_str(), L"w"); const unsigned kod = (bilgi && bilgi->ExceptionRecord) ? (unsigned)bilgi->ExceptionRecord->ExceptionCode : 0u; void* adr = (bilgi && bilgi->ExceptionRecord) ? (void*)bilgi->ExceptionRecord->ExceptionAddress : nullptr; if (f) { fprintf(f, "FikoCad cokme (yakalanmamis istisna)\n"); fprintf(f, "kod: 0x%08X\n", kod); fprintf(f, "adres: %p\n", adr); fprintf(f, "son adim: %s\n", fiko::g_sonAdim ? fiko::g_sonAdim : "?"); fprintf(f, "teshis: %s\n", fiko::gunluk::g_teshisAdim ? fiko::gunluk::g_teshisAdim : "?"); fflush(f); fclose(f); } // ⚠️ AYRICA stderr'ye yaz: GUI uygulamada akış yönlendirilmemiş olabilir. // Ayrıca 0xC0000409 (__fastfail) SetUnhandledExceptionFilter'ı TETİKLEMEZ — // bu satır görünürse SEH yolu, görünmezse fastfail demektir (ayırıcı). { FILE* e = nullptr; if (_wfopen_s(&e, cokmeLogYolu().c_str(), L"a") == 0 && e) { fprintf(e, "[SEH] kod=0x%08X adres=%p son=%s teshis=%s\n", kod, adr, fiko::g_sonAdim ? fiko::g_sonAdim : "?", fiko::gunluk::g_teshisAdim ? fiko::gunluk::g_teshisAdim : "?"); fflush(e); fclose(e); } } return EXCEPTION_EXECUTE_HANDLER; // süreç sonlanır ama teşhis yazıldı } // --- __fastfail (0xC0000409) kaynak ayırıcıları ------------------------------------------- // std::terminate / abort / invalid_parameter / purecall hepsi UCRT'de __fastfail'e gider ve // SetUnhandledExceptionFilter'ı ATLAR. Bu handler'lar fastfail'den ÖNCE çalışır. static void cokmeSatiriYaz(const char* etiket, const char* ayrinti) { FILE* e = nullptr; if (_wfopen_s(&e, cokmeLogYolu().c_str(), L"a") == 0 && e) { fprintf(e, "[%s] %s | son=%s teshis=%s thread=%lu\n", etiket, ayrinti ? ayrinti : "", fiko::g_sonAdim ? fiko::g_sonAdim : "?", fiko::gunluk::g_teshisAdim ? fiko::gunluk::g_teshisAdim : "?", (unsigned long)GetCurrentThreadId()); fflush(e); fclose(e); } } // Cagri yigini: her kare "modul+RVA" olarak cokme.log'a yazilir; RVA'lar linker // map dosyasindan (fikocad.map, /MAP) cozulur. abort()/terminate hangi thread'de, // hangi fonksiyondan tetiklendi sorusunun tek guvenilir cevabi budur. static void yiginYaz(const char* etiket) { void* kare[48]{}; const USHORT n = CaptureStackBackTrace(0, 48, kare, nullptr); FILE* e = nullptr; if (_wfopen_s(&e, cokmeLogYolu().c_str(), L"a") != 0 || !e) return; fprintf(e, "[%s] yigin thread=%lu kare=%u\n", etiket, (unsigned long)GetCurrentThreadId(), (unsigned)n); for (USHORT i = 0; i < n; ++i) { HMODULE m = nullptr; GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)kare[i], &m); wchar_t yol[MAX_PATH]{}; if (m) GetModuleFileNameW(m, yol, MAX_PATH); const wchar_t* ad = wcsrchr(yol, L'\\'); ad = ad ? ad + 1 : yol; fprintf(e, " #%02u %ls+0x%llX\n", (unsigned)i, ad, (unsigned long long)((uintptr_t)kare[i] - (uintptr_t)m)); } fflush(e); fclose(e); } static void terminateYakala() { yiginYaz("TERMINATE-YIGIN"); char ayr[768] = "aktif istisna yok (dogrudan terminate/abort)"; if (std::exception_ptr p = std::current_exception()) { try { std::rethrow_exception(p); } catch (const std::exception& ex) { snprintf(ayr, sizeof ayr, "tip=%s what=%s", typeid(ex).name(), ex.what()); } catch (...) { snprintf(ayr, sizeof ayr, "std::exception olmayan istisna (catch(...))"); } } cokmeSatiriYaz("TERMINATE", ayr); TerminateProcess(GetCurrentProcess(), 0xDEAD0001); // fastfail'e dusme; kod ayirt edilsin } static void sigabrtYakala(int) { yiginYaz("SIGABRT-YIGIN"); cokmeSatiriYaz("SIGABRT", "abort() cagrildi"); TerminateProcess(GetCurrentProcess(), 0xDEAD0002); } static void gecersizParametreYakala(const wchar_t* ifade, const wchar_t* fonk, const wchar_t* dosya, unsigned satir, uintptr_t) { char ayr[512]; snprintf(ayr, sizeof ayr, "fonk=%ls dosya=%ls satir=%u ifade=%ls", fonk ? fonk : L"?", dosya ? dosya : L"?", satir, ifade ? ifade : L"?"); cokmeSatiriYaz("INVALID_PARAM", ayr); TerminateProcess(GetCurrentProcess(), 0xDEAD0003); } static void purecallYakala() { cokmeSatiriYaz("PURECALL", "saf sanal fonksiyon cagrisi"); TerminateProcess(GetCurrentProcess(), 0xDEAD0004); } int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, PWSTR komutSatiri, int) { // COM local-server aktivasyonu ("-Embedding") — CATIA VBA makrosunun // CreateObject("Fikocad.Application") cagirmasiyla Windows bu exe'yi BU // anahtarla baslatir (bkz. com_sunucu.hpp, docs/catia_calisma_alani.md). // AGIR motor/GUI kurulumunun (Vulkan/OCCT/lisans/CEF) TAMAMINI atlar — // yalniz COM mesaj dongusunu calistirir, tamamen headless/pencere-siz. if (fiko::comEmbeddingKomutuMu(komutSatiri ? std::wstring(komutSatiri) : std::wstring())) { return fiko::comSunucusuCalistir(); } #ifdef FIKO_CEF // CEF alt-süreçleri (render/gpu) aynı exe'yi çalıştırır → EN BAŞTA ele al ve çık; // aksi halde ağır kurulum her alt-süreçte tekrar koşar. Ana süreçte -1 döner, devam. { const int cefKod = fiko::yardimCefAltSurec(hInst); if (cefKod >= 0) return cefKod; } #endif SetUnhandledExceptionFilter(cokmeYakala); // AV/fastfail → cokme.log std::set_terminate(terminateYakala); // thread'de yakalanmayan istisna → tip + what() signal(SIGABRT, sigabrtYakala); _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // abort → SIGABRT yolu calissin _set_invalid_parameter_handler(gecersizParametreYakala); _set_purecall_handler(purecallYakala); fiko::comSunucusuKaydet(); // HKCU COM kaydi (CATIA VBA'dan CreateObject icin) — idempotent, ucuz fiko::geometri::occtSinyalKur(); // OCCT donanim sinyalleri → Standard_Failure (boolean/fillet çökme koruması) // Ayni korumayi worker thread'lere de tasi: OSD::SetSignal thread-local'dir; STEP import/ // recompute worker'da OCCT AV'si aksi halde surec dusurur (catch(...) SEH'i yakalayamaz). fiko::GorevSistemi::isciBaslatmaKancasiAyarla(&fiko::geometri::occtSinyalKur); int otoTestKare = 0; bool senaryoDokum = false; const std::wstring args = komutSatiri ? komutSatiri : L""; // Araç kipi (--arac=): ham komut satırını sakla; lisans yüklendikten SONRA // calistir() içinde çözülür (kapı lisans kimliklerine bakar). { const int n = WideCharToMultiByte(CP_UTF8, 0, args.c_str(), (int)args.size(), nullptr, 0, nullptr, nullptr); std::string dar(n > 0 ? (std::size_t)n : 0, '\0'); if (n > 0) WideCharToMultiByte(CP_UTF8, 0, args.c_str(), (int)args.size(), dar.data(), n, nullptr, nullptr); fiko::aracKomutSatiriAyarla(dar); } if (args.find(L"--oto-test") != std::wstring::npos) otoTestKare = 30; if (args.find(L"--senaryo-dokum") != std::wstring::npos) senaryoDokum = true; if (otoTestKare || senaryoDokum) { AllocConsole(); FILE* f; freopen_s(&f, "CONOUT$", "w", stdout); freopen_s(&f, "CONOUT$", "w", stderr); // Senaryo modu otomatik doğrulama: gunluk çıktısını exe yanındaki dosyaya // yönlendir (betikle GPU dispatch/perf denetimi; konsol pencere kalabalık). if (senaryoDokum) { wchar_t exeYol[MAX_PATH]{}; GetModuleFileNameW(nullptr, exeYol, MAX_PATH); const std::wstring logYol = std::filesystem::path(exeYol).replace_filename(L"senaryo.log").wstring(); FILE* lf; _wfreopen_s(&lf, logYol.c_str(), L"w", stdout); // BILGI/UYARI → dosya _dup2(_fileno(stdout), _fileno(stderr)); // HATA/[perf] aynı fd → sıralı, kayıpsız setvbuf(stdout, nullptr, _IONBF, 0); // abort öncesi tampon kaybı olmasın setvbuf(stderr, nullptr, _IONBF, 0); } } else { // NORMAL GUI çalıştırma: gunluk (hata/uyarı/[perf]) aksi halde HİÇBİR yere gitmiyordu — // kullanıcı "hata veriyor/yavaş" dediğinde kanıt yoktu. Exe yanına fikocad.log yaz // (her açılışta taze; senaryo.log kalıbının aynısı — kanıtlı freopen+dup2 akışı). wchar_t exeYol[MAX_PATH]{}; GetModuleFileNameW(nullptr, exeYol, MAX_PATH); const std::wstring logYol = std::filesystem::path(exeYol).replace_filename(L"fikocad.log").wstring(); // _SH_DENYNO: uygulama açıkken de log OKUNABİLİR (canlı teşhis). GUI'de stdout GEÇERSİZ // olabildiğinden (_dup2 sessiz başarısız → 0 bayt log yaşandı) günlük DOĞRUDAN bu FILE*'a // yönlendirilir (gunluk::cikisAta) — stdout'a hiç bel bağlanmaz. if (FILE* lf = _wfsopen(logYol.c_str(), L"w", _SH_DENYNO)) { setvbuf(lf, nullptr, _IONBF, 0); // çökme öncesi tampon kaybı olmasın fiko::gunluk::cikisAta(lf); } } #ifdef FIKO_CEF // GPU-hızlandırma (shared texture OSR) bu CEF 150 build'inde/GPU'da ÇALIŞMIYOR (ölçüldü // 07-17: shared_texture=1 → hiç paint). Software OSR sabitlendi — altyapı kodda duruyor // (DinamikDoku d3d yolu, OnAcceleratedPaint) ama devre dışı; CEF/sürücü destekleyince // yardimCefGpuHizliAyarla(true) ile geri açılabilir. fiko::yardimCefGpuHizliAyarla(false); fiko::yardimCefBaslat(hInst); // CefInitialize (ana süreç; multi-threaded UI loop) #endif // MSAA anti-alias seviyesi: render pass + sahne pipeline'ları VulkanAygit ctor'unda // (calistir → BelgePenceresi → VulkanBaglam üye ilklendirme) SABİTLENİR — o an henüz // AyarSistemi kurulu/yüklü değildir. Bu yüzden kalıcı ayar burada, ham depodan // ("ayar.render.msaa_ornek" — bkz. ayar_kayitlari.cpp degisti köprüsü) erken okunur. // Ayarlar penceresindeki "Anti-alias (MSAA)" seçeneği aynı anahtarı yazar; değişiklik // yalnız yeniden başlatmada etkir (bkz. VulkanAygit::msaaOrnekSayisi belge notu). { const std::string msaa = fiko::ayarOku("ayar.render.msaa_ornek", "4x"); int ornek = 1; if (msaa == "2x") ornek = 2; else if (msaa == "4x") ornek = 4; else if (msaa == "8x") ornek = 8; fiko::VulkanAygit::msaaOrnekSayisi() = (VkSampleCountFlagBits)ornek; } int kod; try { kod = fiko::calistir(otoTestKare, senaryoDokum); } catch (const std::exception& e) { FILE* f = nullptr; _wfopen_s(&f, cokmeLogYolu().c_str(), L"w"); if (f) { fprintf(f, "FikoCad cokme (C++ istisnasi)\nwhat: %s\nteshis: %s\n", e.what(), fiko::gunluk::g_teshisAdim ? fiko::gunluk::g_teshisAdim : "?"); fclose(f); } kod = 3; } #ifdef FIKO_CEF fiko::yardimCefBitir(); // CefShutdown (tüm pencereler kapandıktan sonra) #endif return kod; }