Last active
February 18, 2016 06:05
-
-
Save sirtony/3656eb15d05be370f9ea to your computer and use it in GitHub Desktop.
A utility for loading exported functions from a shared library.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module dylib; | |
private { | |
import std.string : format, toStringz; | |
import std.exception : enforce; | |
version( Windows ) | |
{ | |
extern( Windows ) void* LoadLibraryA( const char* ); | |
extern( Windows ) void* GetProcAddress( void*, const char* ); | |
extern( Windows ) void FreeLibrary( void* ); | |
void* loadLibrary( string name ) | |
{ | |
return LoadLibraryA( name.toStringz ); | |
} | |
void* loadSymbol( void* handle, string name ) | |
{ | |
return GetProcAddress( handle, name.toStringz ); | |
} | |
alias freeLibrary = FreeLibrary; | |
} | |
else version( linux ) | |
{ | |
extern( C ) void* dlopen( const char*, int ); | |
extern( C ) void* dlsym( void*, const char* ); | |
extern( C ) void dlclose( void* ); | |
void* loadLibrary( string name ) | |
{ | |
return dlopen( name.toStringz, 2 ); | |
} | |
void* loadSymbol( void* handle, string name ) | |
{ | |
return dlsym( handle, name.toStringz ); | |
} | |
alias freeLibrary = dlclose; | |
} | |
else | |
{ | |
static assert( false, "Unsupported OS" ); | |
} | |
} | |
final class InteropException : Exception | |
{ | |
this( string msg, string file = __FILE__, size_t line = __LINE__ ) | |
{ | |
super( msg, file, line ); | |
} | |
} | |
final class DynamicLoader | |
{ | |
private void* library; | |
private void*[string] symbols; | |
this( string path ) | |
{ | |
this.library = enforce!( InteropException )( loadLibrary( path ), "Unable to load library '%s'".format( path ) ); | |
} | |
~this() | |
{ | |
freeLibrary( this.library ); | |
} | |
auto loadFunction( string name, TRet = void, TArgs... )() | |
{ | |
alias func_t = extern( C ) TRet function( TArgs ); | |
void* symbol = this.loadSymbol!name; | |
return cast(func_t)symbol; | |
} | |
void opDispatch( string name, TRet, TArgs... )( out TRet result, TArgs args ) | |
{ | |
auto func = this.loadFunction!( name, TRet, TArgs ); | |
result = func( args ); | |
} | |
private void* loadSymbol( string name )() | |
{ | |
if( auto ptr = name in this.symbols ) | |
return *ptr; | |
auto symbol = enforce!( InteropException )( .loadSymbol( this.library, name ), "Unable to load symbol '%s'".format( name ) ); | |
this.symbols[name] = symbol; | |
return symbol; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Windows only | |
version( Windows ) | |
{ | |
enum WINDOWS = true; | |
} | |
else | |
{ | |
enum WINDOWS = false; | |
} | |
static if( !WINDOWS ) | |
static assert( false, "Cannot compile on non-Windows platforms" ); | |
import dylib : DynamicLoader; | |
import std.conv : toStringz; | |
void main() | |
{ | |
// call using loadFunction | |
auto loader = new DynamicLoader( "User32.dll" ); | |
auto MessageBoxA = loader.loadFunction!( "MessageBoxA", int, void*, const char*, const char*, uint ); | |
MessageBoxA( null, "Hello from D".toStringz, "Test".toStringz, 0 ); | |
// using opDispatch | |
auto User32 = loader; | |
int result; | |
User32.MessageBoxA( result, cast(void*)null, "Hello from D".toStringz, "Test".toStringz, 0u ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment