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();
The update to your question provides enough information to explain the behaviour.
LoadLibrary
to load your DLL which accounts for one of the references.DllImport
p/invoke functions which in turn lead to a call toLoadLibrary
. That's the other reference to the library.FreeLibrary
, this succeeds twice since there were two calls toLoadLibrary
.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 callingGetModuleHandle
. They don't. They callLoadLibrary
. 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 toFreeLibrary
. You callLoadLibrary
once. So you must callFreeLibrary
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 withLoadLibrary
andGetProcAddress
.Your usage of
SetDllDirectory
looks somewhat messed up. What do you expect".\\DLL_Dependencies\\"
to be relative to? Supply a full path.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:
Then change your button5 click handler to the following:
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".