Jump to content

[SOLVED] to DLLopen or not ( as in "to be or not to be")


Recommended Posts

From the manual: "DllOpenOpens a DLL file for use in DllCall." But I see everywhere in the distribution UDFs, no use of it for DllCall().

In the manual, the example is:

Local $hDLL = DllOpen("user32.dll")
DllCall($hDLL, "int", "MessageBox", "hwnd", 0, "str", "Some text", "str", "Some title", "int", 0)
DllClose($hDLL)

but what I actually see is the UDFs, is more along the lines of:

; Calling the MessageBox API directly.
DllCall("user32.dll", "int", "MessageBox", _
        "hwnd", 0, _ ; Handle to the parent window
        "str", "Some text", _ ; The text of the message box
        "str", "Some title", _ ; The title of the message box
        "int", 0) ; Flags for the message box.


So, "to DllOpen or not to DllOpen, that is the question."

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

It's a bit like FileWrite, where you can use the filename or a handle you open with FileOpen beforehand. If your call is a one-off then it's overkill to get a handle for it, call it, then close it again. But if you're going to be accessing the dll dozens or hundreds (millions?) of times in your code, it's faster to get a handle once and use that while you need the dll, then close it once.^_^ And of course, the UDFs are mostly single call affairs (GDI+ is an exception), so the only way to ensure the handle gets closed (no memory leak) is to open and close it directly per UDF call.

Edited by RTFC
Link to comment
Share on other sites

2 minutes ago, RTFC said:

if you're going to be accessing the dll dozens or hundreds (millions?) of times

..yes, I see no time difference between one way or the other.
I the DllCall remark is : If a dll filename is given then the DLL is automatically loaded and then closed at the end of the call. If you want to manually control the loading and unloading of the DLL then you should use DllOpen() and DllClose() and use a handle instead of a filename in this function.

I came to this question while looking at <Date.au3> and the question popped into my head: why is this not with a handle to "kernel32.dll" as is constantly called. =/

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

1) The dll itself may already be in virtual memory due to earlier calls (and you'd probably need heavy-duty benchmarking to perceive a notable difference anyhow)

2) avoid memory leaks due to dangling handles

Edited by RTFC
Link to comment
Share on other sites

25 minutes ago, RTFC said:

1) The dll itself may already be in virtual memory due to earlier calls

So AutoIt loads the DLL when first called, and closes it when the program/script closes ?

Maybe system DLLs ( those in use since Win95 ) are accounted for within AutoIt but otherwise it'd be good to Open and close manually ?

Or there are types of DLLs, like those used for GDI+, that need the Open/Close functionality due to the "type" of DLL, and I say "type" with quote marks because, I don't know much, other than to script ( somewhat ) if there is a UDF already in place :)

Edited by argumentum
clarify

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

you missed the more important #2. He suggests closing handles you open. This is the best practice, now and forever, you can sing that like at church.....

in unmanaged  code, you had darned well better clean up after yourself. With .NET managed stuff, it does the garbage cleanup for you, but if you are allocating memory and resources, you should free it when you exit or don't need it anymore

 

https://www.autoitscript.com/autoit3/docs/functions/DllClose.htm

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Link to comment
Share on other sites

14 minutes ago, Earthshine said:

you missed the more important #2. He suggests closing handles you open

AutoIt closes those DLLs ( on exit or right after the call, no clue yet ), BUT there are those that need to be handled manually like GDI or Richedit. My question is when and why use DllOpen() or when is just impractical.
 

16 minutes ago, Earthshine said:

in unmanaged  code, you had darned well better clean up after yourself

I know that I should always clean after myself. My mother told me that, and my father reinforced the knowledge with his slipper shoes :P 

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

  • Developers
11 minutes ago, argumentum said:

My question is when and why use DllOpen() or when is just impractical.

Thought that question was answered already by @RTFC. When you use DllCall() with a filename, AutoIt3 will perform DllOpen();DllCall();DllCLose() for you.
This is fine when doing a single DllCall, but when you want to do a thousand DllCall as fast as possible you can imagine it is faster to one DllOpen() at the beginning, then do all the DllCall's using the openen filehandle and then close it.....   right?

