VBA FreeLibrary doesn't unload DLL

2019-08-14 08:07发布

问题:

I need to delete a DLL file when I am done using it (cleanup after code is completed).

I try using "LoadLibrary" and "FreeLibrary" in Excel VBA but no matter what I do Excel.exe clings to the DLL file.

 Public Declare PtrSafe Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
 Public Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long

 Private Sub Load_Unload_DLL()

     Dim lb As Long, pa As Long
     lb = LoadLibrary("C:\Users\Administrator\Documents\MathLibrary.dll")

     'MsgBox "Library address: " & lb

     Dim FreeResult As Long
     FreeResult = 1

     Do Until FreeResult = 0
         FreeResult = FreeLibrary(lb)
     Loop

     Name "C:\Users\Administrator\Documents\MathLibrary.dll" As "C:\Users\Administrator\Documents\MathLibrary2.dll"

     Kill ("C:\Users\Administrator\Documents\MathLibrary2.dll")

 End Sub

Despite "FreeResult" equaling "0" I receive the following error when executing the "Kill" command:

And Process Explorer showing that the DLL file is indeed still loaded by Excel:

The file can be renamed, but not deleted (as indicated by the code).

Am I missing something?

回答1:

I've just rediscovered this answer and with the benefit of some more experience suggest it NOT be used.

See: https://stackoverflow.com/a/28745693/3451115

One of the issues that I faced with this approach is that, although the library was freed, trying to reload it crashed the host (MS Word for me).

Evil as it is, it may meet a need so be advised and use with caution.


Depending on what the root cause of your problem is this may or may not help, but I think it is a step in the right direction.

The return value of 0 from FreeLib indicates that there has been an error and NOT that the library has been freed, see here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683152%28v=vs.85%29.aspx

From what I understand FreeLib should only be called as many times as LoadLibrary was used... so, rather than looping until an error appears (FreeLib = 0) you could instead have a loop that frees the library and then checks if the library is still loaded, try something like this:

    Do Until lb = 0
        FreeLibrary lb
        If CBool(Err.LastDllError) Then
            debug.print "dll error" & " " & Err.LastDllError
            Err.Clear
            Exit Do
        End If

        lb = 0 ' Reset lb needed for test on next line

        ' Check if the dll really has been released...
        lb = GetModuleHandle("C:\Users\Administrator\Documents\MathLibrary.dll")
    Loop

You'll need to declare this function to use GetModuleHandle (VBA7 version): Private Declare PtrSafe Function GetModuleHandle Lib "kernel32" Alias "GetModuleHandleA" (ByVal GetModuleHandle As String) As LongPtr.

Also, I'm declaring LoadLib and FreeLib with LongPtr for VBA7 like this:

Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Private Declare PtrSafe Function FreeLibrary Lib "kernel32" (ByVal hLibModule As LongPtr) As Long

Hope it helps :)