My Project
PluginLoader.hpp
1 #pragma once
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 2007 - 2010 ParaEngine Corporation, All Rights Reserved.
4 // Author: LiXizhi
5 // Date: 2010.2
6 // Desc: Use this file to load dll, if one wants to link to core lib at runtime.
7 // PE_MODULE_STANDALONE is usually defined with delayed core lib.
8 //-----------------------------------------------------------------------------
9 #include <vector>
10 #include <string>
11 
12 #include <sys/stat.h>
13 #include <sys/types.h>
14 
15 #include "PluginAPI.h"
16 
17 #ifndef OUTPUT_LOG
18 #define OUTPUT_LOG printf
19 #endif
20 namespace ParaEngine
21 {
22  using std::vector;
23  // forward declarations.
24  class ClassDescriptor;
25  class IParaEngineCore;
26 
28  // plug-in library functions to be explicitly imported to the game engine.
29 
31  typedef const char* (*lpFnLibDescription)();
33  typedef unsigned long (*lpFnLibVersion)();
35  typedef int (*lpFnLibNumberClasses)();
37  typedef ClassDescriptor* (*lpFnLibClassDesc)(int i);
39  typedef void (*lpFnLibInit)();
41  typedef void (*lpFnLibInitParaEngine)(IParaEngineCore* pIParaEngineCore);
43  typedef int (*lpFnLibActivate)(int nType, void* pVoid);
44 
45  typedef void (STDCALL *pfnEnsureInit)(void);
46  typedef void (STDCALL *pfnForceTerm)(void);
47 
52  {
53  public:
55  CPluginLoader(const char* filename = NULL)
56  : m_pFuncActivate(NULL), m_hDLL(NULL), m_bIsValid(false), m_bIsInitialized(false)
57  {
58  if(filename)
59  {
60  m_sDllFilePath = filename;
61  }
62  }
63  virtual ~CPluginLoader()
64  {
65  // free the library.
66  if(IsValid())
67  {
68  UnLoad();
69  }
70  }
71 
73  bool IsValid()
74  {
75  return (m_hDLL!=NULL);
76  }
77 
81  const char* GetDLLFilePath()
82  {
83  return m_sDllFilePath.c_str();
84  }
85 
93  {
94  if(IsValid() && i>=0 && i<GetNumberOfClasses())
95  return m_listClassDesc[i];
96  else
97  return NULL;
98  }
99 
105  const char* GetLibDescription()
106  {
107  return m_sLibDescription.c_str();
108  }
109 
114  {
115  return (int)m_listClassDesc.size();
116  }
117 
118 
123  void Init(const char* sFilename)
124  {
125  m_bIsInitialized = true;
126  m_bIsValid = true;
127 
128  if(sFilename)
129  {
130  m_sDllFilePath = sFilename;
131  }
132  string sDLLPath = m_sDllFilePath;
133 
134  // load the library.
135 #ifdef WIN32
136  m_hDLL = (HINSTANCE)LoadLibraryS(sDLLPath.c_str());
137 #else
138  m_hDLL = LoadLibraryS(sDLLPath.c_str(), RTLD_LOCAL | RTLD_LAZY);
139 #endif
140 
141  if (m_hDLL != NULL)
142  {
143 #ifdef WIN32
144  {
145  // see http://support.microsoft.com/default.aspx?scid=kb;en-us;814472
146 
147  // ... initialization code
148  pfnEnsureInit pfnDll= (pfnEnsureInit) GetProcAddressS(m_hDLL, "DllEnsureInit");
149  if(pfnDll!=0)
150  {
151  // Exit, return; there is nothing else to do.
152  pfnDll();
153  }
154  }
155 #endif
156 
157  lpFnLibDescription pLibDescription = (lpFnLibDescription) GetProcAddressS(m_hDLL, "LibDescription");
158 
159  if (pLibDescription != 0)
160  {
161  // call the function
162  m_sLibDescription = pLibDescription();
163  //OUTPUT_LOG("lib desc %s \r\n", m_sLibDescription.c_str());
164  }
165  else
166  {
167 #ifdef WIN32
168  OUTPUT_LOG("failed loading %s : because it does not expose the LibDescription method\r\n", sDLLPath.c_str());
169 #else
170  const char* sErrorMsg = dlerror();
171  if(sErrorMsg == 0)
172  sErrorMsg = "unknown error";
173  OUTPUT_LOG("warning: GetProcAddress( %s ) failed because %s\n", sDLLPath.c_str(), sErrorMsg);
174 #endif
175  // handle the error
176  UnLoad();
177  }
178 
179  lpFnLibVersion pLibVersion = (lpFnLibVersion)GetProcAddressS(m_hDLL, "LibVersion");
180  if (pLibVersion != 0)
181  {
182  // call the function
183  m_nParaEngineVersion = pLibVersion();
184  }
185  else
186  {
187 #ifdef WIN32
188  OUTPUT_LOG("failed loading %s : because it does not expose the LibVersion method\r\n", sDLLPath.c_str());
189 #else
190  const char* sErrorMsg = dlerror();
191  if(sErrorMsg == 0)
192  sErrorMsg = "unknown error";
193  OUTPUT_LOG("warning: GetProcAddress( %s ) failed because %s\n", sDLLPath.c_str(), sErrorMsg);
194 #endif
195  // handle the error
196  UnLoad();
197  }
198  int nClassNum=0;
199 
200  lpFnLibNumberClasses pLibNumberClasses = (lpFnLibNumberClasses)GetProcAddressS(m_hDLL, "LibNumberClasses");
201  if (pLibNumberClasses != 0)
202  {
203  // call the function
204  nClassNum= pLibNumberClasses();
205  //OUTPUT_LOG("lib classes count %d \r\n", nClassNum);
206  m_listClassDesc.reserve(nClassNum);
207  }
208  else
209  {
210 #ifdef WIN32
211  OUTPUT_LOG("failed loading %s : because it does not expose the LibNumberClasses method\r\n", sDLLPath.c_str());
212 #else
213  const char* sErrorMsg = dlerror();
214  if(sErrorMsg == 0)
215  sErrorMsg = "unknown error";
216  OUTPUT_LOG("warning: GetProcAddress( %s ) failed because %s\n", sDLLPath.c_str(), sErrorMsg);
217 #endif
218  // handle the error
219  UnLoad();
220  }
221  lpFnLibClassDesc pLibClassDesc = (lpFnLibClassDesc)GetProcAddressS(m_hDLL, "LibClassDesc");
222  if (pLibDescription != 0)
223  {
224  // call the function
225  for (int i=0; i<nClassNum; ++i)
226  {
227  ClassDescriptor* pClassDesc = pLibClassDesc(i);
228  if(pClassDesc!=0)
229  {
230  m_listClassDesc.push_back(pClassDesc);
231  }
232  else
233  {
234  OUTPUT_LOG("the %d th class in %s is not loaded \r\n", i, sDLLPath.c_str());
235  }
236  }
237  }
238  else
239  {
240 #ifdef WIN32
241  OUTPUT_LOG("failed loading %s : because it does not expose the LibClassDesc method\r\n", sDLLPath.c_str());
242 #else
243  const char* sErrorMsg = dlerror();
244  if(sErrorMsg == 0)
245  sErrorMsg = "unknown error";
246  OUTPUT_LOG("warning: GetProcAddress( %s ) failed because %s\n", sDLLPath.c_str(), sErrorMsg);
247 #endif
248  // handle the error
249  UnLoad();
250  }
251 
252 #ifdef WIN32
253  lpFnLibInit pLibInit = (lpFnLibInit)GetProcAddressS(m_hDLL, "LibInit");
254  if (pLibDescription != 0)
255  {
256  // call the function
257  pLibInit();
258  }
259 #endif
260 
261  m_pFuncActivate = (lpFnLibActivate)GetProcAddressS(m_hDLL, "LibActivate");
262  }
263  else
264  {
265  m_bIsValid = false;
266  }
267 
268  if(IsValid())
269  {
270  // rule of silence, do not pollute std output
271  // OUTPUT_LOG("Plug-in loaded: %s\r\n", sDLLPath.c_str());
272  }
273  else
274  {
275  OUTPUT_LOG("Failed loading plug-in: %s\r\n", sDLLPath.c_str());
276  }
277  }
278 
280  void UnLoad()
281  {
282  if(m_hDLL!=0)
283  {
284 #ifdef WIN32
285  {
286  // see http://support.microsoft.com/default.aspx?scid=kb;en-us;814472
287  pfnForceTerm pfnDll=( pfnForceTerm) GetProcAddressS(m_hDLL, "DllForceTerm");
288  if(pfnDll!=0)
289  {
290  pfnDll();
291  }
292  }
293 #endif
294  FreeLibraryS(m_hDLL);
295  m_hDLL = 0;
296  }
297  m_bIsValid = false;
298  }
299 
307  int Activate(int nType=0, void* pVoid=NULL)
308  {
309  if(IsValid() && m_pFuncActivate!=0)
310  {
311  return m_pFuncActivate(nType, pVoid);
312  }
313  return -1;
314  }
315 
316  /* same as LoadLibrary in windows or dlopen() in linux
317  #define RTLD_LAZY 1
318  #define RTLD_NOW 2
319  #define RTLD_GLOBAL 4
320  */
321  static void* LoadLibraryS(const char *pcDllname, int iMode=2)
322  {
323  std::string sDllName = pcDllname;
324 #ifdef WIN32 // Microsoft compiler
325  if(sDllName.find(".") == string::npos)
326  sDllName += ".dll";
327  return (void*)::LoadLibraryA(pcDllname);
328 #else
329  if(sDllName.find(".") == string::npos)
330  sDllName += ".so";
331  return dlopen(sDllName.c_str(),iMode);
332 #endif
333 
334  }
335  static void * GetProcAddressS(void *Lib, const char *Fnname)
336  {
337 #ifdef WIN32 // Microsoft compiler
338  return (void*)::GetProcAddress((HINSTANCE)Lib,Fnname);
339 #else
340  return dlsym(Lib,Fnname);
341 #endif
342  }
343 
344  static bool FreeLibraryS(void *hDLL)
345  {
346 #ifdef WIN32 // Microsoft compiler
347  return ::FreeLibrary((HINSTANCE)hDLL);
348 #else
349  return dlclose(hDLL);
350 #endif
351  }
352 
353  private:
355  string m_sDllFilePath;
357  vector<ClassDescriptor*> m_listClassDesc;
362  string m_sLibDescription;
368  unsigned long m_nParaEngineVersion;
369 
371  void* m_hDLL;
372 
373  bool m_bIsInitialized;
374 
375  bool m_bIsValid;
376 
378  lpFnLibActivate m_pFuncActivate;
379  };
380 }
ClassDescriptor *(* lpFnLibClassDesc)(int i)
"LibClassDesc": must be implemented in a plug-in.
Definition: PluginLoader.hpp:37
CPluginLoader(const char *filename=NULL)
the dll to load, it does not load it immediately.
Definition: PluginLoader.hpp:55
PE_CORE_DECL void * GetProcAddress(void *Lib, const char *Fnname)
Definition: os_calls.cpp:99
int(* lpFnLibNumberClasses)()
"LibNumberClasses": must be implemented in a plug-in.
Definition: PluginLoader.hpp:35
void(* lpFnLibInitParaEngine)(IParaEngineCore *pIParaEngineCore)
"LibInitParaEngine": this is optional in a plug-in
Definition: PluginLoader.hpp:41
different physics engine has different winding order.
Definition: EventBinding.h:32
a DLL/so plug-in loaded explicitly at runtime.
Definition: PluginLoader.hpp:51
const char * GetDLLFilePath()
Definition: PluginLoader.hpp:81
unsigned long(* lpFnLibVersion)()
"LibVersion": must be implemented in a plug-in.
Definition: PluginLoader.hpp:33
void Init(const char *sFilename)
init the asset entity object.
Definition: PluginLoader.hpp:123
a table of virtual functions which are used by plug-ins to access the game engine ...
Definition: IParaEngineCore.h:17
const char *(* lpFnLibDescription)()
"LibDescription": must be implemented in a plug-in.
Definition: PluginLoader.hpp:31
int(* lpFnLibActivate)(int nType, void *pVoid)
"LibActivate": this is optional in a plug-in
Definition: PluginLoader.hpp:43
bool IsValid()
whether the plugin loaded is valid.
Definition: PluginLoader.hpp:73
int Activate(int nType=0, void *pVoid=NULL)
Activate the DLL.
Definition: PluginLoader.hpp:307
int GetNumberOfClasses()
return the number of plugin classes inside the DLL
Definition: PluginLoader.hpp:113
const char * GetLibDescription()
When a plugin file is loaded that contains an entity that the system does not have access to (i...
Definition: PluginLoader.hpp:105
void UnLoad()
Free the library.
Definition: PluginLoader.hpp:280
void(* lpFnLibInit)()
"LibInit": this is optional in a plug-in
Definition: PluginLoader.hpp:39
ClassDescriptor * GetClassDescriptor(int i)
The plugin must provide the system with a way to retrieve the Class Descriptors defined by the plugin...
Definition: PluginLoader.hpp:92
System keeps a list of the DLL&#39;s found on startup.
Definition: PluginAPI.h:61