forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			331 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			331 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| 
								 | 
							
								#ifndef HX_CFFI_LOADER_H
							 | 
						||
| 
								 | 
							
								#define HX_CFFI_LOADER_H
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
								  This file will only be incuded in one cpp file in the ndll library -
							 | 
						||
| 
								 | 
							
								    the one with IMPLEMENT_API #defined.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  The other files will refer to the val_ functions via the "extern" in CFFI.h
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  For dynamic linking, a macro (DEFFUNC) implements the "val_..." functions as function pointers,
							 | 
						||
| 
								 | 
							
								   and the cpp code calls these function pointers directly.
							 | 
						||
| 
								 | 
							
								  The pointers starts off as function pointers to bootstrap code, so when they are first called
							 | 
						||
| 
								 | 
							
								   the bootstrap uses the "ResolveProc" to find the correct version of the function for the particular
							 | 
						||
| 
								 | 
							
								   platform, and replaces the function pointer with this value. Subsequent calls then go directly
							 | 
						||
| 
								 | 
							
								   to the correct fucntion.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  The ResolveProc can come from:
							 | 
						||
| 
								 | 
							
								   Explicitly setting - the proc is set when a dll is loaded into the hxcpp exe
							 | 
						||
| 
								 | 
							
								   Via 'GetProcAddress' on the exe - if symbols are needed and the proc has not been set
							 | 
						||
| 
								 | 
							
								   Internal implementation (CFFINekoLoader) - when linking agaist a neko process.
							 | 
						||
| 
								 | 
							
								    - Old code used to find this in NekoApi.dll, but the glue code is now built into each ndll directly.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  For static linking, the functions are resolved at link time.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  For HXCPP_JS_PRIME, these functions are implemented in CFFIJsPrime
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef ANDROID
							 | 
						||
| 
								 | 
							
								#include <android/log.h>
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef NEKO_WINDOWS
							 | 
						||
| 
								 | 
							
								#include <windows.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								// Stoopid windows ...
							 | 
						||
| 
								 | 
							
								#ifdef RegisterClass
							 | 
						||
| 
								 | 
							
								#undef RegisterClass
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								#ifdef abs
							 | 
						||
| 
								 | 
							
								#undef abs
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#else // NOT NEKO_WINDOWS
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef NEKO_LINUX
							 | 
						||
| 
								 | 
							
								#define EXT "dso"
							 | 
						||
| 
								 | 
							
								#define NEKO_EXT "so"
							 | 
						||
| 
								 | 
							
								//#define __USE_GNU 1
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#elif defined(HX_MACOS)
							 | 
						||
| 
								 | 
							
								#include <mach-o/dyld.h>
							 | 
						||
| 
								 | 
							
								#define EXT "dylib"
							 | 
						||
| 
								 | 
							
								#define NEKO_EXT "dylib"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#if defined(EMSCRIPTEN)
							 | 
						||
| 
								 | 
							
								#define EXT "ll"
							 | 
						||
| 
								 | 
							
								#else
							 | 
						||
| 
								 | 
							
								#define EXT "so"
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <dlfcn.h>
							 | 
						||
| 
								 | 
							
								#include <stdio.h>
							 | 
						||
| 
								 | 
							
								#include <stdlib.h>
							 | 
						||
| 
								 | 
							
								#include <memory.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								#if defined(BLACKBERRY)
							 | 
						||
| 
								 | 
							
								using namespace std;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								typedef void *(*ResolveProc)(const char *inName);
							 | 
						||