Same counts for FileRead/FileWrite operations.

Jos

Edited by Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

10 minutes ago, Jos said:

but when you want to do a thousand DllCall as fast as possible you can imagine it is faster to one DllOpen()

well, not that noticeable:

Global $kernel32dll = DllOpen("kernel32.dll")
OnAutoItExitRegister("closeDlls")
Func closeDlls()
    DllClose($kernel32dll)
EndFunc   ;==>closeDlls
Local $times[4][2000]
$count = 1
$times[0][0] = 0
$lastcount = -9
$tt = TimerInit()
While $count < 2000
    $times[0][$count] = TimerDiff($tt)
    $times[1][$count] = _MSec()             ; AutoIt Open/Close DLL
;~  $times[1][$count] = _MSec($kernel32dll) ; managed Open/Close DLL
    $times[2][$count] = @error
    $times[3][$count] = @extended
    If $times[0][$count] <> $times[0][$count - 1] Then $count += 1
WEnd
For $i = 1 To $count - 1
    If $times[1][$i] = $times[1][$i - 1] Then ContinueLoop
    ConsoleWrite('TimerDiff, ' & $i & ' @MSEC = ' & StringFormat("%5.5f, %d", $times[0][$i], $times[1][$i]) & " - " & $times[2][$i] & "," & $times[3][$i] & @CRLF) ;### Debug Console
Next
ConsoleWrite('TimerDiff, ' & $count - 1 & ' @MSEC = ' & StringFormat("%5.5f, %d", $times[0][$count - 1], $times[1][$count - 1]) & @CRLF) ;### Debug Console
Exit

Func _MSec($kernel32dll = "kernel32.dll")
    Local $stSystemTime = DllStructCreate("ushort varYear;ushort varMon;ushort varDofW;ushort varDay;ushort varHour;ushort varMin;ushort varSec;ushort varMsec")
    DllCall($kernel32dll, 'none', 'GetSystemTime', 'ptr', DllStructGetPtr($stSystemTime)) ; UTC time
    Return SetError(@error, @extended, StringFormat('%03d', DllStructGetData($stSystemTime, 8)))
EndFunc   ;==>_MSec

that is why I'm posting the question.   

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

  • Developers

I've stated what needed to be stated on the matter and when you don't notice the difference then do as you please. ;)

Jos

SciTE4AutoIt3 Full installer Download page   - Beta files       Read before posting     How to post scriptsource   Forum etiquette  Forum Rules 
 
Live for the present,
Dream of the future,
Learn from the past.
  :)

Link to comment
Share on other sites

1 hour ago, Jos said:

then do as you please

Don't get me wrong. There is a difference of some porcentage* and yes, it is faster to do the DllOpen. The question is a bit deeper. The <Date.au3> does not use DllOpen()  - I was looking at that when my question popped up - and it, in my view, should use it, then again, is impractical for a call or 2 the user would make, to handle the "IsItLoaded" and when to close it. So I was looking for a deeper explanation to, when and why, other than "you can go either way, just clean house once you're done". There are those DLLs that must be properly handled or the script will crash. There must be a reason.

That is all.

* PS: I added this later for anyone that in the future would like to see how much faster, tho, this should not be about speed alone.

Spoiler
Global $stSystemTime = DllStructCreate("ushort varYear;ushort varMon;ushort varDofW;ushort varDay;ushort varHour;ushort varMin;ushort varSec;ushort varMsec")
Global $kernel32dll = DllOpen("kernel32.dll")
OnAutoItExitRegister("closeDlls")
Func closeDlls()
    DllClose($kernel32dll)
