Sign in to follow this  
Followers 0
evilertoaster

DLLStructSetData w/ Binary string

22 posts in this topic




If you specify an Index in DLLStructSetData, only the value at the Index is modified, not the following bytes.


*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Consider:

$a=DllStructCreate('byte[4]')
DllStructSetData($a,1,Binary('0xFFFFFFFF'))
DllStructSetData($a,1,Binary('0xAABB'),2)
MsgBox(0,"",DllStructGetData($a,1))
;result=0xFFAAFFFF

I expected 0xFFAABBFF. What am I doing wrong?

If you use 0xAABB and don't convert your hex number to a string and then to binary then it does what you would expect.

It looks to me like an error in the way AutoIt is handling a binary value in DllstructSetData because if you use Number(Binary('0xAABB')) then it also works.

Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

If you specify an Index in DLLStructSetData, only the value at the Index is modified, not the following bytes.

Yes but why should these give a different result?

$a=[url="../autoit3/docs/functions/DllStructCreate.htm"]DllStructCreate[/url]('byte[4]')
DllStructSetData($a,1,('0xFFFFFFFF'))
DllStructSetData($a,1,0xAABB,2);I expect 0xBB to be written and it is
MsgBox(0,"",DllStructGetData($a,1))

$a=DllStructCreate('byte[4]')
DllStructSetData($a,1,Binary('0xFFFFFFFF'))
DllStructSetData($a,1,Number(Binary('0xAABB')),2);I expect 0xBB to be written and it is
MsgBox(0,"",DllStructGetData($a,1))

If you write the same value but use a Binary variant then a different value might be written as eviltoaster showed. That looks wrong to me.

Maybe the answer is that if you write a value to an element which exceeds the element's range then the result is unpredictable and you have only yourself to blame.

This also works

$a=DllStructCreate('byte[4]')
DllStructSetData($a,1,Binary('0xFFFFFFFF'))
DllStructSetData($a,1,Binary('0xBB'),2);range of element not exceeded
MsgBox(0,"",DllStructGetData($a,1))

But I still think it's wrong that the reult can depend on the variant type.

Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Thanks for the work-arounds.

I would agree it seems to act odd with binary data... I'll throw up a ticket and see if this is intended.

What is additionally counter-intuitive is that-

DllStructSetData($a,1,Binary('0xFFFFFFFF'),1)

and

DllStructSetData($a,1,Binary('0xFFFFFFFF'))

Don't set the same data, even though (according to the documentation) the latter should be automatically using 1 if no argument is specified.

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

I may have spoke to soon.

DllStructSetData($a,1,number(binary('0xAABB')),2

produces the same results as

DllStructSetData($a,1,binary('0xAABB'),2)

and

DllStructSetData($a,1,0xAABB,2)

only sets BB (not AABB)

Is there a way to produce the intended results? Setting AABB so the final data is 0xFFAABBFF?

Edited by evilertoaster

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

I may have spoke to soon.

DllStructSetData($a,1,number(binary('0xAABB')),2

produces the same results as

DllStructSetData($a,1,binary('0xAABB'),2)

and

DllStructSetData($a,1,0xAABB,2)

only sets BB (not AABB)

Is there a way to produce the intended results? Setting AABB so the final data is 0xFFAABBFF?

You are a bit confused by what is happening and partly because you decided to use 0xFFFFFFFF as the data to set. If you had used something like 0x12345678 then you would have seen things were not as you thought.

There are various ways to do what you want and I show one below.

$a=DllStructCreate('byte[4]')
$b = dllstructcreate('int',dllstructgetptr($a))
$c = dllstructcreate("align1;byte;short;byte",dllstructgetptr($a))

DllStructSetData($b,1,0x12345678)
dllstructsetdata($c,2,0xAABB)

$g = dllstructgetdata($b,1);
msgbox(262144,"result is","0x" & Hex($g) )

See that I set and read the data using the int representation of the contents of the struct. If you have a struct of byte array, then you set the data to 0x12345678 then you are saying that byte 1 is 78, byte 2 is 56 and so on. If you try to read that back in one go as an integer all the bytes will be reversed. By using 0xFFFFFFFF you wouldn't notice that.

I hope that makes sense. :)

Edited by martin

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

Try to see a struct like an array:

Dim $aStruct_Char[4]=["A","B","C","D"]    ; there is only 1 byte character place for every indexed "field" in the array

And now try to replace "BC" in the $aStruct_Char-array with "EF"...how would (could) this work? (i know that you know that it is not possible to do that in one step, this is because there is no "BC" in the form of a coherent string into this array!)

You could try

$aStruct_Char[1]="EF"   ;you want to replace B with E and C with F     

with the result that (remember that every member in the struct is only one byte ) 

A ) it causes an error because you want to write a 2-byte "String" into an one byte reserved place in this array. 

