Bu tam olarak sıcak bir konu değil, ancak bir dll'nin bir örnek oluşturmasına ve onu DLL olarak döndürmesine izin veren bir fabrika sınıfım var. Aradığım şeydi ama tam olarak bulamadım.
Gibi denir,
IHTTP_Server *server = SN::SN_Factory<IHTTP_Server>::CreateObject();
IHTTP_Server *server2 =
SN::SN_Factory<IHTTP_Server>::CreateObject(IHTTP_Server_special_entry);
Burada IHTTP_Server, başka bir DLL'de veya aynı DLL'de oluşturulan bir sınıf için saf sanal arabirimdir.
DEFINE_INTERFACE, bir sınıf kimliğine bir arabirim vermek için kullanılır. Arayüzün içine yerleştirin;
Bir arayüz sınıfı şuna benzer:
class IMyInterface
{
DEFINE_INTERFACE(IMyInterface);
public:
virtual ~IMyInterface() {};
virtual void MyMethod1() = 0;
...
};
Başlık dosyası şöyle
#if !defined(SN_FACTORY_H_INCLUDED)
#define SN_FACTORY_H_INCLUDED
#pragma once
Kitaplıklar bu makro tanımında listelenmiştir. Kitaplık / çalıştırılabilir dosya başına bir satır. Başka bir çalıştırılabilir dosyayı çağırabilirsek harika olurdu.
#define SN_APPLY_LIBRARIES(L, A) \
L(A, sn, "sn.dll") \
L(A, http_server_lib, "http_server_lib.dll") \
L(A, http_server, "")
Daha sonra her dll / exe için bir makro tanımlar ve uygulamalarını listelersiniz. Def, arayüz için varsayılan uygulama olduğu anlamına gelir. Varsayılan değilse, onu tanımlamak için kullanılan arabirime bir ad verirsiniz. Yani, özel ve ad IHTTP_Server_special_entry olacaktır.
#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)
Kütüphanelerin tüm kurulumuyla, başlık dosyası gerekli olanı tanımlamak için makro tanımlarını kullanır.
#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,
Bu, kütüphaneler için bir enum oluşturur.
enum LibraryValues
{
SN_APPLY_LIBRARIES(DEFINE_LIBRARY_ENUM, "")
LastLibrary
};
#define DEFINE_ENTRY_ENUM(I, C, L, D) \
I##_##D##_entry,
Bu, arabirim uygulamaları için bir enum oluşturur.
enum EntryValues
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_ENUM)
LastEntry
};
long CallEntryPoint(long id, long interfaceId);
Bu, fabrika sınıfını tanımlar. Burada pek yok.
template <class I>
class SN_Factory
{
public:
SN_Factory()
{
}
static I *CreateObject(long id = I::Id )
{
return (I *)CallEntryPoint(id, I::Id);
}
};
}
#endif
O zaman CPP,
#include "sn_factory.h"
#include <windows.h>
Harici giriş noktasını oluşturun. Falls.exe kullanarak var olup olmadığını kontrol edebilirsiniz.
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;
}
}
}
Makrolar, ihtiyaç duyulan tüm verileri ayarlar.
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);
}
}
Her kitaplık, her kitaplık / çalıştırılabilir dosya için bir stub cpp ile bu "cpp" yi içerir. Herhangi bir özel derlenmiş başlık malzemesi.
#include "sn_pch.h"
Bu kitaplığı kurun.
#define SN_APPLY_CURRENT_LIBRARY(L, A) \
L(A, sn, "sn.dll")
Ana cpp için bir dahil. Sanırım bu cpp bir .h olabilir. Ancak bunu yapmanın farklı yolları var. Bu yaklaşım benim için çalıştı.
#include "../inc/sn_factory.cpp"