0

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?

Andrey Bushman
  • 11,712
  • 17
  • 87
  • 182
  • Did you think about combining http://stackoverflow.com/questions/18362368/loading-dlls-at-runtime-in-c-sharp and http://stackoverflow.com/questions/6493715/how-to-get-current-product-version-in-c ? – Fruchtzwerg May 28 '16 at 12:22
  • I don't see the relation between my theme and those which were specified by you. – Andrey Bushman May 28 '16 at 12:28
  • 1
    It is really simple, just rename the DLL when you deploy it. The odds that you can do anything automated when the api changes and, say, a function gets an extra argument are zero. – Hans Passant May 28 '16 at 12:39
  • @HansPassant, you are not right (if I correctly understood you). That DLL (`some_library_v*.dll`) is not mine. I can't rename it. If I do it then application will not work. I write *the managed extension* for that *unmanaged* program. – Andrey Bushman May 28 '16 at 12:46
  • Is the dll name different in each version of that application? Is the dll deployed in the unmanaged application's folder? – Ivan Prodanov May 28 '16 at 12:58
  • 1
    Well, sure you can rename it. You can also copy it. What gets loaded into *your* process is not under the control of anybody but you. – Hans Passant May 28 '16 at 12:59
  • @IvanProdanov "yes" for both your questions. – Andrey Bushman May 28 '16 at 13:45
  • @HansPassant, that dll has complex dependencies. – Andrey Bushman May 28 '16 at 13:49
  • @Andrey That information was quite useful. Just wrote an answer. Let me know if you need a sample – Ivan Prodanov May 28 '16 at 14:01
  • 1
    It does not matter that it has dependencies, as long as you don't rename the dependencies. The only one that loads *that* DLL is you. Did you actually try this? – Hans Passant May 28 '16 at 14:50

2 Answers2

1

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");
Oleh Nechytailo
  • 2,155
  • 17
  • 26
0

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).
Ivan Prodanov
  • 34,634
  • 78
  • 176
  • 248