My word, what a nerd-geek title ! But what does it mean ? Well, I wanted to load an unmanaged DLL in my C# project and link to its functions at runtime. Thing is, there are a 100+ functions to be linked to and life’s too short to type in the code to link each one in turn – to say nothing of error prone! So, lets see if reflection can come to the rescue.
OK, so lets understand the issue here. In my case, I was loading the main API dll for VLCPlayer and all the functions I want begin with “libvlc_”. It’s discussed more fully at Hosting VLC Player In .NET Winforms but the gist of it is for every function I want to call I need a delegate and an instance of that delegate:
Then when my dll is loaded (using Kernal32′s LoadLibrary) I’ll use GetProcAddress (also kerna32) to get a pointer:
For now, let’s assume this succeeds. Now to create the delegate that we can use to call the VLC dll’s function:
These last two lines – getting procAddress and setting _ libvlc_get_version will essentially be repeated for every linked function. Sure, cut and paste helps but before long you will do something dumb like:
Yep, courtesy of cut-n-paste wrong dll function for delegate … and much time spent head scratching instead of getting on with the important things in life such as making a cuppa. Now, thing is, all the functions I wanted to link to began “libvlc_” and I created an instance with the same name but prefixed with an underscore. Such consistency cries out Reflection !
Now, I’m going to assume you are an OOP programmer so will be keeping all these nasty delegates private and as you are loading a dll you’ll only be doing it once so the delegate instances should be static right ? OK, then we start with:
Now we just such the fields for fields whose names begin with “_libvlc”:
Now to write the “wire it up” bit. Since the delegate name is the same as the name of the function we are calling we can get the function pointer easily:
Assuming that succeeds we can then create the delegate and assign it to the field.
And that’s it ! Now, every time I define a new delegate and associated field it’ll get automatically wired up. The complete code is:
One final job : where the fields are actually defined, the compiler will generate warning CS0649 (“<field> is never assigned to, and will always have its default value null)”. It’s a fair cop, the compiler can’t reasonably be expected to know they are initialised via reflection. Therefore, we just need to put all the declarations in one place and wrap them with:
Job done, time for a tea break … or is it?
Handling Missing Functions
Now, in my case, I’m talking to a 3rd party dll and lets assume I’m not in control of the version that’s being loaded; functions come and functions go, so perhaps a bit of error checking wouldn’t go amiss.
Currently a missing dll function will result in a null argument exception in GetDelegateForFunctionPointer(). I don’t think that is appropriate for the client to get that type of exception, so add a check for function not found and throw a slightly (but not perfectly) more appropriate DllNotFoundException:
But we can do even better. Some DLL functions will always be required – for example, in VLC everything hinges on creating a “session” and without this the DLL would be useless. However, some other functions – for example reading the size of a video frame – I only added out of curiosity and only use in debugging so it’d be a shame to blow up just because a function I didn’t actually need were missing. Wouldn’t it be good to somehow mark functions that were optional ?
Applying Custom Attributes To Delegate Instances
One of the many things I like about C# (.NET) is being able to mark things with custom attributes. Lets create one that we can apply to functions we consider optional:
Wasn’t that easy ! And now we apply that attribute to optional functions:
… and modify the initialise-via-reflection such that when a dll entry point is missing it first checks for this attribute and does not throw an exception if the field has this attribute. (Note: when applying the attribute you can miss off the trailing word “Attribute”).
By the way, note the “gotcha” that initially had me scratching my head. “field” has an “Attributes” field and I was fully expecting my custom attribute to appear in there. But it didn’t. No, what was actually needed was I call field.GetCustomAttributes().
Anyhow, thats a wrap, finally, time for that well earned cuppa … what ? You don’t like reflection ‘cos it’s slow !?
I Don’t Like Reflection, It’s Slow
OK then, lets add a stopwatch around all that and dump the results out to a Debug.WriteLine():-see what we get:
DEBUG build: “Of 25 fields, 22 were vlc fields that were linked, and took 675 milliseconds”.
RELEASE build: “Of 25 fields, 22 were vlc fields that were linked, and took 3 milliseconds”
I can definitely live with that in release builds, though I’m guessing that by the time I have 100 vlc fields I might be wanting a faster PC for debug builds.