digitalmars.D.learn - DLL's reflection and Exceptions
- TheFlyingFiddle (88/88) Dec 28 2013 Hello everyone!
Hello everyone! I'm currently working on a run-time reflection module. The intent of this module is to simplify the process of loading functions / classes / structs from DLL's loaded at run-time. It works something like this ATM: //In pluggin.d (A dll module) void foo() { ... } class Bar { ... } struct Baz { ... } ... more members At the end of the file i have a function like this export extern(C) MetaAssembly getMetaAssembly() { //Tuple of filters to only load relevant stuff. alias filters = standardFilters; return AssemblyGenerator!(filters, module1, ..., moduleN).data; } //In program.d (A host program) void main() { auto dll = loadDll("pluggin0.dll"); MetaAssembly assembly = dll.func!(getter_t)("getMetaAssembly")() //Use assembly to find some classes //construct them and invoke some methods. MetaClass c = assembly. classes. find!(x => x.name == "Foo")[0]; RTObject fooObj = c.constructors[0].create(); MetaMethod method = c.methods[0]; method.invoke(fooObj, "Hello"); } AssemblyGenerator!(...) extracts all needed information from the modules and stores them in a collection of structs that can be used at run-time to do stuff like create instances / set fields / check attributes. Normal reflection stuff. This works fine for normal code flow. However it all falls apart as soon as any function located in a DLL throws an exception. If an exception is thrown the application freezes, usually visual studio crashes with "First hand exception: Privileged Instruction (some address)". I have hacked my way around this limitation like so: //pluggin.d alias exception_handler_t = void function(Throwable) nothrow; __gshared exception_handler_t exceptionHandler; //program.d Throwable t = null; void exceptionHandler(Throwable thrown) nothrow { t = thrown; } bool exceptionThrown() { return t !is null; } void rethrowException() { DLLException e = new DLLException(t.toString()); t = null; throw e; } void main() { auto dll = loadDLL("pluggin0.dll"); MetaAssembly assembly = dll.func!(getter_t)("getMetaAssembly")() auto field = assembly. staticFields. find!(x => x.name == "exceptionHandler"); field.set(&exceptionHandler) } The reflection api wrapps all functions / methods with a try - catch that will call the exceptionHandler if an exception occurs. At the calle side (program.a) after every call it will check if an exception was thrown and if so rethrowng it as a DLLException. This workaround works, (atleast for now) but i don't like it. It complicates the low-level reflection api alot and it only solves the problem of calls from program.d to pluggin.d not the other way around (unless i wrap them aswell). So now to the questions. 1. Why can't i throw exceptions over a DLL boundary? 2. Are there any problems with my hack other then the ones already stated? 3. Does other workarounds exist? Thank you for your time!
Dec 28 2013