Sign in to follow this  
Followers 0
Kip

Dll Call like C++

27 posts in this topic

#1 ·  Posted (edited)

Hi,

I saw this very old post by JPM, about a different kind of DllCall.

Jon didnt want to do it, so I did. :P

It's only one function but thats enough :(

_DllCall($vDll, $sFormat, $vParam1, $vParam2, $vParam3, .......)

Example + Function:

CODE

Global Const $DLL_MESSAGEBOX = "int MessageBox(hwnd handle, str text, str caption, uint type)"

Global Const $DLL_BEEP = "int Beep(int frequency, int duration)"

_DllCall("User32.dll", $DLL_MESSAGEBOX, 0, "Message", "Title", 0)

_DllCall("Kernel32.dll", $DLL_BEEP, 500, 2000)

; _DllCall by Kip

Func _DllCall($vDll, $sFormat, $vParam1=0, $vParam2=0, $vParam3=0, $vParam4=0, $vParam5=0, $vParam6=0, $vParam7=0, $vParam8=0, $vParam9=0, $vParam10=0, $vParam11=0 _

, $vParam12=0, $vParam13=0, $vParam14=0, $vParam15=0, $vParam16=0, $vParam17=0, $vParam18=0, $vParam19=0, $vParam20=0, $vParam21=0, $vParam22=0, $vParam23=0, $vParam24=0 _

, $vParam25=0, $vParam26=0, $vParam27=0, $vParam28=0, $vParam29=0, $vParam30=0, $vParam31=0, $vParam32=0)

$iParams = @NumParams-2

If not $sFormat Then Return

$sFunction = StringLeft($sFormat, StringInStr($sFormat,"(")-1)

$aFunctionSplit = StringSplit($sFunction," ")

Local $sReturnType

Local $sFunctionName

For $i = 1 to $aFunctionSplit[0]

If $aFunctionSplit[$i] Then

If Not $sFunctionName Then

$sFunctionName = $aFunctionSplit[$i]

Else

$sReturnType = $sFunctionName

$sFunctionName = $aFunctionSplit[$i]

ExitLoop

EndIf

EndIf

Next

If Not $sFunctionName Then Return

If Not $sReturnType Then $sReturnType = "int"

$iStart = StringInStr($sFormat,"(")

$iEnd = StringInStr($sFormat,")")

$sParams = StringMid($sFormat,$iStart+1,$iEnd-$iStart-1)

$aParamsSplit = StringSplit($sParams,",")

If $sParams Then

If $aParamsSplit[0] > $iParams Then

$iParams = $aParamsSplit[0]

EndIf

EndIf

Local $aParameters[$iParams+1][2]

For $i = 1 to $aParamsSplit[0]

$aParamSplit = StringSplit($aParamsSplit[$i]," ")

For $j = 1 to $aParamSplit[0]

If $aParamSplit[$j] Then

$aParameters[$i][0] = $aParamSplit[$j]

ExitLoop

EndIf

Next

Next

If $iParams > 32 Then Return

Local $sFinal

For $i = 1 to $iParams

If Not $aParameters[$i][0] Then Return

$aParameters[$i][1] = Execute("$vParam"&$i)

If IsString($aParameters[$i][1]) Then

$aParameters[$i][1] = StringReplace($aParameters[$i][1],'"','""')

$aParameters[$i][1] = '"'&$aParameters[$i][1]&'"'

EndIf

$sFinal &= ',"'&$aParameters[$i][0]&'",'&$aParameters[$i][1]

Next

If IsString($vDll) Then

$vDll = StringReplace($vDll,'"','""')

$vDll = '"'&$vDll&'"'

EndIf

$sFinal = "DllCall("&$vDll&',"'&$sReturnType&'", "'&$sFunctionName&'"'&$sFinal&")"

Return Execute($sFinal)

EndFunc

