Author Topic: LoadLibrary, GetProcAddress, FreeLibrary  (Read 18836 times)

dedndave

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #15 on: November 07, 2015, 04:05:40 AM »
my current solution is to use this code
i am considering getting rid of the FreeLibrary call, and letting ExitProcess perform the clean-up
i have to test that strategy on a variety of OS's, though

Code: [Select]
    INVOKE  GetModuleHandleA,offset __szKernel32
    .if eax
        push    0                                   ;do not free the library handle
    .else
        INVOKE  LoadLibraryA,offset __szKernel32
        push    eax                                 ;free the library handle if non-zero
    .endif

    .if eax
        ;get proc addresses, here
    .endif

    pop     eax
    .if eax
        INVOKE  FreeLibrary,eax
    .endif

jj2007

  • Member
  • *****
  • Posts: 12944
  • Assembler is fun ;-)
    • MasmBasic
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #16 on: November 07, 2015, 05:03:15 AM »
i am considering getting rid of the FreeLibrary call, and letting ExitProcess perform the clean-up

Should work, but I still lack a good reference which types of resources (memory, gdi objects, bitmaps, DLLs, ...) are cleaned up by ExitProcess, and which aren't. Documentation is vague and sparse :(

dedndave

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #17 on: November 07, 2015, 05:08:09 AM »
it would seem logical, because the process memory is released
but - i need to devise a test of some sort to see if it works on win95, 98, 2K.....

TouEnMasm

  • Member
  • *****
  • Posts: 1804
    • EditMasm
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #18 on: November 07, 2015, 07:20:00 PM »
Fa is a musical note to play with CL

jj2007

  • Member
  • *****
  • Posts: 12944
  • Assembler is fun ;-)
    • MasmBasic
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #19 on: November 07, 2015, 07:46:31 PM »
It seems that many anwer are here:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms684232(v=vs.85).aspx

Explain where exactly these pages on "Module Information" elaborate which types of resources (memory, gdi objects, bitmaps, DLLs, ...) are cleaned up by ExitProcess, and which aren't.

Simple examples:
Quote
Because Win32 is based on Win16 there are a lot of Win16 legacy APIs that deal with window messages and the clipboard that do in fact expect HBITMAP's to be usable from multiple processes

Quote
resources managed by the Windows window manager, USER and GDI objects, that represent window elements (like windows and menus) and graphics constructs (like pens, brushes and drawing surfaces). Just like for the other resources I’ve discussed in previous posts, exhausting the various USER and GDI resource limits can lead to unpredictable behavior, including application failures and an unusable system

Released by ExitProcess, yes or no?

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 9739
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #20 on: November 07, 2015, 07:53:14 PM »
I think you can reasonably assume the ExitProcess() does what its name says, exits a process and that entails dumping all of what was loaded when it was running. The reason to use FreeLibrary() apart from the documentation recommendation is to make the exit tidy and fast. I am yet to see what the gain is in omitting FreeLibrary() when its only a simple API call.
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

sinsi

  • Guest
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #21 on: November 07, 2015, 08:03:30 PM »
Fairly straightforward  :badgrin:
Quote from: MSDN
Exiting a process causes the following:

    All of the threads in the process, except the calling thread, terminate their execution without receiving a DLL_THREAD_DETACH notification.
    The states of all of the threads terminated in step 1 become signaled.
    The entry-point functions of all loaded dynamic-link libraries (DLLs) are called with DLL_PROCESS_DETACH.
    After all attached DLLs have executed any process termination code, the ExitProcess function terminates the current process, including the calling thread.
    The state of the calling thread becomes signaled.
    All of the object handles opened by the process are closed.
    The termination status of the process changes from STILL_ACTIVE to the exit value of the process.
    The state of the process object becomes signaled, satisfying any threads that had been waiting for the process to terminate.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

jj2007

  • Member
  • *****
  • Posts: 12944
  • Assembler is fun ;-)
    • MasmBasic
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #22 on: November 07, 2015, 09:27:01 PM »
Hutch, Sinsi,

