Jump to content

Dll Call like C++


Kip
 Share

Recommended Posts

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
Link to comment
Share on other sites

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

Link to comment
Share on other sites

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
Link to comment
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
Link to comment
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.
Link to comment
Share on other sites

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
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

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...