Now you just can copy and paste the syntax of a dll function from MSDN. (You'll still have to change the datatypes though)

Edited by Kip

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

This is really great. I think it will help a lot of people to get them selfs familiar with dll calling (like I would know :P ).

Conversions from windows api types to AutoIt types are needed in order to function more properly, I think.

Edited by trancexx

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Cool idea. One change -

Local $ret = Execute($sFinal)
Return $ret[0]
Edited by wraithdu

Share this post


Link to post
Share on other sites

Nice idea. :P


When the words fail... music speaks

Share this post


Link to post
Share on other sites

Cool idea. One change -

Local $ret = Execute($sFinal)
Return $ret[0]
I don't get this :P

♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Kip, can't you do it without Execute?

No :(

Cool idea. One change -

Local $ret = Execute($sFinal)
 Return $ret[0]
Bad idea. :P Edited by Kip

Share this post


Link to post
Share on other sites

No :P

I'm rewriting this for performance. I hope you don't mind.

Also, there's a bug in your code:

DllCall(user32.dll,"int", "MessageBox","hwnd",0,"str","Message","str","Title","uint",0)

DllCall(kernel32.dll,"int", "Beep","int",500,"int",2000)

DLL's are not included in " ".

Share this post


Link to post
Share on other sites

yes they are:

$vDll = '"'&$vDll&'"' ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< HERE!

EndIf

$sFinal = "DllCall("&$vDll&',"'&$sReturnType&'", "'&$sFunctionName&'"'&$sFinal&")"

Return Execute($sFinal)

Share this post


Link to post
Share on other sites

#12 ·  Posted (edited)

Rewritten completely. I'm about to do some speed tests, it should be a lot faster. I'll keep you posted.

Global $mDllLib[1][4]

Global Const $DLL_MESSAGEBOX = _DllDefine("user32.dll", "int MessageBox(hwnd handle, str text, str caption, uint type)")
Global Const $DLL_BEEP = _DllDefine("kernel32.dll", "int Beep(int frequency, int duration)")


_DllCall($DLL_MESSAGEBOX, 0, "AutoIt Rocks", "Manadar says hi!", 0)
_DllCall($DLL_BEEP,500,100)

; DllCall rewritten for performance by Manadar
; UDF Starts here:

;Global $mDllLib[1][4] ;; UNCOMMENT THIS LINE IF YOU ARE MOVING THIS CODE INTO A SEPERATE FILE

#include <Array.au3>

Func _DllDefine($pDll, $pString)
    $lDim = UBound($mDllLib,1)
    ReDim $mDllLib[$lDim+1][4]
    
    If (IsString($pDll)) Then
        $mDllLib[$lDim][0] = DllOpen($pDll)
        If @error Then
            Return @error
        EndIf
    Else
        $mDllLib[$lDim][0] = $pDll
    EndIf
    
    $lSplit = StringSplit($pString, " (),",0)
    
    $mDllLib[$lDim][1] = $lSplit[1] ; return type
    $mDllLib[$lDim][2] = $lSplit[2] ; functions
    
    Dim $n = 0 ; Creates an array with parameter types
    Dim $lParams[1]
    For $i = 3 to $lSplit[0] Step 3
        $n += 1
        ReDim $lParams[$n+1]
        $lParams[$n] = $lSplit[$i]
    Next
    
    $mDllLib[$lDim][3] = $lParams
    
    Return $lDim
EndFunc

Func _DllCall($pID, $vParam1 = 0, $vParam2 = 0, $vParam3 = 0, $vParam4 = 0, $vParam5 = 0, $vParam6 = 0, $vParam7 = 0, $vParam8 = 0, $vParam9 = 0, $vParam10 = 0, $vParam11 = 0 _
        , $vParam12 = 0, $vParam13 = 0, $vParam14 = 0, $vParam15 = 0, $vParam16 = 0, $vParam17 = 0, $vParam18 = 0, $vParam19 = 0, $vParam20 = 0, $vParam21 = 0, $vParam22 = 0, $vParam23 = 0, $vParam24 = 0 _
        , $vParam25 = 0, $vParam26 = 0, $vParam27 = 0, $vParam28 = 0, $vParam29 = 0, $vParam30 = 0, $vParam31 = 0, $vParam32 = 0)
    $lParams = $mDllLib[$pID][3]
    Switch UBound($lParams)-1
        Case 0
            Return DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2])
        Case 1
            Return DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1)
        Case 2
            Return DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2)
        Case 3
            Return DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2,$lParams[3],$vParam3)
        Case 4
            Return DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2,$lParams[3],$vParam3,$lParams[4],$vParam4)
        Case 5
            Return DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2,$lParams[3],$vParam3,$lParams[4],$vParam4,$lParams[5],$vParam5)
        ; I got bored doing this. Someone continue it please. 
        Case Else
            SetError(1)
            return 0
    EndSwitch
EndFunc
Edited by Manadar

Share this post


Link to post
Share on other sites

Try for yourself. The speed difference isn't all that: 10 functions take 1 ms longer. I've written this without Execute though, which is a plus for me. :P

Global $mDllLib[1][4]