B ) to write tacitly so many characters into the struct (array) as space is reserved therefor (without to show an error....).

Both possibilities do not make what you want to do....but you could choose if you will get an error or not!  :)

$struct=DllStructCreate("char[4]")  ; an array of 4 one-byte "chars"

dllstructsetdata($struct,1,"ABCD")    ;everything is all right, because every place in the array is filled with a one-byte char 

dllstructsetdata($struct,1,"EF",2)       ;should cause an error imho because you want to set a 2-byte "String" into a 1-byte "char" but autoit writes tacitly (my dictionary says this is the right word^^) only the first byte of your string with the result that the struct is now "AECD"....

Andy

/EDIT/  but it would very nice if AutoIt would make the struct to "AEFD"  ;)

 

Edited by AndyG

Share this post


Link to post
Share on other sites

Hummmmmm.

Ok, well I thought the world made sense. There's defiantly some clarification I'll need to find then.

If you have a struct of byte array, then you set the data to 0x12345678 then you are saying that byte 1 is 78, byte 2 is 56 and so on. If you try to read that back in one go as an integer all the bytes will be reversed. By using 0xFFFFFFFF you wouldn't notice that.

I hope that makes sense.

I think this doesn't make sense to me.

WHY is it reversed? That seems very arbitrary to me... if i set some data:

$
a=DllStructCreate('byte[4]')                ;<someMemAdr> : [0x00,0x00,0x00,0x00]
DllStructSetData($a,1,Binary(0x12345678))    ;<someMemAdr> : [0x12,0x34,0x56,0x78]
DllStructSetData($a,1,binary(0xAABB),2)      ;<someMemAdr> : [0x12,0xAA,0xBB,0x78]
MsgBox(0,"",DllStructGetData($a,1))

Is that wrong?

Why is it not the same as idea as something like:

#include <iostream>
#include <string.h>

using namespace std;

int main()
{    
    unsigned char structBytes[7]={43,43,43,43,43,43,0}; //0x2b2b2b2b2b00 -> "+++++\n"
    unsigned char setBytes[2]={85,85};   //0x5555 -> "UU"
    memcpy(&structBytes[2],setBytes,2);
    cout<<structBytes;   //"++UU++" as expected
    cout<<endl;
    system("Pause");
    int a;
}

Truly truly I do implore!

And now try to replace "BC" in the $aStruct_Char-array with "EF"...how would (could) this work? (i know that you know that it is not possible to do that in one step, this is because there is no "BC" in the form of a coherent string into this array!)

I was talking always about the binary data represented by the hex number BC, not a string of "BC" (which as hex would be 0x4243). The C++ example shows 'how' I'd replace it...but I'm obviously missing something here...

Hope its not annoying you, but any further explanations would be quite helpful.

Share this post


Link to post
Share on other sites

It's different than array of bytes but they actually the same.

If you have:

BYTE bTest[4] = {0x12, 0x34, 0x56, 0x78};
BYTE *bPtr = bTest;

and you use a pointer casting, hope it's correct:

DWORD dwVal = *((DWORD *)bTest);

cout << dwVal << endl;

..you're promoting bTest to a dword pointer and thus on a little endian machine it'll read a 4 byte value from memory where the least significant byte is in lower memory address. In memory it looks like:

0x00010000 12
0x00010001 34
0x00010002 56
0x00010003 78

..but reading in little endian machine store the least significant value in the least significant byte order of the dword into 0x78563412.

