Porting COM ke Linux

Saya suka teknologi COM. Tapi kami tidak akan berbicara tentang teknologi, pujian atau kekurangan COM, tetapi pengalaman porting dan implementasi di Linux. Sepeda? Kemanfaatan? Jangan fokus pada ini.


Objek COM (1)

Secara umum, objek kelas yang mengimplementasikan setidaknya satu antarmuka COM. Implementasi objek terutama tersembunyi di perpustakaan yang terhubung secara dinamis yang disebut COM server (2) , antarmuka diterbitkan dan didistribusikan untuk digunakan.


Antarmuka COM, kelas abstrak yang hanya berisi fungsi virtual murni. Antarmuka IUnknown khusus disorot, objek COM apa pun harus mengimplementasikan antarmuka ini.


Setiap antarmuka COM harus mengandung pengenalnya sendiri. Dalam COM, ditentukan oleh struktur GUID dan di sini kita akan menghadapi kelemahan pertama COM. GUID tidak bisa dipahami dan tidak bisa dibaca dengan baik, dan semua yang dijelaskan di Wiki. Kita membutuhkannya sama, tetapi dengan cara yang lebih mudah dibaca dan dimengerti (sebut saja uiid).


IUnknown dan uiid

#define define_uiid(name) \ inline static const std::string& guid() { const static std::string idn(dom_guid_pre_name #name); return idn; } namespace Dom { using uiid = std::string; using clsuid= std::string; struct IUnknown { virtual long AddRef() = 0; virtual long Release() = 0; virtual bool QueryInterface(const uiid&, void **ppv) = 0; define_uiid(Unknown) }; } 

Selain pengenal antarmuka, pengidentifikasi kelas (clsuid), yang diperlukan untuk membuat objek, juga dialokasikan. Dalam kasus kami, karena ini adalah pengenal yang kurang mudah dibaca yang dapat menentukan esensi, Anda dapat melupakan publikasi mereka untuk saat ini (mungkin ini tidak baik).


Ringkasan
Objek COM yang berisi pengidentifikasi kelas tunggal. Ini mengimplementasikan setidaknya satu antarmuka COM - IUnknown (setiap antarmuka COM memiliki pengidentifikasi antarmuka yang unik). Implementasi yang berbeda dari objek COM dapat memiliki pengidentifikasi kelas yang sama (contoh: rilis dan versi debug).



Server COM (2)

Pustaka yang terhubung secara dinamis (untuk Linux itu adalah objek Bersama - jadi) yang mengimplementasikan setidaknya satu objek COM. Server harus mengekspor serangkaian fungsi tertentu:


 extern "C" bool DllCreateInstance(const uiid& iid, void** ppv) 
Membuat objek kelas dengan clsuid, menambah jumlah referensi, setiap kali objek berhasil dibuat. Panggilan ke IUnknown :: AddRef juga harus meningkatkan jumlah referensi untuk itu, dan IUnknown :: Rilis harus berkurang.

 extern "C" bool DllCanUnloadNow() 

Jika jumlah referensi ke SO adalah 0, maka Anda dapat membongkar pustaka.

 extern "C" bool DllRegisterServer(IUnknown* unknown) 

Mendaftarkan semua server clsuid di "registri". Disebut sekali selama instalasi server COM.

 extern "C" bool DllUnRegisterServer(IUnknown* unknown) 

Menghapus entri "registri" tentang server clsuid terdaftar. Disebut sekali ketika mencopot server COM.

Contoh SimpleHello, nyatakan antarmuka IHello:

 struct IHello : public virtual Dom::IUnknown { virtual void Print() = 0; define_uiid(Hello) }; 

Implementasi antarmuka:

 /* COM- */ class SimpleHello : public Dom::Implement<SimpleHello, IHello> { public: SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); } ~SimpleHello() { printf("%s\n", __PRETTY_FUNCTION__); } virtual void Print() { printf("Hello from %s\n",__PRETTY_FUNCTION__); } define_clsuid(SimpleHello) }; /* COM- */ namespace Dom { DOM_SERVER_EXPORT_BEGIN EXPORT_CLASS(SimpleHello) DOM_SERVER_EXPORT_END DOM_SERVER_INSTALL(IUnknown* unknown) { Interface<IRegistryServer> registry; if (unknown->QueryInterface(IRegistryServer::guid(), registry)) { //      } return true; } DOM_SERVER_UNINSTALL(IUnknown* unknown) { Interface<IRegistryServer> registry; if (unknown->QueryInterface(IRegistryServer::guid(), registry)) { //      } return true; } } 

Satu set makro menyembunyikan implementasi fungsi dengan memberikan deklarasi dan logika yang lebih terstruktur.


Dom :: Implement <SimpleHello, IHello> - menyembunyikan implementasi metode antarmuka IUnknown, menambahkan "gula" saat mendeklarasikan antarmuka yang diimplementasikan oleh objek (C ++ 11 dan templat variadik):



 template <typename T, typename ... IFACES> struct Implement : virtual public IUnknown, virtual public IFACES… { ... }; 

IRegistryServer interface - mendefinisikan seperangkat metode untuk bekerja dengan "registri" dari server COM.


β€œDaftar” dari COM-server (3)

Pentingnya registri dapat diremehkan, tetapi mungkin merupakan pilar utama COM. Microsoft menulis ke registri, membuat struktur yang rumit untuk menggambarkan antarmuka dan atributnya (idl), saya pergi dengan cara yang sedikit berbeda.


Dalam implementasinya, registri didasarkan pada sistem file.
Roti jenis apa? Pemahaman, kesederhanaan, kemungkinan pemulihan, roti khusus saat mendaftar server, Anda dapat mengatur beberapa jenis namespace (direktori relatif ke basis registri di mana objek server akan terdaftar), dengan demikian Anda dapat menerapkan integritas dan versi aplikasi menggunakan teknologi.


Dari kekurangan, kemungkinan masalah keamanan, penggantian implementasi objek.


Bagaimana cara menggunakan, contoh aplikasi (4)

Untuk membuat semuanya berfungsi, Anda akan membutuhkan "perpustakaan" kecil dan "program" kecil.


"Perpustakaan" tidak lebih dari pembungkus yang mengimplementasikan dan mengumpulkan semuanya menjadi satu kesatuan, bekerja dengan registri, memuat / membongkar SO, membuat objek.
Ini adalah satu-satunya yang harus ditentukan saat membangun aplikasi. Yang lainnya, "Aku ingin percaya," dia akan melakukannya sendiri.


" Programka " - regsrv sebenarnya adalah analog dari program Microsoft RegSrv32 yang melakukan tindakan yang sama (+ kemampuan untuk menentukan namespace, + kemampuan untuk mendapatkan daftar clsuid terdaftar dan server COM).



sampel

 #include "../include/dom.h" #include "../../skel/ihello.h" int main() { Dom::Interface<Dom::IUnknown> unkwn; Dom::Interface<IHello> hello; if (Dom::CreateInstance(Dom::clsid("SimpleHello"), unkwn)) { unkwn->QueryInterface(IHello::guid(), hello); hello->Print(); } else { printf("[WARNING] Class `SimpleHello` not register.\nFirst execute command\n\tregsrv <fullpath>/libskel.so\n... and try again."); } return 0; } 

Dom (5)

Dom (Dynamic Object Model), implementasi saya untuk Linux.

git klon


Terima kasih

Source: https://habr.com/ru/post/id427919/


All Articles