Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsVB SyntaxEnterprise DevelopmentDatabase AccessControlsCOMWin APICrystal ReportDeploymentGeneralGeneral 2
Related Topics
VB.NET / ASP.NETMS SQL ServerMS AccessOther Database ProductsMore Topics ...

VB Forum / Win API / September 2003



Tip: Looking for answers? Try searching our database.

Unloading Win32 System DLL

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Mohammad Shahzad Saleem - 26 Sep 2003 15:38 GMT
Hi,

I have developed a Win32 System DLL. I am calling its APIs like the way
system APIs are called.
When call to any of its APIs is made, the DLL gets loaded into process's
address space. When my proces terminates DLL still remains loaded in to the
memory. It creates problems when next time the process send calls to it.
Is there any way to unlod the DLLs, that are loaded this way?

Regards
Shahzad
Klaus H. Probst - 27 Sep 2003 09:29 GMT
DLLs can't just sit there in memory by themselves. They have to be attached
to a process. So either your process is really not terminating or another
one is loading the DLL. Have you tried putting some tracing code in DllMain
as the module is attached and detached?

Signature

____________________
Klaus H. Probst, MVP
  http://www.vbbox.com/

Please post/reply to the newsgroup(s)

> Hi,
>
[quoted text clipped - 8 lines]
> Regards
> Shahzad
Mohammad Shahzad Saleem - 27 Sep 2003 19:38 GMT
the dll gets loaded properly and in DllMain module is properly attaching and
detaching.
I give you an example to explain my problem. I have a function "DllFunc" in
the export list of my dll. I am calling this function by not getting its
procedure address. I just call this function by declaring like way....
Declare Function DllFunc Lib "MyDll.dll" () As Integer
when this function called the dll automatically get loaded. When i close the
process that made this call. The dll still remains loaded into the memory. I
dont want that dll to remain in memory, I want to unload it. So that next
time when it is loaded it may reinitialized. I am sure the dlls geting
loaded this way are different than the dll who got loaded by LoadLibrary.

Regards
Shahzad

> DLLs can't just sit there in memory by themselves. They have to be attached
> to a process. So either your process is really not terminating or another
[quoted text clipped - 13 lines]
> > Regards
> > Shahzad
Tom Esh - 29 Sep 2003 08:53 GMT
>the dll gets loaded properly and in DllMain module is properly attaching and
>detaching.
[quoted text clipped - 7 lines]
>time when it is loaded it may reinitialized. I am sure the dlls geting
>loaded this way are different than the dll who got loaded by LoadLibrary.

For declared functions VB loads the library dll the first time you
call the function in code and unloads it when the app terminates. In
order to manually load and unload the library and prevent VB from
doing its automatic thing, you would need to invoke the dll function
purely by it's loaded address and ~not~ use a declare statement.
Unfortunately neither VB nor the Api provides a means to do so
directly. However ~if~ (and only if) your dll function takes exactly 4
32-bit arguments and returns a 32-bit type, you can "cheat" and use
CallWindowProc, which does accept an address. (Note if the dll
function does not fit those requirements exactly, you'll hose the
stack and probably crash the app.) So for example if your dll (MyDll)
exports a function called MyFunction that fits the requirements:

Dim hLib As Long, lpFnAddress As Long, lRet As Long

hLib = LoadLibrary("MyDll")
If hLib <> 0 Then
    lpFnAddress = GetProcessAddress(hLib, "MyFunction")
    If lpFnAddress <> 0 Then
        lRet = CallWindowProc(lpFnAddress, Arg1, Arg2, Arg3, Arg4)
    End If
    FreeLibrary hLib
End If

Otherwise you may want to pick up a copy of Matt Curland's book
("Advanced VB"). He details a more robust (and complex) method of
handling just about any dll function calls without declares.

-Tom
MVP - Visual Basic
(please post replies to the newsgroup)
Michael Culley - 30 Sep 2003 01:57 GMT
The code below can be used to call any dll function. It can be used for a few other calls as well so is longer than it needs to be
just to call a dll. Paste it into a class and rename it CallPtr (or anything you prefer)

--
Michael Culley

Option Explicit

Public Enum mcCallTypeEnum
   mcCallStdCall
   mcCallDeclSpec
   mcCallCOMFunction
   mcCallCOMSub
End Enum

Private mlngParameters() As Long 'list of parameters
Private mlngAddress As Long 'address of function to call
Private mbytCode() As Byte 'buffer for assembly code
Private mCallType As mcCallTypeEnum 'type of function being called
Private mlngCP As Long 'used to keep track of latest byte added to code
Private mlngCodeAddress As Long 'address of first byte in mbytCode that stores the assembly code
Private mlngObjPtr As Long 'object pointer of object containing the function (zero for non COM calls)
Private mlngReturnVal As Long 'return values used for COM calls only
Private mlngHResult As Long
Private mlngModuleId As Long

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

Public Sub LoadDLL(DLLName As String)
   UnloadDLL
   mlngModuleId = LoadLibrary(DLLName)
   If mlngModuleId = 0 Then Err.Raise vbObjectError, "clsCallFunction.LoadDLL", "Load DLL failed"
End Sub

Public Sub UnloadDLL()
   If mlngModuleId <> 0 Then
       FreeLibrary mlngModuleId
       mlngModuleId = 0
   End If
End Sub

Public Property Let ObjectPointer(ByVal NewVal As Long)
   mlngObjPtr = NewVal
End Property
Public Property Get ObjectPointer() As Long
   ObjectPointer = mlngObjPtr
End Property

Public Property Let CallType(ByVal NewVal As mcCallTypeEnum)
   mCallType = NewVal
End Property
Public Property Get CallType() As mcCallTypeEnum
   CallType = mCallType
End Property

