April 15, 2006
This is similar turf to the DDL project, but I couldn't see any examples for Windows DLL runtime linking. So I threw this together and while it works and I do like it, I'm wondering if it can be improved upon.

It lets you define a way to call a function in a DLL without linking in its import library.

So this -

# alias dllimport!("user32.dll", "MessageBoxW", uint, void*, wchar*, wchar*, uint) MessageBox;

can be used as you would with a DLL import library, but it's linked at runtime -

# MessageBox(null, "Hello", "World", 0);

Now, here's the template code that does the magic.

# template signature(R, T0 = void, T1 = void, T2 = void, T3 = void) {
#   static if (!is(T3 == void))
#     extern (Windows) alias R function(T0, T1, T2, T3) signature;
#   else static if (!is(T2 == void))
#     extern (Windows) alias R function(T0, T1, T2) signature;
#   else static if (!is(T1 == void))
#     extern (Windows) alias R function(T0, T1) signature;
#   else static if (!is(T0 == void))
#     extern (Windows) alias R function(T0) signature;
#   else
#     extern (Windows) alias R function() signature;
# }

# template functor(char[] dllName, char[] entryPoint, R, T0 = void, T1 = void, T2 = void, T3 = void) {
#   static if (!is(T3 == void)) {
#     static R opCall(T0 t0, T1 t1, T2 t2, T3 t3) {
#       return (cast(signatureT)GetProcAddress(LoadLibraryA(dllName), entryPoint))(t0, t1, t2, t3);
#     }
#   }
#   else static if (!is(T2 == void)) {
#     static R opCall(T0 t0, T1 t1, T2 t2) {
#       return (cast(signatureT)GetProcAddress(LoadLibraryA(dllName), entryPoint))(t0, t1, t2);
#     }
#   }
#   else static if (!is(T1 == void)) {
#     static R opCall(T0 t0, T1 t1) {
#       return (cast(signatureT)GetProcAddress(LoadLibraryA(dllName), entryPoint))(t0, t1);
#     }
#   }
#   else static if (!is(T0 == void)) {
#     static R opCall(T0 t0) {
#       return (cast(signatureT)GetProcAddress(LoadLibraryA(dllName), entryPoint))(t0);
#     }
#   }
#   else {
#     static R opCall() {
#       return (cast(signatureT)GetProcAddress(LoadLibraryA(dllName), entryPoint))();
#     }
#   }
# }

# struct dllimport(char[] dllName, char[] entryPoint, R, T0 = void, T1 = void, T2 = void, T3 = void) {
#   alias signature!(R, T0, T1, T2, T3) signatureT;
#   mixin functor!(dllName, entryPoint, R, T0, T1, T2, T3);
# }

There are some issues, obviously. FreeLibrary doesn't get called (fairly straightforward to solve). And it should check if both the DLL and function were found, throwing an exception if not.

My main question is this: can I get rid of the struct, maybe replacing it with a delegate? I've been staring at it for so long I can't see the alternatives.

Cheers.