Get Dll functions at compile time

Johnson Jones via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Aug 8 19:11:13 PDT 2017


I like to create code that automates much of the manual labor 
that we, as programmers, are generally forced to do. D generally 
makes much of this work automatable. For example, I have created 
the following code which makes loading dlls similar to libs:



/* Import DLL functions in to type T. The following example shows 
methodology
struct DLLImports
{
	@("DLLImport") public static extern(Windows)
	{
		@("libgdk-3-0.dll")
		{
			void* function(GdkWindow *window) gdk_win32_window_get_handle;
		}
	}
}

// Fixes static functions and function pointers to point to their 
specified DLL's
DllImport!DLLImports;
*/
void DLLImport(alias T)()
{
	version(Windows)
	{
		import core.sys.windows.windows, std.conv, std.meta, std.traits;
		HINSTANCE[string] DLLs;
	
		foreach(fname; __traits(allMembers, T))
		{	
			mixin("enum isf = isFunction!(T."~fname~");");
			mixin("enum isfp = isFunctionPointer!(T."~fname~");");
			mixin("enum attrs = __traits(getAttributes, T."~fname~");");		

			static if ((isf || isfp) && attrs.length == 2 && attrs[0] == 
"DLLImport")
			{
				auto dllName = attrs[1];
				if (dllName !in DLLs)
					DLLs[dllName] = LoadLibrary(to!wstring(dllName~"\0").ptr);

				auto dll = DLLs[dllName];
				if (dll == null)
					assert(0, "Cannot load DLL `"~dllName~"'");

				auto func = GetProcAddress(dll, fname);

				if (isf)
					mixin("auto p = cast(void**)&"~T.stringof~"."~fname~"; *p = 
cast(typeof(p))func;");
				else		
					mixin(""~T.stringof~"."~fname~" = 
cast(typeof("~T.stringof~"."~fname~"))func;");	
			}
		
		}
	}



But this got me thinking that we don't even need to have to 
specify the function in D, hell, they already exist in the lib 
and we are just duplicating work.

What if, at compile time, D could get all the functions and their 
type information and build a class for them for us? We could then 
just write something like

struct DLLImports
{
	@("DLLImport") string libgdk = "libgdk-3-0.dll";
}


and have some ctfe meta functions extract all the function from 
libgdk and insert them in to the struct.

There are two problems with this, one easy and one 
hard/impossible(which would be easy if people were intelligent 
enough to have foresight):


1. Get the dll function by name from the dll at compile time. 
This would probably require manually reading the dll file and 
scanning for the function.

2. Get the type information to build a declaration. This is 
probably impossible since dll's do not contain the type 
information about their parameters and return type(or do they?). 
If they did, it would be easy. I would suggest that all dll's 
generated by D include this information somewhere and an easy way 
to extract it for future programmers so such things could be 
implemented.

Alternatively, maybe a master database could be queried for such 
information by using the function names and dll name? I don't 
know if D has network capabilities at compile time though.

Alternatively, completely scrap the lethargic way things are done 
in the name of backwards compatibility and $$$ and do things 
right(learn from the past, stop repeating same mistakes, etc). 
Sure it's a lot of work, but in the end is far less than one 
thinks considering the increased productivity... but I guess the 
we gotta keep buying the kids christmas presents.





More information about the Digitalmars-d-learn mailing list