EndFunc   ;==>closeDlls
Local $nLoopCount = 10000 ; <--- change this if you feel like it
Local $nTestCount = 10    ; <--- change this if you feel like it
Local $times[4][$nLoopCount]
Local $av[$nTestCount][2]
$av[0][0] = UBound($av) - 1
For $n = 1 To $av[0][0]

    $tt = TimerInit()
    For $count = 1 To $nLoopCount - 1
        $times[0][$count] = TimerDiff($tt)
        $times[1][$count] = _MSec() ; AutoIt Open/Close DLL
    Next
    $av[$n][0] = Round($times[0][$nLoopCount - 1])
    ConsoleWrite('AutoIt Open/Close DLL = TimerDiff, ' & $av[$n][0] & " .ms" & @TAB) ;### Debug Console

    $tt = TimerInit()
    For $count = 1 To $nLoopCount - 1
        $times[0][$count] = TimerDiff($tt)
        $times[1][$count] = _MSec($kernel32dll) ; managed Open/Close DLL
    Next
    $av[$n][1] = Round($times[0][$nLoopCount - 1])
    ConsoleWrite('managed Open/Close DLL = TimerDiff, ' & $av[$n][1] & " .ms ( " & Round((1 - ($av[$n][1] / $av[$n][0])) * 100) & " % faster )" & @CRLF) ;### Debug Console
Next
Exit

Func _MSec($kernel32dll = "kernel32.dll")
    DllCall($kernel32dll, 'none', 'GetSystemTime', 'ptr', DllStructGetPtr($stSystemTime)) ; UTC time
    Return SetError(@error, @extended, StringFormat('%03d', DllStructGetData($stSystemTime, 8)))
EndFunc   ;==>_MSec

 

 

Edited by argumentum
added test bed

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

31 minutes ago, argumentum said:

AutoIt closes those DLLs ( on exit or right after the call

If called with the filename, the dll is closed immediately after the call; if called with the earlier obtained handle it stays open until closed by the user or AFAIK upon normal script termination (although this is sloppy practice ,and you shouldn't rely on it). However, in case of abnormal termination/crash, you may have a memory leak.

34 minutes ago, argumentum said:

there are those that need to be handled manually like GDI

I would suggest you call the GDI Startup function (because there are version-specific settings involved) rather than opening that dll directly. But in general, any dll can be opened and closed on a call-by-call basis using the filename or user-opened and closed separately. Regarding filename-based calls in the standard includes such as <Date.au3>, remember that these UDFs are meant to function on their own, without users needing to be aware of handles to be obtained first or closed after. So by sacrificing a little processing speed, calling a dll function can be made a single action, which makes the task much easier for beginners, and more empowering.:)

58 minutes ago, argumentum said:

my father reinforced the knowledge with his slipper shoes

:blink: Well, I guess you'll have to be thankful he didn't have mountaineering boots with ice crampons close to hand.:D

Link to comment
Share on other sites

Think mega thousands of calls. It makes a diff. Everyone starts as a beginner but you can’t be a beginner forever you need to learn how to program correctly

Many many years ago I read a book called writing structured basic and it changed my life

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Link to comment
Share on other sites

27 minutes ago, Earthshine said:

Many many years ago I read a book called writing structured basic

I started with basic on an Apple II back in 1984. After that I studied microprocessors (1985), Then quit, whent fix planes.
then years later started with TPascal 5.5. I have an idea. Picked up coding back in 2005 looked at Delphi ...but i found AutoIt.
I should have opened this topic in a chat forum but I did it here. Is not help I wanted, but educated views on why, how, etc.
@RTFC answered the question. Repeatedly. 
I was looking for ... go figure, clarification on why the UDF was written as such.
Thank you @Earthshine for your participation.
And since i'm in a thank you letter, thanks @Jos for your input, I added a piece of code to show the speed gain ( %5 on average in my test PC ).
I'm happy :)

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

9 hours ago, argumentum said:

Is not help I wanted, but educated views on why, how, etc.

I never had you pegged as a beginner, argumentum, and I reckon you posed an interesting, valid question (definitely not mere chat). Investigating and questioning(!) the source code is a good way of gaining a deeper understanding; I try to get a peek under the hood myself when I get the chance. So don't put yourself down, okay?:)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...