Ini bukan topik hangat, tapi saya memiliki kelas pabrik yang memungkinkan dll untuk membuat instance dan mengembalikannya sebagai DLL. Ini adalah apa yang saya cari tetapi tidak dapat menemukan dengan tepat.
Ini disebut seperti,
IHTTP_Server *server = SN::SN_Factory<IHTTP_Server>::CreateObject();
IHTTP_Server *server2 =
SN::SN_Factory<IHTTP_Server>::CreateObject(IHTTP_Server_special_entry);
di mana IHTTP_Server adalah antarmuka virtual murni untuk kelas yang dibuat baik di DLL lain, atau yang sama.
DEFINE_INTERFACE digunakan untuk memberikan sebuah antarmuka id kelas. Tempatkan di dalam antarmuka;
Kelas antarmuka terlihat seperti,
class IMyInterface
{
DEFINE_INTERFACE(IMyInterface);
public:
virtual ~IMyInterface() {};
virtual void MyMethod1() = 0;
...
};
File header seperti ini
#if !defined(SN_FACTORY_H_INCLUDED)
#define SN_FACTORY_H_INCLUDED
#pragma once
Pustaka dicantumkan dalam definisi makro ini. Satu baris per perpustakaan / dapat dieksekusi. Akan keren jika kita bisa memanggil executable lain.
#define SN_APPLY_LIBRARIES(L, A) \
L(A, sn, "sn.dll") \
L(A, http_server_lib, "http_server_lib.dll") \
L(A, http_server, "")
Kemudian untuk setiap dll / exe Anda menentukan makro dan mencantumkan implementasinya. Def berarti itu adalah implementasi default untuk antarmuka. Jika bukan default, Anda memberi nama untuk antarmuka yang digunakan untuk mengidentifikasinya. Yaitu khusus, dan namanya adalah IHTTP_Server_special_entry.
#define SN_APPLY_ENTRYPOINTS_sn(M) \
M(IHTTP_Handler, SNI::SNI_HTTP_Handler, sn, def) \
M(IHTTP_Handler, SNI::SNI_HTTP_Handler, sn, special)
#define SN_APPLY_ENTRYPOINTS_http_server_lib(M) \
M(IHTTP_Server, HTTP::server::server, http_server_lib, def)
#define SN_APPLY_ENTRYPOINTS_http_server(M)
Dengan perpustakaan semua pengaturan, file header menggunakan definisi makro untuk menentukan yang diperlukan.
#define APPLY_ENTRY(A, N, L) \
SN_APPLY_ENTRYPOINTS_##N(A)
#define DEFINE_INTERFACE(I) \
public: \
static const long Id = SN::I##_def_entry; \
private:
namespace SN
{
#define DEFINE_LIBRARY_ENUM(A, N, L) \
N##_library,
Ini menciptakan enum untuk perpustakaan.
enum LibraryValues
{
SN_APPLY_LIBRARIES(DEFINE_LIBRARY_ENUM, "")
LastLibrary
};
#define DEFINE_ENTRY_ENUM(I, C, L, D) \
I##_##D##_entry,
Ini membuat enum untuk implementasi antarmuka.
enum EntryValues
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_ENUM)
LastEntry
};
long CallEntryPoint(long id, long interfaceId);
Ini mendefinisikan kelas pabrik. Tidak banyak di sini.
template <class I>
class SN_Factory
{
public:
SN_Factory()
{
}
static I *CreateObject(long id = I::Id )
{
return (I *)CallEntryPoint(id, I::Id);
}
};
}
#endif
Maka CPPnya adalah,
#include "sn_factory.h"
#include <windows.h>
Buat titik masuk eksternal. Anda dapat memeriksa apakah itu ada menggunakan depend.exe.
extern "C"
{
__declspec(dllexport) long entrypoint(long id)
{
#define CREATE_OBJECT(I, C, L, D) \
case SN::I##_##D##_entry: return (int) new C();
switch (id)
{
SN_APPLY_CURRENT_LIBRARY(APPLY_ENTRY, CREATE_OBJECT)
case -1:
default:
return 0;
}
}
}
Makro menyiapkan semua data yang dibutuhkan.
namespace SN
{
bool loaded = false;
char * libraryPathArray[SN::LastLibrary];
#define DEFINE_LIBRARY_PATH(A, N, L) \
libraryPathArray[N##_library] = L;
static void LoadLibraryPaths()
{
SN_APPLY_LIBRARIES(DEFINE_LIBRARY_PATH, "")
}
typedef long(*f_entrypoint)(long id);
f_entrypoint libraryFunctionArray[LastLibrary - 1];
void InitlibraryFunctionArray()
{
for (long j = 0; j < LastLibrary; j++)
{
libraryFunctionArray[j] = 0;
}
#define DEFAULT_LIBRARY_ENTRY(A, N, L) \
libraryFunctionArray[N##_library] = &entrypoint;
SN_APPLY_CURRENT_LIBRARY(DEFAULT_LIBRARY_ENTRY, "")
}
enum SN::LibraryValues libraryForEntryPointArray[SN::LastEntry];
#define DEFINE_ENTRY_POINT_LIBRARY(I, C, L, D) \
libraryForEntryPointArray[I##_##D##_entry] = L##_library;
void LoadLibraryForEntryPointArray()
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_POINT_LIBRARY)
}
enum SN::EntryValues defaultEntryArray[SN::LastEntry];
#define DEFINE_ENTRY_DEFAULT(I, C, L, D) \
defaultEntryArray[I##_##D##_entry] = I##_def_entry;
void LoadDefaultEntries()
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_DEFAULT)
}
void Initialize()
{
if (!loaded)
{
loaded = true;
LoadLibraryPaths();
InitlibraryFunctionArray();
LoadLibraryForEntryPointArray();
LoadDefaultEntries();
}
}
long CallEntryPoint(long id, long interfaceId)
{
Initialize();
enum SN::LibraryValues l = libraryForEntryPointArray[id];
f_entrypoint f = libraryFunctionArray[l];
if (!f)
{
HINSTANCE hGetProcIDDLL = LoadLibraryA(libraryPathArray[l]);
if (!hGetProcIDDLL) {
return NULL;
}
f = (f_entrypoint)GetProcAddress(hGetProcIDDLL, "entrypoint");
if (!f) {
return NULL;
}
libraryFunctionArray[l] = f;
}
return f(id);
}
}
Setiap perpustakaan menyertakan "cpp" ini dengan cpp rintisan untuk setiap perpustakaan / yang dapat dieksekusi. Semua hal header terkompilasi tertentu.
#include "sn_pch.h"
Siapkan perpustakaan ini.
#define SN_APPLY_CURRENT_LIBRARY(L, A) \
L(A, sn, "sn.dll")
Termasuk untuk cpp utama. Saya kira cpp ini bisa jadi .h. Tetapi ada berbagai cara untuk melakukan ini. Pendekatan ini berhasil untuk saya.
#include "../inc/sn_factory.cpp"