| 
								 | 
							
								static ResolveProc sResolveProc = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								extern "C" {
							 | 
						||
| 
								 | 
							
								EXPORT void hx_set_loader(ResolveProc inProc)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   #ifdef ANDROID
							 | 
						||
| 
								 | 
							
								   __android_log_print(ANDROID_LOG_INFO, "haxe plugin", "Got Load Proc %p", inProc );
							 | 
						||
| 
								 | 
							
								   #endif
							 | 
						||
| 
								 | 
							
								   sResolveProc = inProc;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifdef HXCPP_JS_PRIME // { js prime
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define DEFFUNC(name,ret,def_args,call_args) \
							 | 
						||
| 
								 | 
							
								extern "C" ret name def_args;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include "CFFIJsPrime.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#elif defined(STATIC_LINK)  // js prime }   { not js prime, static link
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define DEFFUNC(name,ret,def_args,call_args) \
							 | 
						||
| 
								 | 
							
								extern "C" ret name def_args;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#else  // static link }   { Dynamic link
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #ifdef NEKO_COMPATIBLE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      #include "CFFINekoLoader.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #endif // NEKO_COMPATIBLE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   // This code will get run when the library is compiled against a newer version of hxcpp,
							 | 
						||
| 
								 | 
							
								   //  and the application code uses an older version.
							 | 
						||
| 
								 | 
							
								   bool default_val_is_buffer(void *inBuffer)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      typedef void *(ValToBufferFunc)(void *);
							 | 
						||
| 
								 | 
							
								      static ValToBufferFunc *valToBuffer = 0;
							 | 
						||
| 
								 | 
							
								      if (!valToBuffer)
							 | 
						||
| 
								 | 
							
								         valToBuffer = (ValToBufferFunc *)sResolveProc("val_to_buffer");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (valToBuffer)
							 | 
						||
| 
								 | 
							
								         return valToBuffer(inBuffer)!=0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return false;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   // Neko, old cpp and js_prime are all utf8 based - and go through here
							 | 
						||
| 
								 | 
							
								   #ifdef HXCPP_PRIME
							 | 
						||
| 
								 | 
							
								   struct DynAlloc : public hx::IStringAlloc
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      #define WANT_DYNALLOC_ALLOC_BYTES
							 | 
						||
| 
								 | 
							
								      void *allocBytes(size_t n);
							 | 
						||
| 
								 | 
							
								   };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   HxString default_string_wchar(const wchar_t *src,int len)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      hx::strbuf buf;
							 | 
						||
| 
								 | 
							
								      const char *str = cffi::to_utf8(src,len,&buf);
							 | 
						||
| 
								 | 
							
								      return HxString(str,len);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   HxString default_string_utf8(const char *str,int len)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      return HxString(str,len);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   HxString default_string_utf16(const char16_t *src,int len)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      hx::strbuf buf;
							 | 
						||
| 
								 | 
							
								      const char *str = cffi::to_utf8(src,len,&buf);
							 | 
						||
| 
								 | 
							
								      return HxString(str,len);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   const char *default_to_utf8(const HxString &str,hx::IStringAlloc *alloc)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      return str.c_str();
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   const wchar_t *default_to_wchar(const HxString &str,hx::IStringAlloc *alloc)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      DynAlloc d;
							 | 
						||
| 
								 | 
							
								      if (!alloc)
							 | 
						||
| 
								 | 
							
								         alloc = &d;
							 | 
						||
| 
								 | 
							
								      return cffi::from_utf8<wchar_t>(str.c_str(),str.size(),alloc);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   const char16_t *default_to_utf16(const HxString &str,hx::IStringAlloc *alloc)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      DynAlloc d;
							 | 
						||
| 
								 | 
							
								      if (!alloc)
							 | 
						||
| 
								 | 
							
								         alloc = &d;
							 | 
						||
