Jump to content
Leo1906

Help with DLLStruct and DLLCall

Recommended Posts

Hello Guys,

once aggain I need your help on a DLL Topic :)

I need to pass arguments to my function via a structure, because I am limited to only one argument that can be passed.
But I don't think that thats so important.

So here's my approach:

C++ Code (just the important part):

extern "C"
{

    struct ParamStruct
    {
        const char* test1;
        const char* test2;
        const char* test3;
        int size;
    };

    int testFunc(struct ParamStruct * params)
    {   
        return params->size;
    }
}

And thats how I try to call the function using Autoit:

Local $struct = "struct;char shapefile[128];char output[128];char filename[128];int size;endstruct"
Local $tTest = DllStructCreate($struct)
DllStructSetData($tTest, "test1", "Bla")
DllStructSetData($tTest, "test2", "BlaBla")
DllStructSetData($tTest, "test3", "BlaBlaBla")
DllStructSetData($tTest, "size", 40)

$dll = DLLOpen("myDLL.dll")
$ret = DllCall($dll, "int:cdecl", "testFunc", "STRUCT*", DllStructGetPtr($tTest))
MsgBox(0, 0, $ret[0])

DllClose($dll)

Just for testing I want the function to just return the integer value in the struct.

But this aint working. I tested many things, but still I'm not able to get it running. I even don't know if the mistakes are in the C++ code or the Autoit code or both .. I'm not that skilled at C++ and also not that skilled at Autoit DLLCalls :-/

I would really appreciate some help! :)

Kind regards,
leo

Edited by Leo1906

Share this post


Link to post
Share on other sites

Ok, I got it to work. Don't know what I changed but now it works ..

Another question: If I pass the Struct by ref, why can't Autoit get the changed values from the Struct?
Thats how it's done:

extern "C"
{

    struct ParamStruct
    {
        const char* test1;
        const char* test2;
        const char* test3;
        int size;
    };

    int testFunc(struct ParamStruct &params)
    {   
        params.size = 2;
        return params.size;
    }
}
#NoTrayIcon
Local $struct = "struct;char shapefile[128];char output[128];char filename[128];int size;endstruct"
Local $tTest = DllStructCreate($struct)
DllStructSetData($tTest, "test1", "bla")
DllStructSetData($tTest, "test2", "blabla")
DllStructSetData($tTest, "test3", "blablabla ")
DllStructSetData($tTest, "size", 40)


$dll = DLLOpen("Split_DLL.dll") ;<- open DLL
$ret = DllCall($dll, "int:cdecl", "testFunc", "STRUCT*", DllStructGetPtr($tTest))
MsgBox(0, 0, DllStructGetData($tTest, 4))

MsgBox(0, 0, $ret[0])
MsgBox(0, 0, DllStructGetData($tTest, 4))

DllClose($dll)

 

Edit: and another question. Can I use Strings in a Struct with Autoit? Can't find that dataformat in the helpfile regarding structs ..?

Edit2: Well the code seems not to work though .. as soon as I want to access the char's in the DLL Code Autoit crashes ..?

Edited by Leo1906

Share this post


Link to post
Share on other sites

ParamStruct is defining char pointers while the struct you create in Autoit is declaring char arrays.

Perhaps ParamStruct should look more like:
 

