Andrey Bushman
Andrey Bushman

Reputation: 12516

Dynamically generate code for DllImport depending on application version

I write the .net-extension which can be loaded into different versions of some unmanaged application.

Below I imported the some_func_v01, some_func_v02, and some_func_v03 functions:

[DllImport("some_library_v1.0.dll", CallingConvention = CallingConvention.Cdecl, 
    CharSet = CharSet.Unicode, EntryPoint = "func_name")]
extern static private void some_func_v01(string msg);

[DllImport("some_library_v2.0.dll", CallingConvention = CallingConvention.Cdecl, 
    CharSet = CharSet.Unicode, EntryPoint = "func_name")]
extern static private void some_func_v02(string msg);

[DllImport("some_library_v3.0.dll", CallingConvention = CallingConvention.Cdecl, 
    CharSet = CharSet.Unicode, EntryPoint = "func_name")]
extern static private void some_func_v03(string msg);

...

public void some_func(string msg) 
{
  switch (Application.Version.Major)
  {
    case 1: some_func_v01(msg); break;
    case 2: some_func_v02(msg); break;
    case 3: some_func_v03(msg); break;
  }
}

The some_library library is the part of the target application and has the same version like the application.

The problem is that I am to edit the code of my extension when the new versions of application will appear. I would like to dynamically generate code depending of application version. For example, for application version 1:

[DllImport("some_library_v1.0.dll", CallingConvention = CallingConvention.Cdecl, 
    CharSet = CharSet.Unicode, EntryPoint = "func_name")]
extern static private void some_func(string msg);

I can to do it through the PowerShell hosting using, but maybe more simple way exists... I wouldn't want to create PowerShell hosting only to carry out this task.

Is exist the simple way to do it?

Upvotes: 0

Views: 137

Answers (2)

Ivan Prodanov
Ivan Prodanov

Reputation: 35522

Since you know the version of the external application then you also know its directory and hence the location of of the external dll which resides somewhere in the directory of the external application. What you would like to ignore is the suffix name of the dll (the version v_1 part given in your example). I believe that there is only one version of that dll in each version of the external application.

If my assumption is correct then you could achieve all this like so:

  1. Choose a prefix of the dll that is always in its filename no matter the version ("some_library" in your example)
  2. Enumerate all files in the location of the dll in the external application's directory or subdirectory (Directory.EnumerateFiles or .GetFiles if using older .NET)
  3. Locate the filename that matches the prefix ("some_library_*.dll" as given in your example)
  4. Load the dll dynamically and call the function (Oleh gave you a good example in his answer).

Upvotes: 0

Oleh Nechytailo
Oleh Nechytailo

Reputation: 2195

I think that the best solution will be to load DLLs dynamically.

Use WINAPI LoadLibrary and GetProcAddress to get address of the function. Then use Marshal.GetDelegateForFunctionPointer to get .net delegate.

Example:

//skipping WINAPI native definitions
//you need to define delegate type:
[UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
delegate void MyFuncType(string msg);


//how to get delegate object:

var library = LoadLibrary(libraryNameChosenAtRuntime);
var funcPtr = GetProcAddress(library, funcName);
var func = Marshal.GetDelegateForFunctionPointer<MyFuncType>(funcPtr);

// now you can use func as delegate
// you can store this delegate object somewhere and reuse.
func("msg");

Upvotes: 1

Related Questions