The same holds true for AutoIt, if the data is handled as an int or other primitive data. Can't explain it better. Hope I'm correct.

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

Hummmmmm.

Ok, well I thought the world made sense. There's defiantly some clarification I'll need to find then.

I think this doesn't make sense to me.

WHY is it reversed? That seems very arbitrary to me... if i set some data:

a=DllStructCreate('byte[4]')                ;<someMemAdr> : [0x00,0x00,0x00,0x00]

DllStructSetData($a,1,Binary(0x12345678))    ;<someMemAdr> : [0x12,0x34,0x56,0x78]   Wrong!  [0x78,0x56,0x34,0x12]

DllStructSetData($a,1,binary(0xAABB),2)      ;<someMemAdr> : [0x12,0xAA,0xBB,0x78]      Wrong! It doesnt matter what type of Data you want to write into the struct! Here you write the byte BB to the second(indexed) position in the struct 

MsgBox(0,"",DllStructGetData($a,1))

Is that wrong?          Yes ^^

Why is it not the same as idea as something like:    Ask some Dev...   ;)

int main()

{    

    unsigned char structBytes[7]={43,43,43,43,43,43,0}; //0x2b2b2b2b2b00 -> "+++++\n"

    unsigned char setBytes[2]={85,85};   //0x5555 -> "UU"

     memcpy(&structBytes[2],setBytes,2);                you made a ddlstructsetdata(structbytes,1,"0x55",3) and a ddlstructsetdata(structbytes,1,"0x55",4) in one C-command! Write a function _memcpy() in AutoIt doing the same!

    cout<<structBytes;   //"++UU++" as expected

    cout<<endl;

    system("Pause");

    int a;

 }

I was talking always about the binary data represented by the hex number BC, not a string of "BC" (which as hex would be 0x4243). The C++ example shows 'how' I'd replace it...but I'm obviously missing something here...

Hope its not annoying you, but any further explanations would be quite helpful. 

  :)as i have written before, it does not matter what type of data you want to store into the "memory" of the struct. DllStructSetData() is NOT the same as a _copy_some_bytes_consecutively_into_a_struct() or memcopy()

Edited by AndyG

Share this post


Link to post
Share on other sites

but reading in little endian machine store the least significant value in the least significant byte order of the dword into 0x78563412.

The same holds true for AutoIt, if the data is handled as an int or other primitive data.

A missing piece to my puzzle, thank you.

you made a ddlstructsetdata(structbytes,1,"0x55",3) and a ddlstructsetdata(structbytes,1,"0x55",4) in one C-command! Write a function _memcpy() in AutoIt doing the same!

I've had enough of your and your practicality! (I jest :))

In reality the only problem with this is scenarios where I have much larger chunks of binary data and didn't want to suffer the performance implications of looping though each byte and separately writing it into the structs array. I was hoping that I'd be able to set the data the same way I initialize it.

DllStructSetData() is NOT the same as a _copy_some_bytes_consecutively_into_a_struct()

Except it IS if you don't specify the index parameter:

$a=DllStructCreate('byte[9]')
DllStructSetData($a,1,Binary('0x112233445566778899'))

I just inserted a consecutive string of bytes no? I understand better now what's going on, but I guess in the end it's still counter-intuitive why these aren't the same:

DllStructSetData($a,1,Binary('0x112233445566778899'),1)

vs

DllStructSetData($a,1,Binary('0x112233445566778899'))

If anyone is willing and able to elaborate on that, I think I can rest abit easier.

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

In C for example:

char* something[5] = {'a', 'b', 'c', 'd'};

// Implicitly but to illustrate
something[0] = (byte)0x12345678

// is not the same as
char* somethingelse[] = "string";

Storing a value in index, will trim value to fit within the value type capacity, thus short i = 1<<32 will not fit the next two bytes with the rest as implicit memory copy will do like *((DWORD *)something) = 0x20202020. Anyway, it's how memory works and has nothing to do with AI's DllStructSetData().

Edit: Ignore my mumbling. Just know that:

int values[2];

value[0] = 0;