Global Const $MANADAR_DLL_BEEP = _DllDefine("kernel32.dll", "int Beep(int frequency, int duration)")
Global Const $KIP_DLL_BEEP = "int Beep(int frequency, int duration)"

$MANADAR_START = TimerInit()
For $i = 0 to 9
    _DllCall($MANADAR_DLL_BEEP,500,100)
Next
$MANADAR_DURATION = TimerDiff($MANADAR_START)

$KIP_START = TimerInit()
For $i = 0 to 9
    _Old_DllCall("Kernel32.dll", $KIP_DLL_BEEP, 500, 100)
Next
$KIP_DURATION = TimerDiff($KIP_START)

MsgBox(0, "", "Time it took for Manadars DllCall: " & $MANADAR_DURATION & @CRLF & _
"Time it took for Kips DllCall: " & $KIP_DURATION)

; DllCall rewritten for performance by Manadar
; UDF Starts here:

;Global $mDllLib[1][4] ;; UNCOMMENT THIS LINE IF YOU ARE MOVING THIS CODE INTO A SEPERATE FILE

#include <Array.au3>

Func _DllDefine($pDll, $pString)
    $lDim = UBound($mDllLib,1)
    ReDim $mDllLib[$lDim+1][4]
    
    If (IsString($pDll)) Then
        $mDllLib[$lDim][0] = DllOpen($pDll)
        If @error Then
            Return @error
        EndIf
    Else
        $mDllLib[$lDim][0] = $pDll
    EndIf
    
    $lSplit = StringSplit($pString, " (),",0)
    
    $mDllLib[$lDim][1] = $lSplit[1] ; return type
    $mDllLib[$lDim][2] = $lSplit[2] ; functions
    
    Dim $n = 0 ; Creates an array with parameter types
    Dim $lParams[1]
    For $i = 3 to $lSplit[0] Step 3
        $n += 1
        ReDim $lParams[$n+1]
        $lParams[$n] = $lSplit[$i]
    Next
    
    $mDllLib[$lDim][3] = $lParams
    
    Return $lDim
EndFunc

Func _DllCall($pID, $vParam1 = 0, $vParam2 = 0, $vParam3 = 0, $vParam4 = 0, $vParam5 = 0, $vParam6 = 0, $vParam7 = 0, $vParam8 = 0, $vParam9 = 0, $vParam10 = 0, $vParam11 = 0 _
        , $vParam12 = 0, $vParam13 = 0, $vParam14 = 0, $vParam15 = 0, $vParam16 = 0, $vParam17 = 0, $vParam18 = 0, $vParam19 = 0, $vParam20 = 0, $vParam21 = 0, $vParam22 = 0, $vParam23 = 0, $vParam24 = 0 _
        , $vParam25 = 0, $vParam26 = 0, $vParam27 = 0, $vParam28 = 0, $vParam29 = 0, $vParam30 = 0, $vParam31 = 0, $vParam32 = 0)
    $lParams = $mDllLib[$pID][3]
    Switch UBound($lParams)-1
        Case 0
            DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2])
        Case 1
            DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1)
        Case 2
            DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2)
        Case 3
            DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2,$lParams[3],$vParam3)
        Case 4
            DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2,$lParams[3],$vParam3,$lParams[4],$vParam4)
        Case 5
            DllCall($mDllLib[$pID][0],$mDllLib[$pID][1],$mDllLib[$pID][2],$lParams[1],$vParam1,$lParams[2],$vParam2,$lParams[3],$vParam3,$lParams[4],$vParam4,$lParams[5],$vParam5)
        ; I got bored doing this. Someone continue it please. :P
        Case Else
            SetError(1)
            return 0
    EndSwitch
EndFunc

; _DllCall by Kip

Func _Old_DllCall($vDll, $sFormat, $vParam1=0, $vParam2=0, $vParam3=0, $vParam4=0, $vParam5=0, $vParam6=0, $vParam7=0, $vParam8=0, $vParam9=0, $vParam10=0, $vParam11=0 _
, $vParam12=0, $vParam13=0, $vParam14=0, $vParam15=0, $vParam16=0, $vParam17=0, $vParam18=0, $vParam19=0, $vParam20=0, $vParam21=0, $vParam22=0, $vParam23=0, $vParam24=0 _
, $vParam25=0, $vParam26=0, $vParam27=0, $vParam28=0, $vParam29=0, $vParam30=0, $vParam31=0, $vParam32=0)

$iParams = @NumParams-2