Public Property Get HResult() As Long
   HResult = mlngHResult
End Property

Public Property Let FunctionAddress(ByVal NewVal As Long)
   mlngAddress = NewVal
End Property
Public Property Get FunctionAddress() As Long
   FunctionAddress = mlngAddress
End Property

Public Sub ClearParameters()
   ReDim mlngParameters(0)
End Sub

Public Sub AddParameter(ByVal NewVal As Long)
   Dim lngX As Long
   lngX = UBound(mlngParameters) + 1
   ReDim Preserve mlngParameters(lngX)
   mlngParameters(lngX) = NewVal
End Sub

Public Function CallFunction() As Long
   If (mCallType = mcCallCOMFunction Or mCallType = mcCallCOMSub) And mlngObjPtr = 0 Then Err.Raise vbObjectError,
"clsCallFunction.CallFunction", "Cannot call Null COM object"
   Compile
   CallFunction = CallWindowProc(mlngCodeAddress, 0, 0, 0, 0)
   If mCallType = mcCallCOMFunction Then
       mlngHResult = CallFunction
       CallFunction = mlngReturnVal
   End If
End Function

Public Function CallDLLFunctionByName(FunctionName As String) As Long
   Dim mlngProcAddress As Long
   If mlngModuleId = 0 Then Err.Raise vbObjectError, "clsCallFunction.CallDLLFunctionByName", "No Dll loaded"
   mlngProcAddress = GetProcAddress(mlngModuleId, FunctionName)
   If mlngProcAddress = 0 Then Err.Raise vbObjectError, "clsCallFunction.CallDLLFunctionByName", "Function not found"
   mlngAddress = mlngProcAddress
   CallDLLFunctionByName = CallFunction
End Function

Private Sub Compile()
   Dim lngX As Long
   ReDim mbytCode(18 + 32 + 6 * UBound(mlngParameters))
   mlngCodeAddress = GetAlignedCodeStart(VarPtr(mbytCode(0)))
   mlngCP = mlngCodeAddress - VarPtr(mbytCode(0))
   For lngX = 0 To mlngCP - 1
       mbytCode(lngX) = &HCC
   Next
   'AddByteToCode &HCC 'int 03
   AddByteToCode &H58 'pop eax
   AddByteToCode &H59 'pop ecx
   AddByteToCode &H59 'pop ecx
   AddByteToCode &H59 'pop ecx
   AddByteToCode &H59 'pop ecx
   AddByteToCode &H50 'push eax
   If mCallType = mcCallCOMFunction Then
       AddByteToCode &H68 'push wwxxyyzz
       AddLongToCode VarPtr(mlngReturnVal)
   End If
   For lngX = UBound(mlngParameters) To 1 Step -1 'push parameters from right to left
       AddByteToCode &H68 'push wwxxyyzz
       AddLongToCode mlngParameters(lngX)
   Next
   If mCallType = mcCallCOMFunction Or mCallType = mcCallCOMSub Then
       AddByteToCode &H68 'push wwxxyyzz
       AddLongToCode mlngObjPtr
   End If
   AddCallToCode mlngAddress
   If mCallType = mcCallDeclSpec Then
       For lngX = 1 To UBound(mlngParameters)
           AddByteToCode &H59 'pop ecx
       Next
   End If
   AddByteToCode &HC3
   AddByteToCode &HCC

   'Assembler:
   '58                 pop     eax         'pop return address
   '59                 pop     ecx         'kill hwnd
   '59                 pop     ecx         'kill msg
   '59                 pop     ecx         'kill wParam
   '59                 pop     ecx         'kill lParam
   '50                 push    eax         'put back return address
   '68 zz yy xx ww     push    wwxxyyzz    'if COM call, push a pointer to a variable to be used as a return value

   '68 zz yy xx ww     push    wwxxyyzz    'once for each parameter, in reverse order

   '68 zz yy xx ww     push    wwxxyyzz    'if COM call, push Object Pointer to object being called
   'E8 zz yy xx ww     call    wwxxyyzz    'call function

   '59                 pop     ecx         'if DeclSpec call, parameters must be removed

   'C3                 ret
End Sub

Private Sub AddCallToCode(lngAddress As Long)
   AddByteToCode &HE8
   AddLongToCode lngAddress - VarPtr(mbytCode(mlngCP)) - 4
End Sub

Private Sub AddJumpToCode(lngAddress As Long)
   AddByteToCode &HE9
   AddLongToCode lngAddress - VarPtr(mbytCode(mlngCP)) - 4
End Sub

Private Sub AddLongToCode(lng As Long)
   Dim intX As Integer
   Dim byt(3) As Byte
   CopyMemory byt(0), lng, 4
   For intX = 0 To 3
       AddByteToCode byt(intX)
   Next
End Sub

Private Sub AddByteToCode(byt As Byte)
   mbytCode(mlngCP) = byt
   mlngCP = mlngCP + 1
End Sub

Private Function GetAlignedCodeStart(lngAddress As Long) As Long
   'align to 16 byte boundary for speed
   GetAlignedCodeStart = lngAddress + (15 - (lngAddress - 1) Mod 16)
   If (15 - (lngAddress - 1) Mod 16) = 0 Then GetAlignedCodeStart = GetAlignedCodeStart + 16
End Function

Private Sub Class_Initialize()
   ReDim mlngParameters(0)
   ReDim mbytCode(0)
End Sub

Private Sub Class_Terminate()
   UnloadDLL
End Sub
Sin - 29 Sep 2003 16:04 GMT
VB is a bit messed up when it comes to DLLs. If you run an app from the IDE
for example, it will often keep a hold of the DLL even once the program has
terminated, since it's running inside the IDE (ie : VB loaded it, not your
program). This is a old bug and you have to learn to live with it.

Alex.
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.