Created
September 29, 2012 15:47
-
-
Save MikeWey/3804415 to your computer and use it in GitHub Desktop.
GtkD loader using GetLastError
This file contains 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
/* | |
* This file is part of gtkD. | |
* | |
* gtkD is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU Lesser General Public License | |
* as published by the Free Software Foundation; either version 3 | |
* of the License, or (at your option) any later version, with | |
* some exceptions, please read the COPYING file. | |
* | |
* gtkD is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser General Public License | |
* along with gtkD; if not, write to the Free Software | |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA | |
*/ | |
module gtkc.Loader; | |
version(Tango) | |
{ | |
import tango.io.Stdout; | |
import tango.stdc.string; | |
import tango.stdc.stringz; | |
//For the string alias. | |
import gtkc.glibtypes; | |
} | |
else | |
{ | |
import std.stdio; | |
import std.string; | |
version(D_Version2) | |
import core.stdc.string; | |
else | |
import std.c.string; | |
} | |
import gtkc.paths; | |
public struct Linker | |
{ | |
private static void*[string] loadedLibraries; | |
private static string[][string] loadFailures; | |
/* | |
* Links the provided symbol | |
* Params: | |
* funct = The function we are linking | |
* symbol = The name of the symbol to link | |
* libraries = One or more libraries to search for the symbol | |
*/ | |
public static void link(T)(ref T funct, string symbol, LIBRARY[] libraries ...) | |
{ | |
funct = cast(T)getSymbol(symbol, libraries); | |
} | |
/* | |
* Links the provided symbol | |
* Params: | |
* funct = The function we are linking | |
* symbol = The name of the symbol to link | |
* libraries = One or more libraries to search for the symbol | |
*/ | |
public static void link(T)(inout T funct, string symbol, string[] libraries ...) | |
{ | |
funct = cast(T)getSymbol(symbol, libraries); | |
} | |
/* | |
* Gets a simbol from one of the provided libraries | |
* Params: | |
* symbol = The name of the symbol to link | |
* libraries = One or more libraries to search for the symbol | |
*/ | |
public static void* getSymbol(string symbol, LIBRARY[] libraries ...) | |
{ | |
string[] libStr = new string[libraries.length]; | |
foreach (i, library; libraries ) | |
{ | |
libStr[i] = importLibs[library]; | |
} | |
return getSymbol(symbol, libStr); | |
} | |
/* | |
* Gets a simbol from one of the provided libraries | |
* Params: | |
* symbol = The name of the symbol to link | |
* libraries = One or more libraries to search for the symbol | |
*/ | |
public static void* getSymbol(string symbol, string[] libraries ...) | |
{ | |
void* handle; | |
foreach ( library; libraries ) | |
{ | |
if( !(library in loadedLibraries) ) | |
loadLibrary(library); | |
handle = pGetSymbol(loadedLibraries[library], symbol); | |
if ( handle !is null ) | |
break; | |
} | |
if ( handle is null ) | |
{ | |
foreach ( library; libraries ) | |
loadFailures[library] ~= symbol; | |
} | |
return handle; | |
} | |
/* | |
* Loads a library | |
*/ | |
public static void loadLibrary(string library) | |
{ | |
void* handle = pLoadLibrary(libPath ~ library); | |
version(Windows) | |
{ | |
if ( handle is null ) | |
throw new Exception(getErrorMessage()); | |
} | |
else | |
{ | |
if ( handle is null ) | |
throw new Exception("Library load failed: " ~ library); | |
} | |
loadedLibraries[library] = handle; | |
} | |
/* | |
* Unload a library | |
*/ | |
public static void unloadLibrary(LIBRARY library) | |
{ | |
unloadLibrary( importLibs[library] ); | |
} | |
/* | |
* Unload a library | |
*/ | |
public static void unloadLibrary(string library) | |
{ | |
pUnloadLibrary(loadedLibraries[library]); | |
loadedLibraries.remove(library); | |
} | |
/** | |
* Checks if any symbol failed to load | |
* Returns: true if ALL symbols are loaded | |
*/ | |
public static bool isPerfectLoad() | |
{ | |
return loadFailures.keys.length == 0; | |
} | |
/** | |
* Gets all libraries loaded. | |
* returns: An array with the loaded libraries | |
*/ | |
public static string[] getLoadLibraries() | |
{ | |
return loadedLibraries.keys; | |
} | |
/** | |
* Print all libraries loaded. | |
*/ | |
public static void dumpLoadLibraries() | |
{ | |
foreach ( lib; getLoadLibraries() ) | |
{ | |
version(Tango) | |
Stdout.formatln("Loaded lib = {}", lib); | |
else | |
writefln("Loaded lib = %s", lib); | |
} | |
} | |
/** | |
* Checks if a library is loaded. | |
* Returns: true is the library was loaded sucsessfully. | |
*/ | |
public static bool isLoaded(LIBRARY library) | |
{ | |
return isLoaded(importLibs[library]); | |
} | |
/** | |
* Checks if a library is loaded. | |
* Returns: true is the library was loaded sucsessfully. | |
*/ | |
public static bool isLoaded(string library) | |
{ | |
if ( library in loadedLibraries ) | |
return true; | |
else | |
return false; | |
} | |
/** | |
* Gets all the failed loads for a specific library. | |
* returns: An array of the names hat failed to load for a specific library | |
* or null if none was found | |
*/ | |
public static string[] getLoadFailures(LIBRARY library) | |
{ | |
return getLoadFailures(importLibs[library]); | |
} | |
/** | |
* Gets all the failed loads for a specific library. | |
* returns: An array of the names hat failed to load for a specific library | |
* or null if none was found | |
*/ | |
public static string[] getLoadFailures(string library) | |
{ | |
if ( library in loadFailures ) | |
return loadFailures[library]; | |
else | |
return null; | |
} | |
/** | |
* Print all symbols that failed to load | |
*/ | |
public static void dumpFailedLoads() | |
{ | |
foreach ( library; loadedLibraries.keys ) | |
{ | |
foreach ( symbol; getLoadFailures(library) ) | |
{ | |
version(Tango) | |
Stdout.formatln("failed ({}) {}", library, symbol); | |
else | |
writefln("failed (%s) %s", library, symbol); | |
} | |
} | |
} | |
static ~this() | |
{ | |
foreach ( library; loadedLibraries.keys ) | |
unloadLibrary(library); | |
} | |
} | |
// Platform specific implementation below. | |
version(Windows) | |
{ | |
private: | |
extern(Windows) | |
{ | |
void* LoadLibraryA(char*); | |
void* GetProcAddress(void*, char*); | |
void FreeLibrary(void*); | |
uint GetLastError(); | |
uint FormatMessageA(uint, void*, uint, uint, char*, uint, void* /* va_list */); | |
enum MessageFormat | |
{ | |
FromSystem = 0x00001000, | |
ArgumentArray = 0x00002000 | |
} | |
enum Lang | |
{ | |
Neutral = 0x00 | |
} | |
} | |
uint errorCode; | |
void* pLoadLibrary(string libraryName) | |
{ | |
void* lib = LoadLibraryA(cast(char*)toStringz(libraryName)); | |
errorCode = GetLastError(); | |
return lib; | |
} | |
void* pGetSymbol(void* handle, string symbol) | |
{ | |
return GetProcAddress(handle, cast(char*)toStringz(symbol)); | |
} | |
alias FreeLibrary pUnloadLibrary; | |
string getErrorMessage() | |
{ | |
char[] buffer = new char[2048]; | |
FormatMessageA( MessageFormat.FromSystem | MessageFormat.ArgumentArray, | |
null, | |
errorCode, | |
Lang.Neutral, | |
buffer.ptr, | |
buffer.length, | |
null); | |
return cast(string)buffer[0 .. strlen(buffer.ptr)]; | |
} | |
} | |
else | |
{ | |
extern(C) | |
{ | |
void* dlopen(char*, int); | |
char* dlerror(); | |
void* dlsym(void*,char*); | |
int dlclose(void*); | |
} | |
enum RTLD | |
{ | |
LAZY = 0x00001, // Lazy function call binding | |
NOW = 0x00002, // Immediate function call binding | |
NOLOAD = 0x00004, // No object load | |
DEEPBIND = 0x00008, // | |
GLOBAL = 0x00100 // Make object available to whole program | |
} | |
private void* pLoadLibrary(string libraryName, RTLD flag = RTLD.NOW) | |
{ | |
void* handle = dlopen(cast(char*)toStringz(libraryName), flag); | |
// clear the error buffer | |
dlerror(); | |
return handle; | |
} | |
private void* pGetSymbol(void* libraryHandle, string symbol) | |
{ | |
void* symbolHandle = dlsym(libraryHandle, cast(char*)toStringz(symbol)); | |
// clear the error buffer | |
dlerror(); | |
return symbolHandle; | |
} | |
private int pUnloadLibrary(void* libraryHandle) | |
{ | |
return dlclose(libraryHandle); | |
} | |
version(build) version(linux) | |
{ | |
pragma(link, "dl"); // tell dsss to link libdl | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment