Đây không hẳn là một chủ đề nóng, nhưng tôi có một lớp nhà máy cho phép một dll tạo một thể hiện và trả về nó dưới dạng một DLL. Đó là những gì tôi đã tìm kiếm nhưng không thể tìm thấy chính xác.
Nó được gọi là,
IHTTP_Server *server = SN::SN_Factory<IHTTP_Server>::CreateObject();
IHTTP_Server *server2 =
SN::SN_Factory<IHTTP_Server>::CreateObject(IHTTP_Server_special_entry);
trong đó IHTTP_Server là giao diện ảo thuần túy cho một lớp được tạo trong một DLL khác hoặc cùng một lớp.
DEFINE_INTERFACE được sử dụng để cung cấp giao diện id lớp. Đặt giao diện bên trong;
Một lớp giao diện trông giống như,
class IMyInterface
{
DEFINE_INTERFACE(IMyInterface);
public:
virtual ~IMyInterface() {};
virtual void MyMethod1() = 0;
...
};
Tệp tiêu đề giống như thế này
#if !defined(SN_FACTORY_H_INCLUDED)
#define SN_FACTORY_H_INCLUDED
#pragma once
Các thư viện được liệt kê trong định nghĩa macro này. Một dòng cho mỗi thư viện / tệp thực thi. Sẽ rất tuyệt nếu chúng ta có thể gọi vào một tệp thực thi khác.
#define SN_APPLY_LIBRARIES(L, A) \
L(A, sn, "sn.dll") \
L(A, http_server_lib, "http_server_lib.dll") \
L(A, http_server, "")
Sau đó, đối với mỗi dll / exe, bạn xác định một macro và liệt kê các triển khai của nó. Def có nghĩa là nó là cài đặt mặc định cho giao diện. Nếu nó không phải là mặc định, bạn đặt tên cho giao diện được sử dụng để xác định nó. Tức là, đặc biệt và tên sẽ là 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)
Với tất cả các thư viện được thiết lập, tệp tiêu đề sử dụng các định nghĩa macro để xác định những thứ cần thiết.
#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,
Điều này tạo ra một enum cho các thư viện.
enum LibraryValues
{
SN_APPLY_LIBRARIES(DEFINE_LIBRARY_ENUM, "")
LastLibrary
};
#define DEFINE_ENTRY_ENUM(I, C, L, D) \
I##_##D##_entry,
Điều này tạo ra một enum cho việc triển khai giao diện.
enum EntryValues
{
SN_APPLY_LIBRARIES(APPLY_ENTRY, DEFINE_ENTRY_ENUM)
LastEntry
};
long CallEntryPoint(long id, long interfaceId);
Điều này xác định lớp nhà máy. Không nhiều về nó ở đây.
template <class I>
class SN_Factory
{
public:
SN_Factory()
{
}
static I *CreateObject(long id = I::Id )
{
return (I *)CallEntryPoint(id, I::Id);
}
};
}
#endif
Sau đó, CPP là,
#include "sn_factory.h"
#include <windows.h>
Tạo điểm vào bên ngoài. Bạn có thể kiểm tra xem nó có tồn tại hay không bằng cách sử dụng 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;
}
}
}
Các macro thiết lập tất cả dữ liệu cần thiết.
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);
}
}
Mỗi thư viện bao gồm "cpp" này với một cpp sơ khai cho mỗi thư viện / tệp thực thi. Bất kỳ nội dung tiêu đề được biên dịch cụ thể nào.
#include "sn_pch.h"
Thiết lập thư viện này.
#define SN_APPLY_CURRENT_LIBRARY(L, A) \
L(A, sn, "sn.dll")
Một bao gồm cho cpp chính. Tôi đoán cpp này có thể là một .h. Nhưng có nhiều cách khác nhau để bạn có thể làm điều này. Cách tiếp cận này đã làm việc cho tôi.
#include "../inc/sn_factory.cpp"