dllimport to unload dll

D

Dan Holmes

I have this DllImport attribute on an external C++ dll. What i am noticing that the dll isn't unloaded after the static
method is complete. I was thinking that when the method (it is a static method) completed then the dll would be unloaded.

[System.Runtime.InteropServices.DllImport(@"C:\dnlds\R3Rse_a.dll"
, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]

Is there a way i can force this to unload or will i have to use loadlibrary?

danny
 
J

Jeroen Mostert

Dan said:
I have this DllImport attribute on an external C++ dll. What i am
noticing that the dll isn't unloaded after the static method is
complete. I was thinking that when the method (it is a static method)
completed then the dll would be unloaded.
Well, first of all, the method being static or not has nothing to do with
anything. Imported functions do not take a "this" parameter whether they're
declared as static or not, and there are no special semantics associated
with it. To lessen confusion it's a good idea to always declare an imported
function as static, though.

Second, there is no way for the runtime to know that it's safe to unload the
DLL. Many DLLs cannot be unloaded at all, at least not without crashing the
executable that loaded them. They can start new threads, allocate resources,
register callbacks, etc, and many have no proper cleanup code. It would be
quite annoying to load a DLL, call a function that starts a background
thread, and then have the runtime helpfully unload that DLL behind your
back, which would either crash the thread or force the DLL to terminate it
(barring some hax code injection).
[System.Runtime.InteropServices.DllImport(@"C:\dnlds\R3Rse_a.dll"
, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]

Is there a way i can force this to unload or will i have to use
loadlibrary?
There's always GetModuleHandle() and FreeLibrary() (twice) if you're sure
the DLL can be safely unloaded. I don't know if explicit FreeLibrary() calls
cooperate nicely with the interop loading mechanism, though. Personally, I
wouldn't bother. About the only thing explicit unloading would be good for
is to allow the DLL to be replaced while the main application is still
running, which is a dubious versioning mechanism to say the least. .NET's
explicitly unloadable AppDomains are a better match for that.
 
D

Dan Holmes

Jeroen said:
Dan said:
I have this DllImport attribute on an external C++ dll. What i am
noticing that the dll isn't unloaded after the static method is
complete. I was thinking that when the method (it is a static method)
completed then the dll would be unloaded.
Well, first of all, the method being static or not has nothing to do
with anything. Imported functions do not take a "this" parameter whether
they're declared as static or not, and there are no special semantics
associated with it. To lessen confusion it's a good idea to always
declare an imported function as static, though.

Second, there is no way for the runtime to know that it's safe to unload
the DLL. Many DLLs cannot be unloaded at all, at least not without
crashing the executable that loaded them. They can start new threads,
allocate resources, register callbacks, etc, and many have no proper
cleanup code. It would be quite annoying to load a DLL, call a function
that starts a background thread, and then have the runtime helpfully
unload that DLL behind your back, which would either crash the thread or
force the DLL to terminate it (barring some hax code injection).
[System.Runtime.InteropServices.DllImport(@"C:\dnlds\R3Rse_a.dll"
, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]

Is there a way i can force this to unload or will i have to use
loadlibrary?
There's always GetModuleHandle() and FreeLibrary() (twice) if you're
sure the DLL can be safely unloaded. I don't know if explicit
FreeLibrary() calls cooperate nicely with the interop loading mechanism,
though. Personally, I wouldn't bother. About the only thing explicit
unloading would be good for is to allow the DLL to be replaced while the
main application is still running, which is a dubious versioning
mechanism to say the least. .NET's explicitly unloadable AppDomains are
a better match for that.
Fair enough though this is actually a SqlProcedure so the dll loads in SqlServer's memory space. That means if i need
to replace the dll i have to restart SqlServer. I don't want to do that.

If i used LoadLibrary and FreeLibrary would multiple calls to the dll get different instances of the dll thus enhancing
thread safety? Right now globals are shared among function calls ( i proved it). If the loadlibrary gets around that
that would be one more reason for the loadlibrary/freelibrary mechanism.

dan
 
J

Jeroen Mostert

Dan said:
Jeroen said:
Dan said:
I have this DllImport attribute on an external C++ dll. What i am
noticing that the dll isn't unloaded after the static method is
complete. I was thinking that when the method (it is a static
method) completed then the dll would be unloaded.
Well, first of all, the method being static or not has nothing to do
with anything. Imported functions do not take a "this" parameter
whether they're declared as static or not, and there are no special
semantics associated with it. To lessen confusion it's a good idea to
always declare an imported function as static, though.

Second, there is no way for the runtime to know that it's safe to
unload the DLL. Many DLLs cannot be unloaded at all, at least not
without crashing the executable that loaded them. They can start new
threads, allocate resources, register callbacks, etc, and many have no
proper cleanup code. It would be quite annoying to load a DLL, call a
function that starts a background thread, and then have the runtime
helpfully unload that DLL behind your back, which would either crash
the thread or force the DLL to terminate it (barring some hax code
injection).
[System.Runtime.InteropServices.DllImport(@"C:\dnlds\R3Rse_a.dll"
, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]

Is there a way i can force this to unload or will i have to use
loadlibrary?
There's always GetModuleHandle() and FreeLibrary() (twice) if you're
sure the DLL can be safely unloaded. I don't know if explicit
FreeLibrary() calls cooperate nicely with the interop loading
mechanism, though. Personally, I wouldn't bother. About the only thing
explicit unloading would be good for is to allow the DLL to be
replaced while the main application is still running, which is a
dubious versioning mechanism to say the least. .NET's explicitly
unloadable AppDomains are a better match for that.
Fair enough though this is actually a SqlProcedure so the dll loads in
SqlServer's memory space. That means if i need to replace the dll i
have to restart SqlServer. I don't want to do that.
Hold on, are you telling me you've written an assembly that's hosted in SQL
Server which explicitly calls unmanaged code? Ugh.

You're jeopardizing the stability and security of the server with such
antics. Never mind unloading the DLL, loading it in the first place is a bad
idea, unless it's under your full control and you're certain it does nothing
untoward. CLR hosting in SQL Server is subject to pretty serious
restrictions precisely because they didn't want just any old code to execute
as part of SQL Server itself. Too bad unmanaged imports can just waltz
completely around that.

If at all possible I'd investigate if you really need to use an unmanaged
library to achieve your goals. If it's small and standalone functionality,
maybe reimplementing it as pure managed code is feasible. If this isn't
feasible, I'd investigate if this functionality is really needed in a stored
procedure hosted in the database itself, rather than in a separate data
access layer that uses the database server rather than trying to become a
part of it.

OK, enough sermonizing. If you really want to do this, then yes, you'll
probably want to unload the DLL after using it, and an explicit
LoadLibrary() might be a better idea than relying on the automagic loading
done by the interop layer. Note that this means you'll have to use
GetProcAddress() and carefully crafted delegates (see for example
http://blogs.msdn.com/jmstall/archive/2007/01/06/Typesafe-GetProcAddress.aspx).
This also notes the caveats with FreeLibrary().

On the other hand, if you can't unload it, it at least forces you to
consider upgrades to the library very carefully. This is a good thing,
because bugs in the unmanaged library could have nasty consequences.
If i used LoadLibrary and FreeLibrary would multiple calls to the dll
get different instances of the dll thus enhancing thread safety?

If you mean "will multiple calls to LoadLibrary give me multiple instances
of the same DLL loaded simultaneously", then no. A DLL can be loaded only
once per process. Thread-safety has to be achieved through other means.
Ideally, the DLL is thread-aware and duplicates its per-thread data or
provides objects you can lock on. If not, you'll have to synchronize access
to the DLL yourself, for example through a mutex.

If you mean "will the state of the DLL be flushed if the DLL is unloaded and
then reloaded", it depends a bit on what mechanism the DLL uses for storing
its state. Regular C-like static variables are stored in a section of memory
that will be freed when the library is unloaded, and the DLL should free
anything else it allocated when it's unloaded, but it's possible for a DLL
to persist information across reloading (deliberately or accidentally).

A DLL becomes part of the loading process' address space, so it's not really
possible to guarantee it's not leaving mud stains on the carpet after you've
invited it in. Repeated unloading and reloading of a DLL can cause problems
if the DLL doesn't do proper cleanup.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top