Thanks. In my own proggies, Dll & Declare perform the FreeLibrary; perhaps it's not needed... OTOH, I never indulge in DeleteObject orgies in a WM_DESTROY handler, although you may find such stuff in Windows programming tutorials.

Below a small collection of related sources.

The Old New Thing: Quick overview of how processes exit on Windows XP
3 May 2007
The kernel will close all your open handles to kernel objects. Any memory you allocated will be freed automatically when the process's address space is torn down.

ExitProcess function
6. All of the object handles opened by the process are closed.

Terminating a process has the following results:
    Any remaining threads in the process are marked for termination.
    Any resources allocated by the process are freed.
    All kernel objects are closed.
    The process code is removed from memory.
    The process exit code is set.
    The process object is signaled.

While open handles to kernel objects are closed automatically when a process terminates, the objects themselves exist until all open handles to them are closed. Therefore, an object will remain valid after a process that is using it terminates if another process has an open handle to it.


CodeGuru Alexey B
Regardless of how the process terminates, the system guarantees that all allocated memory, all User and GDI objects are freed, all open files are closed and the usage count on all kernel objects is decremented.

Mark Russinovich's Blog: Pushing the Limits of Windows: USER and GDI Objects

User Objects
With the fundamental concepts in hand, let's turn our attention first to USER objects. USER objects get their name from the fact that they represent user interface elements like desktops, windows, menus, cursors, icons, and accelerator tables (menu keyboard shortcuts). Despite the fact that USER objects are associated with a specific desktop, they must be accessible from all the desktops of a session, for example to allow a process on one desktop to register for a hotkey that can be entered on any of them. For that reason, the window manager assigns USER object identifiers that are scoped to a window station.

A basic limitation imposed by the window manager is that no process can create more than 10,000 USER objects. That limitation attempts to prevent a single process from exhausting the resources associated with USER objects, either because it’s programmed with algorithms that can create excessive number of objects or because it leaks objects by allocating them and not deleting them when it's through using them. You can easily verify this limit by running the Sysinternals Testlimit utility with the –u switch, which directs Testlimit to create as many USER objects as it can


Debugging a GDI Resource Leak

 --Definitions--

GDI Objects are resources that are managed by GDI32.DLL on behalf of an application. Some of the most common types of GDI objects are Device Contexts (DCs), Bitmaps, Brushes, Fonts, Metafiles, Pens, and Regions.  GDI Objects are stored in Kernel Memory (specifically the Paged Pool or Session Pool portions of kernel memory – more on this later).

GDI Handles are unique identifiers of a GDI Object.  Each GDI Object can have only one handle.  Each GDI Handle is process-specific (cannot be used by other processes).

The GDI Handle Table is a table (array) of GDI entries.  Each entry contains 32-bits of information about a GDI object, including the handle, the type of the object (i.e. bitmap, DC, pen, font, etc.), the process for which that handle is valid, and a pointer to the actual GDI object in Kernel Memory. This table exists in User Memory.

dedndave

  • Member
  • *****
  • Posts: 8828
  • Still using Abacus 2.0
    • DednDave
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #23 on: November 07, 2015, 10:11:45 PM »
and, yet, it's not hard to get a memory leak
seems to me that everything documented is not always closed
and, it is likely to be an OS version sensitive issue


I am yet to see what the gain is in omitting FreeLibrary() when its only a simple API call.

well - i write a library function that gets the proc address for some function the first time it's used
i can provide a special exit clean-up routine, but there's no guarantee that the user calls it before exit

let me cite a specific example
GlobalMemoryStatusEx is not supported by earlier OS versions
so - the library function that calls it tries to initialize the address via GetProcAddress
this is better than calling it directly, causing it to crash on older OS's
in the event that it is not supported, the routine can fall back to GlobalMemoryStatus (no Ex)