struct ParamStruct
    {
        char const test1[128];
        char const test2[128];
        char const test3[128];
        int size;
    };

 

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

  • Similar Content

    • By supersonic
      Hi -
      Currently I'm playing around with Windows Credential Manager. I'm trying to access it with DllCall("advapi32.dll", ...) using the functions 'CredWriteW', 'CredReadW' and 'CredDeleteW'. All well. Another function I have to deal with is 'CredEnumerateW': https://docs.microsoft.com/en-us/windows/desktop/api/wincred/nf-wincred-credenumeratew/ .
      That's the test code I have so far:
      #include <Array.au3> #include <String.au3> Local $tCredentialsCount = DllStructCreate("DWORD;") Local $tPointerToArrayOfPointers = DllStructCreate("PTR;") ; Local $tPointerToArrayOfPointers = DllStructCreate(_StringRepeat("PTR;", 200)) ; ??? Local $aResult = DllCall("advapi32.dll", "BOOL", "CredEnumerateW", _ "WSTR", Null, "DWORD", 1, "DWORD", DllStructGetPtr($tCredentialsCount), "PTR", DllStructGetPtr($tPointerToArrayOfPointers)) If (Not @error) Then Local $iCredentialsCount = DllStructGetData($tCredentialsCount, 1) _ArrayDisplay($aResult, $iCredentialsCount) Local $hPointerToArrayOfPointers = DllStructGetData($tPointerToArrayOfPointers, 1) MsgBox(0, "$hPointerToArrayOfPointers", $hPointerToArrayOfPointers) ; Fails... For $i = 1 To 10 ; $iCredentialsCount MsgBox(0, $i & "___" & (($i * 2) - 1), DllStructGetData($tPointerToArrayOfPointers, ($i * 2) - 1)) Next $tCredentialsCount = 0 $tPointerToArrayOfPointers = 0 DllCall("advapi32.dll", "NONE", "CredFreeW", "PTR", $hPointerToArrayOfPointers) EndIf The DllCall seems to function properly - I get a valid count of credentials (on my computer ~ 133) and a pointer "to array of pointers".
      What is meant by "array of pointers"?
      Microsoft says: Pointer to an array of pointers to credentials. The returned credential is a single allocated block. Any pointers contained within the buffer are pointers to locations within this single allocated block.
      How to access these pointers... Contained within the buffer???
      Any information you can provide me would be greatly appreciated.
    • By bladem2003
      Hello,
      i need help to translate the c code to autoit .
      I don't understand the callback function.
       
      #include <windows.h> #include <stdio.h> // native IR Data by PAnsiChar typedef void CALLBACK CallBackPAnsiChar(char*, char*, char*, char*); typedef int (__stdcall *impInitPAnsiChar)(CallBackPAnsiChar); CALLBACK MyCallBackPAnsiChar(char* Protocol, char* Address, char* Command, char* Flags) { printf("\nIR Data received: Protocol: %s, Address: 0x%s, Command: 0x%s, Flags: 0x%s", Protocol, Address, Command, Flags); fflush(stdout); } int main(int argc, char **argv) { impInitPAnsiChar InitPAnsiChar = NULL; // Load DLL file HINSTANCE hinstLib = LoadLibrary(TEXT("USB_IR_Remote_Receiver.dll")); if (hinstLib == NULL) { printf("\nERROR: unable to load DLL\n"); return 1; } // Get function pointer InitPAnsiChar InitPAnsiChar = (impInitPAnsiChar)GetProcAddress(hinstLib, "InitPAnsiChar"); if (InitPAnsiChar == NULL) { printf("\nERROR: unable to find DLL function\n"); FreeLibrary(hinstLib); return 1; } if (InitPAnsiChar(*MyCallBackPAnsiChar)) { printf("\nInit DLL with InitPAnsiChar successfull"); } else { // Unload DLL file FreeLibrary(hinstLib); return 0; } while(1) { } //return 0; }  
    • By Yirrlaar
      Hello All,
      I'm using "ImageSearch2015.au3" and i'm trying to figure out WHY, for the life of me, I can't find an image is hidden.
      So what I came up with, is as follows:
      _ImageSearchAreaHidden("C:\icon.png", 1, 0, 0, 800, 600, $x1, $y1, 80, 0) Func _ImageSearchAreaHidden($findImage, $resultPosition, $x1, $y1, $right, $bottom, ByRef $x, ByRef $y, $tolerance, $transparency = 0) Local $h, $result local $TestScreen = "C:\TestScreen.png" ;previsous screenshot of the image looking for, fully visible If Not FileExists($findImage) Then Return "Image File not found" If $transparency <> 0 Then $findImage = "*" & $transparency & " " & $findImage If $tolerance < 0 Or $tolerance > 255 Then $tolerance = 0 If $h_ImageSearchDLL = -1 Then _ImageSearchStartup() If $tolerance > 0 Then $findImage = "*" & $tolerance & " " & $findImage $result = DllCall($h_ImageSearchDLL, "str", "ImageSearchEx", "str", $TestScreen, "int", $x1, "int", $y1, "int", $right, "int", $bottom, "str", $findImage) If @error Then Return "DllCall Error=" & @error If $result = "0" Then Return False $array = StringSplit($result[0], "|") If (UBound($array) >= 4) Then $x = Int(Number($array[2])) ; Get the x,y location of the match $y = Int(Number($array[3])) If $resultPosition = 1 Then $x = $x + Int(Number($array[4]) / 2) ; Account for the size of the image to compute the centre of search $y = $y + Int(Number($array[5]) / 2) EndIf Return True EndIf EndFunc ;==>_ImageSearchAreaHidden Now when the folder with the icon is completely visible, it finds the icon without any issues, however if I cover up the icon, it no longer finds the image in the folder.
      Any ideas?
    • By Bilgus
      So first things first the example in the help file for _WinApi_Enum_Windows has an error
      ;_ArrayDisplay($aResult, "_WinAPI_EnumWindows", Default, Default, Default, Default, "#|Handle|Class|Title|Text|Process") Should Be _ArrayDisplay($aResult, "_WinAPI_EnumWindows", Default, Default, Default, "Handle|Class|Title|Text|Process") Next is a bit of helpful info on LPCSTR in a callback function it needs  to be passed as a PTR
      DllCallbackRegister($sFUNCT, $sRETURN, "ptr") Finally on to my question
      I'd want to call EnumPropsEX and pass a string through lparam + append to it rather than declaring anything globally
      I can Come up with two ways to do this The second it a lot more code but possibly safer but the first way I think Should do
      1. From a bit of testing It seems AutoIt won't overflow a DllStruct?
      2. Are strings passed through DLL call guaranteed to be 'an ANSI string (a minimum of 65536 chars is allocated)' as the Helpfile clearly states?
      #include <Array.au3> #include <WinAPI.au3> Example() Func Example() Local $aWindows = _WinAPI_EnumWindows() Local $aResult[$aWindows[0][0]][6] For $i = 1 To $aWindows[0][0] $aResult[$i - 1][0] = "0x" & Hex($aWindows[$i][0], 8) $aResult[$i - 1][1] = $aWindows[$i][1] $aResult[$i - 1][2] = WinGetTitle($aWindows[$i][0]) $aResult[$i - 1][3] = WinGetText($aWindows[$i][0]) $aResult[$i - 1][4] = WinGetProcess($aWindows[$i][0]) $aResult[$i - 1][5] = _ArrayToString(EnumProps($aWindows[$i][0]), ", ", 1) Next _ArrayDisplay($aResult, "_WinAPI_EnumWindows", Default, Default, Default, "Handle|Class|Title|Text|Process|Properties") EndFunc ;==>Example Func EnumProps($hWnd, $vDLL = 'user32.dll') ; Create callback function. Local $iErr = 0 Local $aProps[1] = [0] Local $hCb = DllCallbackRegister('_PropEnumProcEx', 'int', 'hwnd;ptr;handle;ptr') ; Call EnumPropsEx Local $aRet = DllCall($vDLL, 'int', 'EnumPropsEx', 'HWND', $hWnd, 'ptr', DllCallbackGetPtr($hCb), 'str', "") If @error Or Not $aRet[0] Then $iErr = @error ConsoleWrite("EnumProps Error:" & $iErr & @CRLF) ElseIf $aRet[3] <> "" Then $aProps = StringSplit($aRet[3], ";") EndIf DllCallbackFree($hCb) Return SetError($iErr, 0, $aProps) EndFunc ;==>EnumProps Func _PropEnumProcEx($hWnd, $sProp, $hData, $pStr) Local $iSzStr = _WinAPI_StringLenA($sProp) + 1 ; + Null Char If $iSzStr > 1 Then Local $tProp = DllStructCreate('char[' & $iSzStr & ']', $sProp) Local $tRetn = DllStructCreate('char[65535]', $pStr) DllStructSetData($tRetn, 1, DllStructGetData($tRetn, 1) & DllStructGetData($tProp, 1) & ";") EndIf Return 1 EndFunc ;==>_PropEnumProcEx ;-------------------------------------------------------------------------------------------------------------- Func EnumProps2($hWnd, $iSzBuffer = 4096, $vDLL = 'user32.dll') ; Create callback function. Local $iErr = 0 Local $sProps Local $aProps[1] = [0] Local $hCb = DllCallbackRegister('_PropEnumProcEx', 'int', 'hwnd;ptr;handle;ptr') Local $tProps = DllStructCreate('int;int;char[' & $iSzBuffer & ']') DllStructSetData($tProps, 1, $iSzBuffer) ;BufferSz DllStructSetData($tProps, 2, $iSzBuffer) ;BufferRemaining ; Call EnumPropsEx Local $aRet = DllCall($vDLL, 'int', 'EnumPropsEx', 'HWND', $hWnd, 'ptr', DllCallbackGetPtr($hCb), 'ptr', DllStructGetPtr($tProps)) If @error Or Not $aRet[0] Then $iErr = @error DllStructSetData($tProps, 2, 0) EndIf DllCallbackFree($hCb) $sProps = DllStructGetData($tProps, 3) If DllStructGetData($tProps, 2) > 0 Then If $sProps <> "" Then $aProps = StringSplit(StringTrimRight($sProps, 1), ";") EndIf Else If Not $iErr Then $iErr = 6 ;buffer overflow Return SetError($iErr, -DllStructGetData($tProps, 2), $aProps) EndIf Return $aProps EndFunc ;==>EnumProps2 Func _PropEnumProcEx2($hWnd, $sProp, $hData, $ptProp) Local $iSzStr = _WinAPI_StringLenA($sProp) + 1 Local $tProp = DllStructCreate('char[' & $iSzStr & ']', $sProp) If $iSzStr > 1 Then Local $sRet = DllStructGetData($tProp, 1) Local $iSzBuffer = DllStructGetData(DllStructCreate('int', $ptProp), 1) Local $tRetn = DllStructCreate('int;int;char[' & $iSzBuffer & ']', $ptProp) DllStructSetData($tRetn, 2, DllStructGetData($tRetn, 2) - $iSzStr) If DllStructGetData($tRetn, 2) > 0 Then DllStructSetData($tRetn, 3, DllStructGetData($tRetn, 3) & $sRet & ";") EndIf EndIf Return 1 EndFunc ;==>_PropEnumProcEx2  
    • By c.haslam
      At least illogical to me!
      The following script is based on a script jchd wrote. I have changed it so it returns a tag rather than writing the element types and values to the Console. The tag and the values set in the structure are those he used.
      As is, it returns "char;". It should return "char[3]; ...'. With changes in the diagnostic code, I have seem it return "char[3];", but it should return the whole tag.
      I am aware that the script will not differentiate, for example, between an int and a long: it works from the type of what DllStructGetData returns, and calls it an int.
      I am concerned that there may be a memory leak due to a DLLStruct* call, because the code, with minor variations, produces different results.
      I have instrumented it liberally, but @error is 0 everywhere.
      Clues will be most welcome!
      Local $tag = "char a[3];handle b[3];uint c[35];byte d[128];wchar e[190000]; double f[3];int64 g[3];" & _ "char h[3];float i;double j;byte k;ubyte l;short m;ushort n;int o;uint p;char q" Local $struct = DllStructCreate($tag) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 1, 'sos') If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 2, Ptr(123456789)) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 3, 8, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 3, 0x87654321, 2) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 3, 256, 5) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 4, Binary('sos')) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 5, 'gno' & @CRLF & 'ji' & @TAB & 'o') If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 6, 3.1415926, 2) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 7, 17, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 7, -1, 2) DllStructSetData($struct, 8, 'end') If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 9, 2.7182818284590452353602874713527) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 10, 2.7182818284590452353602874713527) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 11, 107) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 12, -108) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 13, 109) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 14, 110) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 15, 111) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($struct, 16, 112) If @error Then MsgBox(0,@ScriptLineNumber,@error) _cDebug_DetectStructElements($struct) Func _cDebug_DetectStructElements($tStruct) Local $retTag Local $len = DllStructGetSize($tStruct) Local $ptr = DllStructGetPtr($tStruct) Local $nbElem = 1, $idx, $incr, $data, $type, $oldvalue, $readvalue, $elem $g_CDebug_sStructElementTypes = '' While 1 $data = DllStructGetData($tStruct, $nbElem) If @error And @error<>2 Then MsgBox(0,@ScriptLineNumber,@error) If @error = 2 Then ExitLoop ; if element out of range or unknown $type = VarGetType($data) $idx = 1 $incr = 0 ; determine max index of element While 1 DllStructGetData($tStruct, $nbElem, 2 * $idx) If @error And @error<>3 Then MsgBox(0,@ScriptLineNumber,@error) If @error = 3 Then ExitLoop $incr = $idx $idx *= 2 WEnd ; index is in [$idx, (2 * $idx) - 1] $idx += $incr Do DllStructGetData($tStruct, $nbElem, $idx) If @error And @error<>3 Then MsgBox(0,@ScriptLineNumber,@error) If @error = 3 Then ; if element is out of range ; approach is asymetric (upper bound is too big) $idx -= ($incr = 1) ? 1 : $incr / 2 Else $idx += Int($incr / 2) EndIf $incr = Int($incr / 2) Until $incr = 0 Switch $type Case "Int32", "Int64" $data = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) DllStructSetData($tStruct, $nbElem, 0x7777666655554433, 1) $readvalue = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) Switch $readvalue Case 0x7777666655554433 $elem = "int64" ; alias: uint64 ; alias: int_ptr(x64), long_ptr(x64), lresult(x64), lparam(x64) ; alias: uint_ptr(x64), ulong_ptr(x64), dword_ptr(x64), wparam(x64) Case 0x55554433 DllStructSetData($tStruct, $nbElem, 0x88887777, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $elem = ($readvalue > 0 ? "uint" : "int") ; int aliases: long, bool, int_ptr(x86), long_ptr(x86), lresult(x86), lparam(x86); ; uint aliases: ulong, dword, uint_ptr(x86), ulong_ptr(x86), dword_ptr(x86), wparam(x86) Case 0x4433 DllStructSetData($tStruct, $nbElem, 0x8888, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $elem = ($readvalue > 0 ? "ushort" : "short") Case 0x33 $elem = "byte" ; alias: ubyte EndSwitch DllStructSetData($tStruct, $nbElem, $data, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $retTag &= $elem Case "String" $oldvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, ChrW(0x2573), 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, $oldvalue, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $retTag = ($readvalue = ChrW(0x2573) ? "wchar" : "char") ;~ If $idx > 1 Then $elem &= "[" & $idx & "]" ; Dosn't work here either!!! Case "Binary" Local $blen = BinaryLen($data) $retTag = "byte" Case "Ptr" $retTag &= "ptr" ; alias: hwnd, handle Case "Double" $oldvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, 10^-15, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $readvalue = DllStructGetData($tStruct, $nbElem, 1) DllStructSetData($tStruct, $nbElem, $oldvalue, 1) If @error Then MsgBox(0,@ScriptLineNumber,@error) $retTag &= ($readvalue = 10^-15 ? "double" : "float") EndSwitch If $nbElem=1 Then MsgBox(0,@ScriptLineNumber,'idx '&$idx) If $idx>1 Then If $nbElem=1 Then MsgBox(0,@ScriptLineNumber,'before index') $retTag &= '['&$idx&']' EndIf $retTag &= ';' $nbElem += 1 WEnd MsgBox(0,@ScriptLineNumber,'$retTag "'&$retTag&'"') Return $retTag EndFunc jchd's code is in post 7
       
       
×
×
  • Create New...