// is just setting an int's value like
int val = 0;

..nothing is assumed but the lvalue (the left of the assignment operator) is treated as int = value.

Edited by Authenticity

Share this post


Link to post
Share on other sites

In your simplified example that's fine. But for the most part I'm referring to the specific examples where byte (or char/ubyte) arrays are being used. Mainly because of this:

When the element is char[n], byte[n] or ubyte[n] the data can be a string otherwise it has to be a number.

Which is from the DLLStructSetData function help. What you're all saying (and seems to be true) is that you cannot actually provide a string, or rather it would be useless to do so since it only respects the first byte of the string. So would it be more appropriate to say:

"When the element is char[n], byte[n] or ubyte[n] the data can be an ASCII character, otherwise it has to be a number." ?

Continued thanks for all involved in the discussion, this interesting topic for me.

Share this post


Link to post
Share on other sites

...which is logical because storing byte/char or 1 byte based array is linear and correct:

$char = DllStructCreate("char[10]")
DllStructSetData($char, 1, "abcd")
ConsoleWrite(DllStructGetData($char, 1) & @CRLF)

$short = DllStructCreate("short[2]")
DllStructSetData($short, 1, 0x10001000)
ConsoleWrite(DllStructGetData($short, 1, 1) & @TAB & DllStructGetData($short, 1, 2) & @CRLF)
ConsoleWrite(DllStructGetData($short, 1) & @CRLF)

..but if you store two shorts and read the value, there is no convention as to how to store the data in order the represent it as int or maybe float... I think the documentation is clear enough, it's logical.

Share this post


Link to post
Share on other sites

#16 ·  Posted (edited)

from the help of dllstructsetdata()

index[optional] If the element is an array, you need to specify which index to set, otherwise it sets index 1. The first element is 1.

Sorry! But i never saw an Array in one of your many examples...I know what you want to do and believe me, i wish that your "idea" would work, to have a really fast access to big data in the memory.

I take AutoIt-Functions "as is" , if they are buggy in sense of the description in the helpfile i would make a bugreport..

/EDIT/ sorry for writing crap....

Edited by AndyG

Share this post


Link to post
Share on other sites

...which is logical because storing byte/char or 1 byte based array is linear and correct

Except you can't do that if you provide an index parameter?

If I have a byte array, and the doc says "data can be a string", it's only 1/2 true .It can only be a string if the index parameter is 1... But yet THAT's not even true, It can really only be a string if the index parameter is left out (which apparently doesn't default to 1 like the help file suggests).

Stepping back and looking at how it works with what I know now, it makes sense why it does that. But I still think it's misleading at best.

It would defiantly be nice if there was native support for doing something like this...but in the least maybe a note in the help file about providing 'strings' with an index...

Any more thoughts on the matter?

Share this post


Link to post
Share on other sites

Ok, i have found my "fault"

in the german translation the description of the [index] parameter is more like this: [index] if the element is an array, with this index a single array element can be accessed

it should be clear that there is no possibility to set more than one array element

Share this post


Link to post
Share on other sites

Hum that's true too kinda of the English one though: "you need to specify which index to set, otherwise it sets index 1." It doesn't say anything about multiple indexes. However, you can't really set a 'string' of data in a single element of a 1-byte array so that's what led me to think "well logically, if it can't fit, it would bleed into the next index" but instead it just truncates the data. If anything, I would have thought it to return @error=2 (Element value out of range) instead...

Share this post


Link to post
Share on other sites

... this seems to be a classic case of a misunderstanding  :)

However, you can't really set a 'string' of data in a single element of a 1-byte array

That is why in one of the examples that I've written above:

$struct=DllStructCreate("char[4]")  ; an array of 4 one-byte "chars"

dllstructsetdata($struct,1,"ABCD")    ;everything is all right, because every place in the array is filled with a one-byte char

dllstructsetdata($struct,1,"EF",2)       ;should cause an error imho because you want to set a 2-byte "String" into a 1-byte "char" but autoit writes tacitly (my dictionary says this is the right word^^) only the first byte of your string with the result that the struct is now "AECD"....

 

So we're of one mind, that's nice!

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