Jump to content

DllStructs strange behavior


Andreik
 Share

Go to solution Solved by jchd,

Recommended Posts

Can someone explain this behavior?

If I run this code

For $i = 1 To 15
    Test()
Next

Func Test()
    Local $pStruct = DllStructGetPtr(CreateStruct())
    ConsoleWrite($pStruct & @CRLF)
    Local $tStruct = DllStructCreate('char Test[4];', $pStruct)
    ConsoleWrite('Value: ' & $tStruct.Test & @CRLF & @CRLF)
EndFunc

Func CreateStruct()
    Local $tStruct = DllStructCreate('char Test[4];')
    ConsoleWrite(DllStructGetPtr($tStruct) & @CRLF)
    DllStructSetData($tStruct, 'Test', 'test')
    Return $tStruct
EndFunc

the result is quite strange

0x016C5DF0
0x016C5DF0
Value: test

0x016C5F90
0x016C5F90
Value: 

0x016C5E70
0x016C5E70
Value: test

0x016C5E50
0x016C5E50
Value: 

0x016C5FC0
0x016C5FC0
Value: test

0x016C5FB0
0x016C5FB0
Value: 

0x016C5E50
0x016C5E50
Value: 

0x016C5EB0
0x016C5EB0
Value: 

0x016C5DF0
0x016C5DF0
Value: test

0x016C5E00
0x016C5E00
Value: test

0x016C5ED0
0x016C5ED0
Value: 

0x016C5FD0
0x016C5FD0
Value: test

0x016C5EB0
0x016C5EB0
Value:  

0x016C5EF0
0x016C5EF0
Value: test

0x016C5F90
0x016C5F90
Value:

Sometimes seems to work fine but sometimes I get unexpected values.

If I change the code as below (changed just first two lines of code in Test function) seems to work fine.

For $i = 1 To 15
    Test()
Next

Func Test()
    $temp = CreateStruct()
    Local $pStruct = DllStructGetPtr($temp)
    ConsoleWrite($pStruct & @CRLF)
    Local $tStruct = DllStructCreate('char Test[4];', $pStruct)
    ConsoleWrite('Value: ' & $tStruct.Test & @CRLF & @CRLF)
EndFunc

Func CreateStruct()
    Local $tStruct = DllStructCreate('char Test[4];')
    ConsoleWrite(DllStructGetPtr($tStruct) & @CRLF)
    DllStructSetData($tStruct, 'Test', 'test')
    Return $tStruct
EndFunc

 

When the words fail... music speaks.

Link to comment
Share on other sites

I feel like the DLLStructCreate in Test() is stomping over the struct you create in the CreateStruct() function, but I can't explain what is happening.

Can't you just use the struct as returned from CreateStruct()?  

For $i = 1 To 15
    Test()
Next

Func Test()
    Local $tStruct = CreateStruct()
    ConsoleWrite('Value: ' & $tStruct.Test & @CRLF & @CRLF)
EndFunc

Func CreateStruct()
    Local $tStruct = DllStructCreate('char Test[4];')
    DllStructSetData($tStruct, 'Test', 'test')
    Return $tStruct
EndFunc

What is the bigger picture?

Link to comment
Share on other sites

The problem in the code below is that you are losing the value that CreateStruct() returns because you are feeding it to DllStructGetPtr().  But after that you can’t reference it, only the pointer to it.

Func Test()
    Local $pStruct = DllStructGetPtr(CreateStruct())
    ConsoleWrite($pStruct & @CRLF)
    Local $tStruct = DllStructCreate('char Test[4];', $pStruct)
    ConsoleWrite('Value: ' & $tStruct.Test & @CRLF & @CRLF)
EndFunc

Isn’t this what you want:

For $i = 1 To 15
    Test()
Next

Func Test()
    Local $pStruct, $tStruct  
    
    CreateStruct($pStruct, $tStruct)
    
    ConsoleWrite('Value: ' & $tStruct.Test & @CRLF & @CRLF)
EndFunc

Func CreateStruct(ByRef $tStruct, ByRef $pStruct)
    $tStruct = DllStructCreate('char Test[4];')
    DllStructSetData($tStruct, 'Test', 'test')
    $pStruct = DllStructGetPtr($tStruct)
EndFunc

(Not tested)

Edit: Or as @spudw2k suggests, do you even want to use a pointer, since your allocating the memory yourself anyway?

Edited by JockoDundee

Code hard, but don’t hard code...

Link to comment
Share on other sites

1 hour ago, Andreik said:

but I don't get it why the first example doesn't fail every time.

IMHO, and without knowing AutoIt internal Implementation details,  I think what’s happening is due to the $tStruct going out of scope - with its reference count=0, that’s why saving it works.  The randomness may just be due to the timing of garbage collection or whatever memory cleanup AutoIt does on $tStruct. If it runs async, then anything is possible.

Code hard, but don’t hard code...

Link to comment
Share on other sites

  • Solution

That's the problem with pointers: whatever rock-solid vault you save it in, the "thing" the pointer points to (a block of memory) has to be kept alive until further use of the pointer, else anything bad can happen.

I don't recall that AutoIt uses a garbage collector. I believe the allocated block is just returned to the system. If you allocate a much larger block, an exception almost always results because the system is more likey to require an allocation fitting the hole made by releasing the initial block.

For $i = 1 To 5
    Test()
Next

Func Test()
    Local $pStruct = DllStructGetPtr(CreateStruct())
    ConsoleWrite($pStruct & @CRLF)
    Local $tStruct = DllStructCreate('wchar Test[1000000];', $pStruct)
    ConsoleWrite('Value: ' & $tStruct.Test & @CRLF & @CRLF)
EndFunc

Func CreateStruct()
    Local $tStruct = DllStructCreate('wchar Test[1000000];')
    ConsoleWrite(DllStructGetPtr($tStruct) & @CRLF)
    DllStructSetData($tStruct, 'Test', 'test')
    Return $tStruct
EndFunc

Yields an access violation at the second loop every time I ran it:

0x05F97020
0x05F97020
!>13:40:26 AutoIt3.exe ended.rc:-1073741819

 

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

what AutoIt version are you using? I ran your code in a loop of 1000000 and it never failed. 3.3.14.5

I'm using Version 3.3.14.5

 

Saludos

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