We have a supplier who provides a library for access to their hardware. Unfortunately, if you have multiple devices, you need to import their library multiple times, with different dll names. As a consequence, we have a metric ton of duplicated code, and I'm worried that it will soon become be a maintenance nightmare.
What we have at the moment is somthing like:
namespace MyNamespace {
public static class Device01 {
public const string DLL_NAME = @"Device01.dll";
[DllImport(DLL_NAME, EntryPoint = "_function1")]
public static extern int Function1(byte[] param);
...
[DllImport(DLL_NAME, EntryPoint = "_function99")]
public static extern int Function99(int param);
}
....
public static class Device16 {
public const string DLL_NAME = @"Device16.dll";
[DllImport(DLL_NAME, EntryPoint = "_function1")]
public static extern int Function1(byte[] param);
...
[DllImport(DLL_NAME, EntryPoint = "_function99")]
public static extern int Function99(int param);
}
}
If I were using C or C++, I would just define the functions one file and #include them multiple times in the static classes, not pretty but better than the alternative, but in C# I don't have that option.
If anyone has any clever ideas about how to effectively define a factory which would allow us to generate as many static device classes as we need, I would be very interested.
Thanks,
Edit: The function prototypes are quite videly varied, so any method which relies on them being the same wouldn't be suitable. Thanks for the suggestions so far, I wasn't expacting so many ideas quite so quickly.
I would also just suggest using the native
LoadLibrary
andGetProcAddress
.With the latter, you simply call
Marshal.GetDelegateForFunctionPointer
with a delegate type that matches the pinvoke method signature.How about using T4 (Text Template Transformation Toolkit). Create a .tt file with the following content:
Visual Studio will then convert this into:
Just some considerations:
Alternative #one
EDIT: this approach requires changing compiled methods, which is hard and requires injection, assembly modification or other methods that are commonly used in AOP-land. Consider approach two below, which is easier.
GetIlAsByteArray
to create a dynamic method of yourDllImport
methodAlternative #two:
EDIT: This alternative approach seems a bit involved at first, but someone already did the work for you. Look up this excellent CodeProject article and simply download and use its code to dynamically create DllImport style methods. Basically, it comes down to:
LoadLibrary
orLoadLibraryEx
using the dllimport API functionsMethodBuilder
.Alternative #three
EDIT: looking further, there's an easier approach: simply use
DefinePInvokeMethod
which does all you need. The MSDN link already gives a good example, but a full wrapper that can create any Native DLL based on DLL and function name is provided at this CodeProject article.DefinePInvokeMethod
Here's how this approach looks in code, you can reuse the returned delegate as much as you like, the costly building of the dynamic method should be done only once per method.
EDIT: updated the code sample to work with any delegate and to automatically reflect the correct return type and parameter types from the delegate signature. This way, we decoupled the implementation completely from the signature, which is, given your current situation, the best we can do. Advantages: you have type safety and single-point-of-change, which means: very easily manageable.
Other approaches are possible, I guess (like the templating approach mentioned by someone else in this thread).
Update: added a link to excellent codeproject article.
Update: third and way easier approach added.
Update: added code sample
Update: updated code sample to work seamlessly with any function prototype
Update: fixed dreadful error:
typeof(Function02)
should betypeof(T)
of course