however, if i have to use LoadLibrary to ensure that Kernel32.dll is loaded,
i have incremented the reference count on that module

when it comes time to exit, the user must call a library function to decrement the count (FreeLibrary call)
if the user omits that call - what happens ?
it would be nice to eliminate that requirement by some sort of trickery
well - as we've discussed before, GetModuleHandle does not increment the reference count
but, Hutch claims it may not be safe to assume that Kernel32 is always loaded

hutch--

  • Administrator
  • Member
  • ******
  • Posts: 9739
  • Mnemonic Driven API Grinder
    • The MASM32 SDK
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #24 on: November 08, 2015, 12:41:43 AM »
> but, Hutch claims it may not be safe to assume that Kernel32 is always loaded

No, I have made the point that you risk unreliable results in other OS versions if you don't clean up correctly. If you load a library, you free it after, whether the procedure exists or not, it really that simple.

In sequence,

LoadLibrary()         ; load the library address
GetProcAddress(), ; whoops, the function does not exist
FreeLibrary()          ; you have still loaded the library.

Try this.

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    .data?
      pMessageBox dd ?
      pDudFunction dd ?

    .data
      titl db "Msgbox Call",0
      tmsg db "Howdy from the MessageBox address",0

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    call main

    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL pKernel :DWORD
    LOCAL pUser   :DWORD

    fn LoadLibrary,"user32.dll"
    mov pUser, eax

    fn GetProcAddress,pUser,"MessageBoxA"
    mov pMessageBox, eax

    fn FreeLibrary, pUser

    push 0
    push OFFSET titl
    push OFFSET tmsg
    push 0
    call pMessageBox

    fn LoadLibrary,"kernel32.dll"
    mov pKernel, eax
    fn GetProcAddress,pKernel,"DudFunction"
    .if eax == 0
      fn MessageBox,0,"Sorry Cannot find that function",str$(eax),MB_OK
    .endif

    fn FreeLibrary, pKernel
  ; ----------------------------------------------------
  ; non zero means the FreeLibrary call worked correctly
  ; ----------------------------------------------------
    fn MessageBox,0,str$(eax),"FreeLibrary return value",MB_OK

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start
hutch at movsd dot com
http://www.masm32.com    :biggrin:  :skrewy:

nidud

  • Member
  • *****
  • Posts: 2388
    • https://github.com/nidud/asmc
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #25 on: November 08, 2015, 01:22:08 AM »
deleted
« Last Edit: February 25, 2022, 11:01:05 AM by nidud »

TWell

  • Member
  • ****
  • Posts: 743
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #26 on: November 08, 2015, 02:07:24 AM »
Dilemma
If someone use GetProcAddress , kernel32.dll is already loaded ;)
So other functions from kernel32.dll are available too? GetModuleHandleA is enough?

jj2007

  • Member
  • *****
  • Posts: 12944
  • Assembler is fun ;-)
    • MasmBasic
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #27 on: November 08, 2015, 02:31:39 AM »
Dilemma
If someone use GetProcAddress , kernel32.dll is already loaded ;)
So other functions from kernel32.dll are available too? GetModuleHandleA is enough?

Who knows?

Code: [Select]
include \masm32\include\masm32rt.inc

.code
start:
  mov esi, rv(GetProcAddress, rv(GetModuleHandle, "Kernel32"), "CreateFileA")
  print LastError$()
  inkey hex$(esi)
  exit

end start

Adamanteus

  • Member
  • **
  • Posts: 249
    • LLC "AMS"
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #28 on: November 08, 2015, 03:12:39 AM »
 The imported libraries in exe header, makes library loaded during program execution - so need count also this.

nidud

  • Member
  • *****
  • Posts: 2388
    • https://github.com/nidud/asmc
Re: LoadLibrary, GetProcAddress, FreeLibrary
« Reply #29 on: November 08, 2015, 03:27:15 AM »
deleted
« Last Edit: February 25, 2022, 11:01:16 AM by nidud »