#include "com/fikom_sunucu.hpp" #include namespace fikatia { namespace { // Fikatia.Sistem sinif kimligi (sabit — kayit ve istemciler buna baglanir) const CLSID SINIF_KIMLIK = {0xb7e4a3d1, 0x9c52, 0x4f8e, {0xa1, 0xb6, 0x3d, 0x74, 0xc2, 0xe8, 0x5f, 0x19}}; const wchar_t* PROG_ID = L"Fikatia.Sistem"; const wchar_t* ACIKLAMA = L"Fikatia COM Sunucusu"; std::vector& tablo() { static std::vector t; return t; } int g_istemciSayisi = 0; std::function g_istemciKanca; // ---- Otomasyon nesnesi: elle IDispatch (typelib yok — late binding, win32com gibi) ---- class SunucuNesne : public IDispatch { public: // sayilir: yalniz factory (CreateObject) ornekleri istemci sayilir; ROT'taki // aktif nesne surec boyunca yasar, sayilmaz. explicit SunucuNesne(bool sayilir = false) : sayilir_(sayilir) { if (sayilir_) { ++g_istemciSayisi; if (g_istemciKanca) g_istemciKanca(true, g_istemciSayisi); } } ~SunucuNesne() { if (sayilir_) { --g_istemciSayisi; if (g_istemciKanca) g_istemciKanca(false, g_istemciSayisi); } } // IUnknown HRESULT __stdcall QueryInterface(REFIID iid, void** cikti) override { if (!cikti) return E_POINTER; if (iid == IID_IUnknown || iid == IID_IDispatch) { *cikti = static_cast(this); AddRef(); return S_OK; } *cikti = nullptr; return E_NOINTERFACE; } ULONG __stdcall AddRef() override { return (ULONG)InterlockedIncrement(&ref_); } ULONG __stdcall Release() override { const LONG n = InterlockedDecrement(&ref_); if (n == 0) delete this; return (ULONG)n; } // IDispatch HRESULT __stdcall GetTypeInfoCount(UINT* adet) override { if (adet) *adet = 0; return S_OK; } HRESULT __stdcall GetTypeInfo(UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; } HRESULT __stdcall GetIDsOfNames(REFIID, LPOLESTR* adlar, UINT adet, LCID, DISPID* kimlikler) override { if (!adlar || !kimlikler) return E_POINTER; HRESULT sonuc = S_OK; for (UINT i = 0; i < adet; ++i) { kimlikler[i] = DISPID_UNKNOWN; if (i == 0) { const auto& t = tablo(); for (size_t k = 0; k < t.size(); ++k) { if (_wcsicmp(t[k].ad.c_str(), adlar[0]) == 0) { kimlikler[0] = (DISPID)(k + 1); break; } } } if (kimlikler[i] == DISPID_UNKNOWN) sonuc = DISP_E_UNKNOWNNAME; } return sonuc; } HRESULT __stdcall Invoke(DISPID kimlik, REFIID, LCID, WORD bayrak, DISPPARAMS* prm, VARIANT* donus, EXCEPINFO*, UINT*) override { if (!(bayrak & (DISPATCH_METHOD | DISPATCH_PROPERTYGET))) return DISP_E_MEMBERNOTFOUND; const auto& t = tablo(); if (kimlik < 1 || (size_t)kimlik > t.size()) return DISP_E_MEMBERNOTFOUND; if (prm && prm->cNamedArgs > 0) return DISP_E_NONAMEDARGS; // Invoke argumanlari TERS sirada gelir — isleyiciye normal sirada ver. std::vector<_variant_t> args; if (prm && prm->cArgs > 0) { args.reserve(prm->cArgs); for (UINT i = prm->cArgs; i > 0; --i) args.emplace_back(prm->rgvarg[i - 1]); } _variant_t sonuc; const HRESULT hr = t[(size_t)kimlik - 1].isle(args, sonuc); if (SUCCEEDED(hr) && donus) { VariantInit(donus); return VariantCopy(donus, sonuc.GetAddress()); } return hr; } private: LONG ref_ = 1; bool sayilir_ = false; }; // ---- Class factory ---- class SunucuFabrika : public IClassFactory { public: HRESULT __stdcall QueryInterface(REFIID iid, void** cikti) override { if (!cikti) return E_POINTER; if (iid == IID_IUnknown || iid == IID_IClassFactory) { *cikti = static_cast(this); return S_OK; } *cikti = nullptr; return E_NOINTERFACE; } // Statik omur: surec yasadikca yasar ULONG __stdcall AddRef() override { return 2; } ULONG __stdcall Release() override { return 1; } HRESULT __stdcall CreateInstance(IUnknown* dis, REFIID iid, void** cikti) override { if (dis) return CLASS_E_NOAGGREGATION; SunucuNesne* n = new SunucuNesne(true); const HRESULT hr = n->QueryInterface(iid, cikti); n->Release(); return hr; } HRESULT __stdcall LockServer(BOOL) override { return S_OK; } }; SunucuFabrika g_fabrika; DWORD g_fabrikaKayit = 0; DWORD g_aktifKayit = 0; SunucuNesne* g_aktifNesne = nullptr; bool anahtarYaz(const std::wstring& yol, const wchar_t* deger) { HKEY anahtar = nullptr; if (RegCreateKeyExW(HKEY_CURRENT_USER, yol.c_str(), 0, nullptr, 0, KEY_WRITE, nullptr, &anahtar, nullptr) != ERROR_SUCCESS) return false; const LSTATUS s = RegSetValueExW(anahtar, nullptr, 0, REG_SZ, (const BYTE*)deger, (DWORD)((wcslen(deger) + 1) * sizeof(wchar_t))); RegCloseKey(anahtar); return s == ERROR_SUCCESS; } std::wstring clsidMetin() { wchar_t m[64]{}; StringFromGUID2(SINIF_KIMLIK, m, 64); return m; } } // namespace void sunucuMetodEkle(SunucuMetod m) { tablo().push_back(std::move(m)); } bool sunucuKayitYaz() { wchar_t exeYol[MAX_PATH]{}; GetModuleFileNameW(nullptr, exeYol, MAX_PATH); const std::wstring clsid = clsidMetin(); const std::wstring kok = L"Software\\Classes\\"; const std::wstring sunucu = L"\"" + std::wstring(exeYol) + L"\" -Embedding"; bool ok = true; ok &= anahtarYaz(kok + PROG_ID, ACIKLAMA); ok &= anahtarYaz(kok + PROG_ID + L"\\CLSID", clsid.c_str()); ok &= anahtarYaz(kok + L"CLSID\\" + clsid, ACIKLAMA); ok &= anahtarYaz(kok + L"CLSID\\" + clsid + L"\\LocalServer32", sunucu.c_str()); ok &= anahtarYaz(kok + L"CLSID\\" + clsid + L"\\ProgID", PROG_ID); return ok; } bool sunucuKayitSil() { const std::wstring kok = L"Software\\Classes\\"; const std::wstring clsid = clsidMetin(); bool ok = true; ok &= RegDeleteTreeW(HKEY_CURRENT_USER, (kok + PROG_ID).c_str()) == ERROR_SUCCESS; ok &= RegDeleteTreeW(HKEY_CURRENT_USER, (kok + L"CLSID\\" + clsid).c_str()) == ERROR_SUCCESS; return ok; } bool sunucuBaslat() { if (g_fabrikaKayit) return true; HRESULT hr = CoRegisterClassObject(SINIF_KIMLIK, &g_fabrika, CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE, &g_fabrikaKayit); if (FAILED(hr)) return false; // GetObject(,"Fikatia.Sistem") calissin diye calisan ornegi ROT'a da yaz. g_aktifNesne = new SunucuNesne(); RegisterActiveObject(g_aktifNesne, SINIF_KIMLIK, ACTIVEOBJECT_WEAK, &g_aktifKayit); return true; } void sunucuDurdur() { if (g_aktifKayit) { RevokeActiveObject(g_aktifKayit, nullptr); g_aktifKayit = 0; } if (g_aktifNesne) { g_aktifNesne->Release(); g_aktifNesne = nullptr; } if (g_fabrikaKayit) { CoRevokeClassObject(g_fabrikaKayit); g_fabrikaKayit = 0; } } int sunucuIstemciSayisi() { return g_istemciSayisi; } void sunucuIstemciKancasi(std::function kanca) { g_istemciKanca = std::move(kanca); } } // namespace fikatia