www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - DLL's reflection and Exceptions

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