tags:

views:

171

answers:

2

I am making use of an external unmanaged dll using PInvoke and the DllImport attribute. eg.

[DllImport("mcs_apiD.dll", CharSet = CharSet.Auto)]
private static extern byte start_api(byte pid, byte stat, byte dbg, byte ka);

I am wondering if it is possible to alter the dll file details (mcs_apiD.dll in this example) dynmically in some manner, if for instance I wanted to build against another dll version

+1  A: 

you can't change the name of the dll but you can alter the path of the library being loaded (like by reading it from the registry or a configuration file) and load it manually with LoadLibrary kernel32's function: see my answer there.

Gregory Pakosz
Ok. But in my example I have specified a specific function prototype so that I can marsall the parameters correctly, some of the api functions have complex structures as parameters. How would I do this when working in this manner?
if the parameters change from one version of the DLL to another, you're out of luck with the method I mentioned
Gregory Pakosz
+2  A: 

Yes this is possible, you'll have to do part of the job that the P/Invoke marshaller does. Loading the DLL and finding the entry point of the exported function. Start by declaring a delegate whose signature matches the exported function:

 private delegate byte start_api(byte pid, byte stat, byte dbg, byte ka);

Then use code like this:

 using System.ComponentModel;
 using System.Runtime.InteropServices;
  ...

    static IntPtr dllHandle;
  ...
        if (dllHandle == IntPtr.Zero) {
            dllHandle = LoadLibrary("mcs_apiD.dll");
            if (dllHandle == IntPtr.Zero) throw new Win32Exception();
        }
        IntPtr addr = GetProcAddress(dllHandle, "_start_api@16");
        if (addr == IntPtr.Zero) throw new Win32Exception();
        var func = (start_api)Marshal.GetDelegateForFunctionPointer(addr, typeof(start_api));
        var retval = func(1, 2, 3, 4);
  ...
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr LoadLibrary(string name);
    [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string name);

Lots of ways to get this wrong of course. Do note that you have to use the actual exported name from the DLL, you no longer get the help from the P/Invoke marshaller to help with name decoration. Use dumpbin.exe /exports on the DLL if you are not sure what the export name looks like.

Hans Passant
indeed, with 1 delegate type per version of the DLL API combined with GetProcAddress, you'll get your way out of it
Gregory Pakosz