Skip to content

Instantly share code, notes, and snippets.

@SirTony
Last active February 18, 2016 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SirTony/3656eb15d05be370f9ea to your computer and use it in GitHub Desktop.
Save SirTony/3656eb15d05be370f9ea to your computer and use it in GitHub Desktop.
A utility for loading exported functions from a shared library.
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;
}
}
// 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