-1

Have the following C# code for loading and unloading a C++ DLL.

I load DLL only once, but code has to unload DLL 2 times. Also after unloading DLL, when I load it again, and I call DLL's exported function, I get the following error message:

Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

DLL depends on other DLLs.

    /// //////////////handle of FDD DLL:
    System.IntPtr SystemIntPtr_handle_of_DLL=System.IntPtr.Zero;

    private void button4_Click(object sender, EventArgs e)
    {
        try
        {
            string string_Dependency_path = ".\\DLL_Dependencies\\";
            Call_DLL.SetDllDirectory(string_Dependency_path);
            SystemIntPtr_handle_of_DLL = Call_DLL.LoadLibrary("DLL.dll");
            if (SystemIntPtr_handle_of_DLL == System.IntPtr.Zero) { throw new Exception("DLL did not load"); }

        }
        catch (Exception Exception_Object) { MessageBox.Show(Exception_Object.Message); }
    }

    private void button5_Click(object sender, EventArgs e)
    {
        try
        {
            int int_FreeLibrary_counter = 0;
            while (Call_DLL.FreeLibrary(SystemIntPtr_handle_of_DLL))
            {
                int_FreeLibrary_counter++;
            }
            MessageBox.Show("DLL unloaded. You will have to load it again. (Unloaded" + int_FreeLibrary_counter + " times)");
        }
        catch (Exception Exception_Object) { MessageBox.Show(Exception_Object.Message); }
    }

The invoke method:

class Call_DLL
{
    [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool SetDllDirectory(string string_Dependency_path);
    [DllImport("kernel32.dll")]
    public static extern IntPtr LoadLibrary(string string_DLL_name);
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool FreeLibrary(IntPtr IntPtr_handle_of_DLL);
}

EDIT

I forgot to include the following which call DLL exported functions, after loading DLL and before unloading DLL. It makes sense to think that something else is going on inside these exported functions which is causing strange behavior (i.e. loading 1 time, having to unload 2 times):

