views:

1007

answers:

2

I have a need to create a wrapper for a DLL, loading and unloading it as needed (for those interested in the background of this question, see http://stackoverflow.com/questions/1662075/how-to-work-around-memory-leaking-3rd-party-dll-no-source-code-accessed-by-tomc) . I'm doing it in Visual Basic 6, and the loading and unloading with the following example works:


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

Private Sub cmdTestLoadingDLL_Click()

    Dim lb As Long, pa As Long    
    lb = LoadLibrary("D:\projects\other\VB_DLLs\TestDLL\TestDLL.dll")    

    Msgbox "Library address: " + lb

    FreeLibrary lb    

End Sub

I can see using Process Explorer that the DLL is loaded to memory when the messagebox is displayed, and is discarded afterwards. However, calling the method is naturally not enough - I need to access the methods within the dynamically loaded DLL.

How can I achieve this? I would like to call the method getVersion in class mainClass, which is in TestDLL, like this:


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

Private Sub cmdTestLoadingDLL_Click()

    Dim lb As Long, pa As Long
    Dim versionString As String

    lb = LoadLibrary("D:\projects\other\VB_DLLs\TestDLL\TestDLL.dll")    

    versionString = "- From DLL: " + mainClass.getVersion
    MsgBox versionString

    FreeLibrary lb    

End Sub

However, the line


versionString = "- From DLL: " + mainClass.getVersion

throws an error "Object required".

+1  A: 

First of all, since you are calling it via LoadLibrary, there are no classes here - only functions are exported for public consumption. So your mainClass reference would never work. Let's assume you have a function getVersion that is exported.

I would try the following:

Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long
Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Any, ByVal wParam As Any, ByVal lParam As Any) As Long

Private Sub Foo
  On Error Resume Next

  Dim lb As Long, pa As Long
  Dim versionString As String
  Dim retValue as Long

  lb = LoadLibrary("D:\projects\other\VB_DLLs\TestDLL\TestDLL.dll")  

  'retrieve the address of getVersion'
  pa = GetProcAddress(lb, "getVersion")

  'Call the getVersion function'
  retValue = CallWindowProc (pa, Me.hWnd, "I want my version", ByVal 0&, ByVal 0&)

  'release the library'
  FreeLibrary lb
End Sub
AngryHacker
When I try to get the address of function getVersion, it is always 0 (=not found). When accessing the DLL with DependencyWalker, I cannot see the function either. What could be the reason? I can only see the 4 standard functions: DllCanUnloadNow, DllGetClassObject, DllRegisterServer and DllUnregisterServer.
simon
Accepted as correct answer, even though it didn't work for me, as it seems to be the right way to do it.
simon
I'd google around for CallWindowProc. I've always used this method for calling functions that did not need to return anything. So perhaps, you need to figure out how CallWindowProc actually returns the value back from your getVersion function.
AngryHacker
+1  A: 

Do you need to call COM methods on this DLL? If so, I'm not at all sure this is possible.

  • Matthew Curland's excellent Advanced Visual Basic 6 is the first place I'd look, though. There's some powerful under-the-hood COM stuff in there that circumvents the normal VB6 techniques.

  • There's also DirectCom, which allows you to call COM methods without using COM. Never used it myself, but people chat about it on the VB6 newsgroup.

MarkJ
Thanks for the pointer to DirectCom, I was able to solve the original problem using ideas gathered from the DirectCom's DLL.
simon