If not $sFormat Then Return

$sFunction = StringLeft($sFormat, StringInStr($sFormat,"(")-1)

$aFunctionSplit = StringSplit($sFunction," ")

Local $sReturnType
Local $sFunctionName

For $i = 1 to $aFunctionSplit[0]

If $aFunctionSplit[$i] Then

If Not $sFunctionName Then

$sFunctionName = $aFunctionSplit[$i]

Else

$sReturnType = $sFunctionName
$sFunctionName = $aFunctionSplit[$i]

ExitLoop

EndIf

EndIf

Next

If Not $sFunctionName Then Return
If Not $sReturnType Then $sReturnType = "int"

$iStart = StringInStr($sFormat,"(")
$iEnd = StringInStr($sFormat,")")

$sParams = StringMid($sFormat,$iStart+1,$iEnd-$iStart-1)

$aParamsSplit = StringSplit($sParams,",")
If $sParams Then

If $aParamsSplit[0] > $iParams Then
$iParams = $aParamsSplit[0]
EndIf

EndIf

Local $aParameters[$iParams+1][2]

For $i = 1 to $aParamsSplit[0]

$aParamSplit = StringSplit($aParamsSplit[$i]," ")

For $j = 1 to $aParamSplit[0]

If $aParamSplit[$j] Then
$aParameters[$i][0] = $aParamSplit[$j]

ExitLoop
EndIf

Next

Next

If $iParams > 32 Then Return

Local $sFinal

For $i = 1 to $iParams

If Not $aParameters[$i][0] Then Return

$aParameters[$i][1] = Execute("$vParam"&$i)

If IsString($aParameters[$i][1]) Then
$aParameters[$i][1] = StringReplace($aParameters[$i][1],'"','""')
$aParameters[$i][1] = '"'&$aParameters[$i][1]&'"'
EndIf

$sFinal &= ',"'&$aParameters[$i][0]&'",'&$aParameters[$i][1]

Next

If IsString($vDll) Then
$vDll = StringReplace($vDll,'"','""')
$vDll = '"'&$vDll&'"'
EndIf

$sFinal = "DllCall("&$vDll&',"'&$sReturnType&'", "'&$sFunctionName&'"'&$sFinal&")"

Return Execute($sFinal)

EndFunc

Share this post


Link to post
Share on other sites

#14 ·  Posted (edited)

I've written this without Execute though, which is a plus for me. :P

Just curious, what is wrong with "Execute"?

Thanks,

Bob

Edited by YellowLab

You can't see a rainbow without first experiencing the rain.

Share this post


Link to post
Share on other sites

Because Manadar does things like this

Posted Image

Share this post


Link to post
Share on other sites

Now you just can copy and paste the syntax of a dll function from MSDN.

This is simply not true. Anything that takes a string will not work. Anything that uses a structure will not work. Those two aspects alone comprise the majority of the functions in the Windows API. Anything that uses a BOOL will not work since that is also an invalid type.

Just curious, what is wrong with "Execute"?

In this case there's nothing wrong with using it. In fact this is one of only a handful of actual, legitimate uses for Execute(). The problem Execute() solves in this case is it allows a built-in function to be called with a specific number of parameters not known until run-time. Mandar's solution, while avoiding Execute() arbitrarily enforces a limit to the number of parameters that can be passed to DllCall() effectively eliminating the wrapper function's usefulnesson the more complex API calls.

Share this post


Link to post
Share on other sites

#17 ·  Posted (edited)

Just curious, what is wrong with "Execute"?

Without going into discussion it is often considered as "bad programming practice" to use Execute, and as such I try to avoid it always.

There's not a real topic yet defining why Execute is bad, but we (AutoIt forum and members) have had the discussion many times. I guess we could move the question here: http://www.autoitscript.com/forum/index.php?showtopic=49064 and look for a better explanation.

Edit: Never mind. Valik already started.

Edited by Manadar

Share this post


Link to post
Share on other sites

Oh, and for the sake of clarification, I didn't mean that Manadar is a turtle who has sex with other turtles. I meant that he makes images like that (as you can see by it being hosted on his website).

Share this post


Link to post
Share on other sites

#19 ·  Posted (edited)

This is simply not true.

I know, you still have to edit some minor stuff, but it is easier.

Edit: Edited first post

Edited by Kip

Share this post


Link to post
Share on other sites

If editing things to make it work at all is minor in your book then I really would like to know what you consider major.

Share this post


Link to post
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
Sign in to follow this  
Followers 0