    [DllImport(@"DLL.dll", EntryPoint = "getFreq")]
    public static extern System.IntPtr getFreq([In, Out, MarshalAs(UnmanagedType.LPStr)] string char_Address, [In, Out, MarshalAs(UnmanagedType.I4)]int int_Num, [In, Out, MarshalAs(UnmanagedType.I4)]int int_Samp);
    [DllImport(@"DLL.dll", EntryPoint = "setNat")]
    public static extern System.IntPtr setNat([In, Out, MarshalAs(UnmanagedType.LPStr)]string char_Address_File_nat);
    [DllImport(@"DLL.dll", EntryPoint = "getMode")]
    public static extern System.IntPtr getMode();
Megidd
  • 7,089
  • 6
  • 65
  • 142
  • 2
    It's pretty certain that freeing the library twice is why it fails on subsequent reload. Why do you feel you need to free it twice? – Mark B Feb 25 '15 at 21:01
  • 1
    That behaviour cannot readily be re-produced. So until you can show us how to reproduce this, there's nothing to answer. – David Heffernan Feb 25 '15 at 21:23
  • @DavidHeffernan You're right. I should think about how to provide information to be able to reproduce this behavior. – Megidd Feb 25 '15 at 21:52
  • 2
    My psychic debugger says that you forgot to post your [DllImport] declaration that *also* uses this DLL. You cannot do it both ways. – Hans Passant Feb 25 '15 at 22:03
  • @HansPassant Right, I added now. – Megidd Feb 26 '15 at 13:32
  • You still cannot do it both ways. – Hans Passant Feb 26 '15 at 13:43
  • @HansPassant I didn't understand what you meant. Can you explain. – Megidd Feb 26 '15 at 14:37
  • 1
    Not until you explain why you think you need to do this. Up until now it looks completely pointless to use LoadLibrary. – Hans Passant Feb 26 '15 at 14:39
  • @HansPassant I was using `LoadLibrary` to be able to use `SetDllDirectory`, but I think you mean it is a better idea to use [this](http://stackoverflow.com/a/11418341/3405291) procedure. Right? – Megidd Feb 26 '15 at 14:43
  • 1
    Hmm, hardly. But given how confused you are about SetDllDirectory(), you'll certainly have better luck with that. – Hans Passant Feb 26 '15 at 14:45
  • @HansPassant I'm going to test with [that](http://stackoverflow.com/a/11418341/3405291) procedure. – Megidd Feb 26 '15 at 14:47
  • @HansPassant btw, please let me know if I'm not aware of any better procedure to use instead of `SetDllDirectory`. – Megidd Feb 26 '15 at 14:49
  • 1
    SetDllDirectory is fine. You have to stop calling LoadLibrary. Then it's all good. Or follow the rules and call FreeLibrary as many times as you called LoadLibrary. – David Heffernan Feb 26 '15 at 14:53
  • Down-vote is not fair! – Megidd Mar 24 '15 at 13:38

4 Answers4

5

The update to your question provides enough information to explain the behaviour.

  1. You call LoadLibrary to load your DLL which accounts for one of the references.
  2. You call DllImport p/invoke functions which in turn lead to a call to LoadLibrary. That's the other reference to the library.
  3. Then when you call FreeLibrary, this succeeds twice since there were two calls to LoadLibrary.

But now you are in trouble because you've gone behind the back of the p/invoke system and it still believes that it owns one of the references to the DLL. A reference that you stole from it with your second call to FreeLibrary.

I guess that the information you are missing is how the DllImport p/invokes bind to the function. You are hoping that they will obtain a module handle by calling GetModuleHandle. They don't. They call LoadLibrary. They do this the first time they are called and the module they load stays loaded until the assembly itself unloads.

What you have to do, above all else, is follow the rules. The rules state that each call to LoadLibrary is to be matched by a call to FreeLibrary. You call LoadLibrary once. So you must call FreeLibrary exactly once also. Stop calling it twice and all is well.

I suspect that you are actually trying to arrange a system whereby you can load and unload DLLs. This prevents you from using p/invoke via DllImport. You'll have to do it all with LoadLibrary and GetProcAddress.

Your usage of SetDllDirectory looks somewhat messed up. What do you expect ".\\DLL_Dependencies\\" to be relative to? Supply a full path.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • In a comment of [this](http://stackoverflow.com/a/11418341/3405291) post, it is mentioned that _Path set via SetDllDirectory function will not be used when you're loading dlls via .NET interop (DllImport)_. My observation implies that that comment looks misleading. – Megidd Feb 26 '15 at 16:06
0

If you only call LoadLibrary once then you only need to call FreeLibrary once as well. Calling it a second time is moving into undefined behavior.

If you look at the MSDN docs https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152%28v=vs.85%29.aspx the function returns a non zero value if it succeeds, or 0 if there is an error.

If you want to be sure that its unloaded then you can call GetModuleHandle on it after the call to FreeLibrary and it should return null. https://msdn.microsoft.com/en-us/library/windows/desktop/ms683199(v=vs.85).aspx

Updated your invoke method class to include:

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);

Then change your button5 click handler to the following:

private void button5_Click(object sender, EventArgs e)
{
    try
    {
        int freeCount = 0;
        while(Call_DLL.GetModuleHandle("DLL.dll") != System.IntPtr.Zero)
        {
             Call_DLL.FreeLibrary(SystemIntPtr_handle_of_DLL);
             freeCount++;
        }

        MessageBox.Show("DLL unloaded. You will have to load it again. (Unloaded" + int_FreeLibrary_counter + " times)");
     }
     catch(Exception Exception_Object)
     {
        MessageBox.Show(Exception_Object.Message);
     }
}
rgoble
  • 329
  • 2
  • 7
  • 1
    The question is asking why that second call succeeds. Can you explain why that happens? – David Heffernan Feb 25 '15 at 21:25
  • The second call doesn't succeed, it fails. The docs clearly state that it returns 0 if there is an error, which is why it exits the loop after the second call. – rgoble Feb 26 '15 at 03:48
  • 1
    The second call succeeds which is why it enters the loop body a second time – David Heffernan Feb 26 '15 at 07:01
  • @rgoble I implemented your procedure with `GetModuleHandle` and behavior is the same: I load DLL 1 time, and `int_FreeLibrary_counter++` shows that it has to be unloaded 2 times. – Megidd Feb 26 '15 at 14:05
  • 1
    @user Why did you think anything would change. rgoble hasn't attempted to explain where the extra ref count comes from. – David Heffernan Feb 26 '15 at 14:51
  • @DavidHeffernan You're right. Code of rgoble was basically doing the same thing, no change expected. – Megidd Feb 26 '15 at 14:55
  • @DavidHeffernan You were correct that it was unloading it twice. I was mistaken and thought FreeLibrary was only being called twice, but it was actually called 3 times. – rgoble Feb 26 '15 at 16:09
0

I know that this question come to completion, but working on a similar problem I have found a way to load and unload library dynamically using DllImport and without exceptions.

The approach is based on these stakeholders:
- the DllImport load the library on the first call to a method wrapped.
- if a library is alredy loaded on the stack the call to a method will use this instance of the library instead load another one

based on these considerations you can manage your module in this way:

  1. implement your class which wrap the library
    public class MyWrapper
    {
        int _libraryHandle = 0;

        [DllImport("mylibrary.dll")]
        public external static void MyMethod();
    }
  1. in the constructor load the library using LoadLibrary:
    public MyWrapper()
    {
        _libraryHandle = LoadLibrary("mylibrary.dll");
    }
  1. in the dispose method unload the library using FreeLibrary:
    public Dispose()
    {
        FreeLibrary(_libraryHandle);
    }

in this way everytime you'll instance your wrapper a new occurrence of the library will be loaded on the stack without any exception.

-1

According to https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152%28v=vs.85%29.aspx (the first google hit) If the function succeeds, the return value is nonzero. Your unload loop basically says "as long as freeing the library worked, free it again, until the unload fails".

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 1
    I think that the asker knows this but can't understand why the number of calls to `LoadLibrary` doesn't match the number made to `FreeLibrary`. Do you know why? – David Heffernan Feb 25 '15 at 21:24