| 
								 | 
							
								      return cffi::from_utf8<char16_t>(str.c_str(),str.size(),alloc);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   hx::StringEncoding default_get_encoding(void *inPtr) { return hx::StringUtf8; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   void * default_alloc_empty_string(int) { return 0; }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   // Do nothing on earlier versions of hxcpp that do not know what to do
							 | 
						||
| 
								 | 
							
								   void default_gc_change_managed_memory(int,const char *) { }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   void *ResolveDefault(const char *inName)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      void *result = sResolveProc(inName);
							 | 
						||
| 
								 | 
							
								      if (result)
							 | 
						||
| 
								 | 
							
								         return result;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"val_is_buffer"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_val_is_buffer;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"alloc_empty_string"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_alloc_empty_string;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"gc_change_managed_memory"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_gc_change_managed_memory;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"hxs_encoding"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_get_encoding;
							 | 
						||
| 
								 | 
							
								      #ifdef HXCPP_PRIME
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"alloc_hxs_wchar"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_string_wchar;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"alloc_hxs_utf16"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_string_utf16;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"alloc_hxs_utf8"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_string_utf8;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"hxs_utf8"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_to_utf8;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"hxs_utf16"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_to_utf16;
							 | 
						||
| 
								 | 
							
								      if (!strcmp(inName,"hxs_wchar"))
							 | 
						||
| 
								 | 
							
								         return (void *)default_to_wchar;
							 | 
						||
| 
								 | 
							
								      #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return 0;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #ifdef NEKO_WINDOWS // {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   void *LoadFunc(const char *inName)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      #ifndef HX_WINRT
							 | 
						||
| 
								 | 
							
								      static const char *modules[] = { 0, "hxcpp", "hxcpp-debug" };
							 | 
						||
| 
								 | 
							
								      for(int i=0; i<3 && sResolveProc==0; i++)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         HMODULE handle = GetModuleHandleA(modules[i]);
							 | 
						||
| 
								 | 
							
								         if (handle)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            sResolveProc = (ResolveProc)GetProcAddress(handle,"hx_cffi");
							 | 
						||
| 
								 | 
							
								            if (sResolveProc==0)
							 | 
						||
| 
								 | 
							
								               FreeLibrary(handle);
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      #ifdef NEKO_COMPATIBLE
							 | 
						||
| 
								 | 
							
								      if (sResolveProc==0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         sResolveProc = InitDynamicNekoLoader();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (sResolveProc==0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         fprintf(stderr,"Could not link plugin to process (hxCFFILoader.h %d)\n",__LINE__);
							 | 
						||
| 
								 | 
							
								         exit(1);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return ResolveDefault(inName);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #else // windows }  { not windows
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   void *LoadFunc(const char *inName)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      #ifndef ANDROID // {
							 | 
						||
| 
								 | 
							
								         if (sResolveProc==0)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            sResolveProc = (ResolveProc)dlsym(RTLD_DEFAULT,"hx_cffi");
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								         #ifdef NEKO_COMPATIBLE
							 | 
						||
| 
								 | 
							
								         if (sResolveProc==0)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            sResolveProc = InitDynamicNekoLoader();
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         #endif
							 | 
						||
| 
								 | 
							
								      #endif // !Android  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (sResolveProc==0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         #ifdef ANDROID
							 | 
						||
| 
								 | 
							
								         __android_log_print(ANDROID_LOG_ERROR, "CFFILoader.h", "Could not API %s", inName);
							 | 
						||
| 
								 | 
							
								         return 0;
							 | 
						||
| 
								 | 
							
								         #else
							 | 
						||
| 
								 | 
							
								         #ifdef NEKO_COMPATIBLE
							 | 
						||
| 
								 | 
							
								         fprintf(stderr,"Could not link plugin to process (CFFILoader.h %d) - with neko\n",__LINE__);
							 | 
						||
| 
								 | 
							
								         #else
							 | 
						||
| 
								 | 
							
								         fprintf(stderr,"Could not link plugin to process (CFFILoader.h %d)\n",__LINE__);
							 | 
						||
| 
								 | 
							
								         #endif
							 | 
						||
| 
								 | 
							
								         exit(1);
							 | 
						||
| 
								 | 
							
								         #endif
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      return ResolveDefault(inName);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #undef EXT
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #endif // not windows }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #ifndef ANDROID // not android {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #define DEFFUNC(name,ret,def_args,call_args) \
							 | 
						||
| 
								 | 
							
								   typedef ret (*FUNC_##name)def_args; \
							 | 
						||
| 
								 | 
							
								   extern FUNC_##name name; \
							 | 
						||
| 
								 | 
							
								   ret IMPL_##name def_args \
							 | 
						||
| 
								 | 
							
								   { \
							 | 
						||
| 
								 | 
							
								      name = (FUNC_##name)LoadFunc(#name); \
							 | 
						||
| 
								 | 
							
								      if (!name) \
							 | 
						||
| 
								 | 
							
								      { \
							 | 
						||
| 
								 | 
							
								         fprintf(stderr,"Could not find function:" #name " \n"); \
							 | 
						||
| 
								 | 
							
								         exit(1); \
							 | 
						||
| 
								 | 
							
								      } \
							 | 
						||
| 
								 | 
							
								      return name call_args; \
							 | 
						||
| 
								 | 
							
								   }\
							 | 
						||
| 
								 | 
							
								   FUNC_##name name = IMPL_##name;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								   #ifdef NEKO_COMPATIBLE
							 | 
						||
| 
								 | 
							
								   DEFINE_PRIM(neko_init,5)
							 | 
						||
| 
								 | 
							
								   #endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #else // not android }  { android
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #define DEFFUNC(name,ret,def_args,call_args) \
							 | 
						||
| 
								 | 
							
								   typedef ret (*FUNC_##name)def_args; \
							 | 
						||
| 
								 | 
							
								   extern FUNC_##name name; \
							 | 
						||
| 
								 | 
							
								   ret IMPL_##name def_args \
							 | 
						||
| 
								 | 
							
								   { \
							 | 
						||
| 
								 | 
							
								      name = (FUNC_##name)LoadFunc(#name); \
							 | 
						||
| 
								 | 
							
								      if (!name) \
							 | 
						||
| 
								 | 
							
								      { \
							 | 
						||
| 
								 | 
							
								         __android_log_print(ANDROID_LOG_ERROR,"CFFILoader", "Could not find function:" #name "\n"); \
							 | 
						||
| 
								 | 
							
								      } \
							 | 
						||
| 
								 | 
							
								      return name call_args; \
							 | 
						||
| 
								 | 
							
								   }\
							 | 
						||
| 
								 | 
							
								   FUNC_##name name = IMPL_##name;
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   #endif // android }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif // dynamic link }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 |