#include "fiko/eklenti/eklenti_yonetici.hpp" #include #include #include "fiko/core/gunluk.hpp" namespace fiko::eklenti { namespace { std::wstring genislet(const std::string& s) { if (s.empty()) return {}; const int n = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), nullptr, 0); std::wstring w(n, 0); MultiByteToWideChar(CP_UTF8, 0, s.c_str(), (int)s.size(), w.data(), n); return w; } std::string daralt(const std::wstring& w) { if (w.empty()) return {}; const int n = WideCharToMultiByte(CP_UTF8, 0, w.c_str(), (int)w.size(), nullptr, 0, nullptr, nullptr); std::string s(n, 0); WideCharToMultiByte(CP_UTF8, 0, w.c_str(), (int)w.size(), s.data(), n, nullptr, nullptr); return s; } } // namespace EklentiYonetici::~EklentiYonetici() { while (!kayitlar_.empty()) kaldir(kayitlar_.size() - 1); } size_t EklentiYonetici::tara(const std::string& dizin) { namespace fs = std::filesystem; size_t sayi = 0; std::error_code ec; for (const auto& giris : fs::directory_iterator(fs::path(genislet(dizin)), ec)) { if (!giris.is_regular_file(ec)) continue; if (giris.path().extension() != L".dll") continue; if (yukle(daralt(giris.path().wstring()))) ++sayi; } return sayi; } bool EklentiYonetici::yukle(const std::string& dllYolu) { namespace fs = std::filesystem; // Aynı DLL zaten yüklüyse tekrar yükleme (menü/araç komutlarının çift kaydını // ve DLL referans sayacı sızıntısını önler; "Dizini Tara" idempotent olur). const std::wstring dosyaAd = fs::path(genislet(dllYolu)).filename().wstring(); for (const EklentiKayit& k : kayitlar_) { if (fs::path(genislet(k.yol)).filename().wstring() == dosyaAd) return false; } const HMODULE m = LoadLibraryW(genislet(dllYolu).c_str()); if (!m) { sonHata_ = "DLL yüklenemedi: " + dllYolu; gunluk::hata("{}", sonHata_); return false; } using SurumFn = unsigned (*)(); using OlusturFn = Eklenti* (*)(); using YokEtFn = void (*)(Eklenti*); const auto surum = reinterpret_cast( reinterpret_cast(GetProcAddress(m, "fikoEklentiApiSurum"))); const auto olustur = reinterpret_cast( reinterpret_cast(GetProcAddress(m, "fikoEklentiOlustur"))); const auto yokEt = reinterpret_cast( reinterpret_cast(GetProcAddress(m, "fikoEklentiYokEt"))); if (!surum || !olustur || !yokEt) { sonHata_ = "Eklenti export'ları eksik: " + dllYolu; gunluk::hata("{}", sonHata_); FreeLibrary(m); return false; } const unsigned api = surum(); if (api != EKLENTI_API_SURUM) { sonHata_ = "Eklenti API sürümü uyumsuz (" + std::to_string(api) + " != " + std::to_string(EKLENTI_API_SURUM) + "): " + dllYolu; gunluk::hata("{}", sonHata_); FreeLibrary(m); return false; } Eklenti* e = olustur(); if (!e || !e->baslat(baglam_)) { sonHata_ = "Eklenti başlatılamadı: " + dllYolu; gunluk::hata("{}", sonHata_); if (e) yokEt(e); FreeLibrary(m); return false; } EklentiKayit k; k.bilgi = e->bilgi(); k.yol = dllYolu; k.etkin = true; k.modul = m; k.ornek = e; k.yokEt = yokEt; gunluk::bilgi("Eklenti yüklendi: {} {} ({})", k.bilgi.ad, k.bilgi.surum, dllYolu); kayitlar_.push_back(std::move(k)); return true; } bool EklentiYonetici::kaldir(size_t indeks) { if (indeks >= kayitlar_.size()) return false; EklentiKayit k = std::move(kayitlar_[indeks]); kayitlar_.erase(kayitlar_.begin() + static_cast(indeks)); if (k.ornek) { k.ornek->kapat(baglam_); if (k.yokEt) k.yokEt(k.ornek); } if (k.modul) FreeLibrary(static_cast(k.modul)); gunluk::bilgi("Eklenti kaldırıldı: {}", k.yol); return true; } void EklentiYonetici::kareGuncelle(f32 dt) { for (auto& k : kayitlar_) { if (k.etkin && k.ornek) k.ornek->kareGuncelle(baglam_, dt); } } } // namespace fiko::eklenti