Jump to content

DllStruct Dev


Ejoc
 Share

Recommended Posts

I am making post #1 host my UDFs for DllStruct.

Update May 16, 2005:

Added _DllStructCreateFromString() Creat a struct that is a copy of a string

Added _GetLastErrorMessage() String containing system error message

Update May 12,2005:

Renamed _StructWriteToFile() to _FileWriteFromDllStruct()

Renamed _FileReadToStruct() to _FileReadToDllStruct()

Fixed header comments

Added _StructWriteToFile($p,$szFileName)

Added _FileReadToStruct($szFileName)

Update May 11, 2005:

Added _DllStructGetSizeFromStr($szStruct) like DllStructGetSize() without creating the struct

Added _DllStructSubStruct($p,$iElement,$szStruct) see header

Function Headers:

;=====================================================
;   _DllStructGetSizeFromStr($szStruct)
;   $string     The string you would use in DllStructCreate
;   Returns     The size of the struct
;               0 on error and sets @Error To the DllStructCreate Error
;=====================================================

;=====================================================
;   _DllStructSubStruct(ByRef $p, $iElement, $szStruct)
;   $p          The return from DllStructCreate()
;   $iElement   The element where the sub struct is located
;   $szStruct   The String representing the Sub Struct
;   Returns a new struct for use in DllStructGet/DllStructSet
;   Sets @Error to -1 if $iElement is outside, -2 sub struct
;       would go outside the bounds of the struct
;   $p's elements are decreased as the substruct elements are removed
;
;   $RECT_STR   = "int;int;int;int"
;   $POINT_STR  = "int;int"
;   $p          = DllStructCreate("ptr;" & $RECT_STR & ";" & $POINT_STR)
;   $rect       = _DllStructSubStruct($p,2,$RECT_STR)
;   $point      = _DllStructSubStruct($p,3,$POINT_STR)
;   DllCall("some.dll","int","func","ptr",DllStructPtr($p))
;   $point_x    = DllStructGet($point,1)
;   $point_y    = DllStructGet($point,2)
;   $left       = DllStructGet($rect,1)
;   $top        = DllStructGet($rect,2)
;   $right      = DllStructGet($rect,3)
;   $bottom     = DllStructGet($rect,4)
;   DllStructFree($p)
;=====================================================

;===============================================
;   _FileWriteFromDLLStruct($p,$szFileName)
;   Write a Struct to a file
;   $p              Struct to write
;   $szFileName     Name of the file to write
;   Return          Bytes Written
;   On Error        @Error is set to
;                   -1 invalid Struct
;                   -2 DllStructGetSize Failed
;                   -3 Could not open File
;                   -4 DllCall Failed
;                   -5 WriteFile Failed
;===============================================


;===============================================
;   _FileReadToDLLStruct($szFileName)
;   Read a file into a DllStruct, which you must delete
;   $szFileName     Name of the file to read
;   Return          DllStruct which element 1 is an
;                   array of bytes = file size
;                   element 2  is the number of bytes
;                   read.  Access the data with:
;                   $n = DllStructGetData($p,2)
;                   DllStructGetData($p,1,1..$n)
;   On Error        @Error is set to
;                   -1 File does not exist
;                   -2 DllStructCreate Failed
;                   -3 Could not open File
;                   -4 DllCall Failed
;                   -5 ReadFile Failed
;===============================================

;===============================================
;   _DllStructCreateFromString($szString)
;   Create a DllStruct That is a string, and copy $szString into it
;   $szString       String to be in the new struct
;   Return          Success a new struct, Failure @error = -1
;===============================================

;===============================================
;   _GetLastErrorMessage($DisplayMsgBox="")
;   Format the last windows error as a string and return it
;   if $DisplayMsgBox <> "" Then it will display a message box w/ the error
;   Return      Window's error as a string
;===============================================

DLLStruct.au3

Edited by Ejoc
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

  • Replies 70
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Interesting idea... Makes for a little more clarity, but it sounds like it will require a bunch of potentially hairy code that gives minimal return for the effort. I'm quite satisfied with the way its currently done with element indexes.

On a side note, I just took nearly 800 lines of C code writen as a command line utility under Linux, made some very minor changes, compiled it as a DLL, made an .au3 wrapper for it and it works just great! I am so thrilled. Your UDFs made me realize that this was even possible. I had previously started to re-write it in AutoIt and quickly came to realize it was going to take an incredibly long time to execute. (I estimated that it was going to take over 1000 times longer than the roughly 2 seconds the DLL takes. It has some very long loops and some intensive number crunching.)

I hope you get this added into the AutoIt source, I think it is definitely a worthy feature :)

601DisengageEnd Program

Link to comment
Share on other sites

I dont think it will add that much more for me. Because I was planing on computing all the indexs...indecies...whatever on DllStructCreate() and return it in an array along with the pointer. This would reduce so much overhead, including the variable names wouldn't be that bad.

$array = DllStructCreate("int x; int y; char str[256]")

$array[0] = the pointer

$array[1] = 3 ; the number of elements in the struct

$array[2] = 0 ; memory offset to element 1

$array[3] = 4 ; memory offset to element 2

$array[4] = 8 ; memory offset to element 3

$array[5] = 4 ; element 1 data size

$array[6] = 4 ; element 2 data size

$array[7] = 1 ; element 3 data size

$array[8] = "x" ; element 1 var name

$array[9] = "y" ; element 2 var name

$array[10] = "str" ; element 3 var name

I would still keep DllStructCreate("int;int;char[256]") valid

Edited by Ejoc
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

indices actually... whatever... Seriously, as long as its reasonably easy and clear how to get back the information thats needed, no matter how you choose to implement it, I'm sure that I and almost everybody else will be happy just to have the feature.

/vocabulary nazi :)

601DisengageEnd Program

Link to comment
Share on other sites

I don't know how to alloc memory so good... just hopin' for...

$a = DLLCreateStruct("int;int;int")

$val = DLLGetStructItem($a,1)

DLLFreeStruct($a)

or something on that order...

especially for RECT

$rect = DLLCreateStruct("int;int;int;int")

DLLCall("user32.dll","int","GetWindowRect","hwnd",$hwnd,"ptr",$rect)

$l = DLLGetStructItem($rect,1)

$t = DLLGetStructItem($rect,2)

$r = DLLGetStructItem($rect,3)

$b = DLLGetStructItem($rect,4)

DLLFreeStruct($rect)

<{POST_SNAPBACK}>

As I see the "best" way to implement it the only thing you would do differently is:

DLLCall("user32.dll","int","GetWindowRect","hwnd",$hwnd,"ptr",$rect[0])

Everything else would work like you have it coded. Using the array format will greatly improve the execution speed

Edited by Ejoc
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

$array = DllStructCreate("int x; int y; char str[256]")

$array[0] = the pointer

$array[1] = 3 ; the number of elements in the struct

$array[2] = 0 ; memory offset to element 1

$array[3] = 4 ; memory offset to element 2

$array[4] = 8 ; memory offset to element 3

$array[5] = 4 ; element 1 data size

$array[6] = 4 ; element 2 data size

$array[7] = 1 ; element 3 data size

$array[8] = "x" ; element 1 var name

$array[9] = "y" ; element 2 var name

$array[10] = "str" ; element 3 var name

I would still keep DllStructCreate("int;int;char[256]") valid

<{POST_SNAPBACK}>

Nice to see that feature will be implemented! But I have one llittle suggestion about return format. This style with one dimentional array imo not so convenient to use in the loops. I think this will be a bit more logical and easier for working by index:

$array[0][0] = the pointer
$array[0][1] = 3; the number of elements in the struct
$array[0][2] = 9; structure size

$array[1][0] = 0; memory offset to element 1
$array[1][1] = 4; element 1 data size
$array[1][2] = "x"; element 1 var name

$array[2][0] = 4; memory offset to element 2
$array[2][1] = 4; element 2 data size
$array[2][2] = "y"; element 2 var name

$array[3][0] = 8; memory offset to element 3
$array[3][1] = 1; element 3 data size
$array[3][2] = "str"; element 3 var name
Link to comment
Share on other sites

Remember guys we are C/C++ programmers. We, to varying extents, understand the sizes and layouts of objects in C. Average-Joe-Dumbass is going to be lucky to know the difference between an int and a char, much less that an int is traditionally 4x the size of a char or that a char is traditionally a byte. Is this size/offset information really needed for the end-user? If not, then they don't need to see it; hide it somewhere or don't let them look at whats stored in the variant at all, make all access through functions which act on a variable.

Link to comment
Share on other sites

If not, then they don't need to see it; hide it somewhere or don't let them look at whats stored in the variant at all, make all access through functions which act on a variable.

<{POST_SNAPBACK}>

That was my plan. People will never use $array[x], I guess ignore my last post about using $array[0], while going to sleep I thought what Valik said. Functions I see being used:

DllStructPtr() ; used in the actual DllCall("","","","ptr",DllStructPtr($array))

DllStructSize()

DllStructCreate()

DllStructGet()

DllStructSet()

DllStructFree()

Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

I dont have the help files yet, but I sent the code off as it is.

This is the test.au3, it shows how it works, I'll do some timing next and see what the difference is in execution time between _DllMem* and DllStruct*

;   valid data types (case sensitive)
;   Type    C equiv         Note
;=========================================================
;   int     __int32
;   uint    __int32A        Sets the unsigned flag
;   byte    char
;   ubyte   char            Sets the unsigned flag
;   char    char            Sets the ASCII flag, char[] sets the String Flag
;   dword   __int32
;   udword  __int32         Sets the unsigned flag
;   int64   __int64
;   uint64  __int64         Sets the unsigned flag
;   ptr     int
;   short   short
;   ushort  short           Sets the unsigned flag
;=========================================================
;   to create an array add [array size] to the data type:
;   "char[128]" = string 128 bytes long
;   "byte[128]" = array of 128 chars, not treated as a string
;=========================================================

;=========================================================
;   Create the struct
;   struct {
;       int             var1;
;       unsigned char   var2;
;       unsigned int    var3;
;       char            var4[128];
;   }
;=========================================================
$str        = "int;ubyte;uint;char[128]"
$a          = DllStructCreate($str)
if @error Then
    MsgBox(0,"","Error in DllStructCreate " & @error);
    exit
endif

;=========================================================
;   Set data in the struct
;   struct.var1 = -1;
;   struct.var2 = 255;
;   struct.var3 = INT_MAX; -1 will be typecasted to (unsigned int)
;   strcpy(struct.var4,"Hello");
;   struct.var4[0]  = 'h';
;=========================================================
DllStructSet($a,1,-1)
DllStructSet($a,2,255)
DllStructSet($a,3,-1)
DllStructSet($a,4,"Hello")
DllStructSet($a,4,Asc("h"),1)

;=========================================================
;   Display info in the struct
;=========================================================
MsgBox(0,"DllStruct","Struct Size: " & DllStructSize($a) & @CRLF & _
        "Struct pointer: " & DllStructPtr($a) & @CRLF & _
        "Data:" & @CRLF & _
        DllStructGet($a,1) & @CRLF & _
        DllStructGet($a,2) & @CRLF & _
        DllStructGet($a,3) & @CRLF & _
        DllStructGet($a,4))

;=========================================================
;   Try to "break" it by setting data outside the memory allocated for
;   the struct
;=========================================================
;   Set element 100 to -1
DllStructSet($a,100,-1)
if @error Then MsgBox(0,"DllStructSet($a,100,-1)","You tried to write to a non existing element",4)

;   Set element 0 to -1
DllStructSet($a,0,-1)
if @error Then MsgBox(0,"DllStructSet($a,0,-1)","You tried to write to a non existing element",4)

;   Set element 4, index 256 to -1
DllStructSet($a,4,-1,256)
if @error Then MsgBox(0,"DllStructSet($a,4,-1,256)","You tried to write to an index outside the struct",4)


;=========================================================
;   Free the memory allocated for the struct
;=========================================================
DllStructFree($a)
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

Rockin! I have a question about this though:

;    Try to "break" it by setting data outside the memory allocated for
;    the struct
;=========================================================
;    Set element 100 to -1
DllStructSet($a,100,-1)
if @error Then MsgBox(0,"DllStructSet($a,100,-1)","You tried to write to a non existing element",4)

;    Set element 0 to -1
DllStructSet($a,0,-1)
if @error Then MsgBox(0,"DllStructSet($a,0,-1)","You tried to write to a non existing element",4)

;    Set element 4, index 256 to -1
DllStructSet($a,4,-1,256)
if @error Then MsgBox(0,"DllStructSet($a,4,-1,256)","You tried to write to an index outside the struct",4)

Please tell me that you are setting @error to a value so we can determine what sort of idiotic stunt we tried to pull, rather than just flaging it and expecting us to figure it out. I'm sure you are, but the example code should demonstrate that.

Pretty excited about this, if I survive the tsunami of Larry's sweat, I expect to be using this all the time. Now I can write "Code for Windows" without having to write "Windows Code"! :)

601DisengageEnd Program

Link to comment
Share on other sites

Rockin!  I have a question about this though:

;   Try to "break" it by setting data outside the memory allocated for
;   the struct
;=========================================================
;   Set element 100 to -1
DllStructSet($a,100,-1)
if @error Then MsgBox(0,"DllStructSet($a,100,-1)","You tried to write to a non existing element",4)

;   Set element 0 to -1
DllStructSet($a,0,-1)
if @error Then MsgBox(0,"DllStructSet($a,0,-1)","You tried to write to a non existing element",4)

;   Set element 4, index 256 to -1
DllStructSet($a,4,-1,256)
if @error Then MsgBox(0,"DllStructSet($a,4,-1,256)","You tried to write to an index outside the struct",4)

Please tell me that you are setting @error to a value so we can determine what sort of idiotic stunt we tried to pull, rather than just flaging it and expecting us to figure it out.  I'm sure you are, but the example code should demonstrate that.

Pretty excited about this, if I survive the tsunami of Larry's sweat, I expect to be using this all the time.  Now I can write "Code for Windows" without having to write "Windows Code"! :)

<{POST_SNAPBACK}>

The first 2 set the error code to -2, the 3rd -3. There are different error codes for different errors :D Edited by Ejoc
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

Speed test results :)

_DllMemCreate()     15.0 Ticks
DllStructCreate()   0.2 Ticks

_DllMemSet() int    4.5 Ticks
DllStructSet() int  0.1 Ticks

_DllMemGet() int    4.3 Ticks
DllStructGet() int      0.1 Ticks

_DllMemSet() str    4.6 Ticks
DllStructSet() str  0.1 Ticks

_DllMemGet() str    4.6 Ticks
DllStructGet() str  0.1 Ticks

_DllMemFree()       0.3 Ticks
DllStructFree()     0.1 Ticks

The DllStructScript:

$str    = "int;byte;char[128];int;dword;char[128]"

$begin  = TimerInit()
$a      = DllStructCreate($str);
$Create = TimerDiff($begin)

$begin  = TimerInit()
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$b      = DllStructSet($a,4,100)
$Set    = TimerDiff($begin)

$begin  = TimerInit()
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$b      = DllStructGet($a,4)
$Get    = TimerDiff($begin)

$begin  = TimerInit()
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$b      = DllStructSet($a,3,"Speed Test")
$SetStr = TimerDiff($begin)

$begin  = TimerInit()
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$b      = DllStructGet($a,3)
$GetStr = TimerDiff($begin)

$begin  = TimerInit()
DllStructFree($a)
$Free   = TimerDiff($begin)

MsgBox(0,"Speeds:",_
    "DllStructCreate(): " & $Create & @CRLF & _
    "10 int DllStructSet(): " & $Set & @CRLF & _
    "10 int DllStructGet(): " & $Get & @CRLF & _
    "10 str DllStructSet(): " & $SetStr & @CRLF & _
    "10 str DllStructGet(): " & $GetStr & @CRLF & _
    "DllStructFree(): " & $Free)

The _DllMem Script:

#include <DllMem.au3>
$str    = "int;byte;char(128);int;dword;char(128)"

$begin  = TimerInit()
$a      = _DllMemCreate($str);
$Create = TimerDiff($begin)

$begin  = TimerInit()
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$b      = _DllMemSet($a,$str,3,100)
$Set    = TimerDiff($begin)

$begin  = TimerInit()
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$b      = _DllMemGet($a,$str,3)
$Get    = TimerDiff($begin)

$begin  = TimerInit()
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$b      = _DllMemSetString($a,$str,2,"Speed Test")
$SetStr = TimerDiff($begin)

$begin  = TimerInit()
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$b      = _DllMemGetString($a,$str,2)
$GetStr = TimerDiff($begin)

$begin  = TimerInit()
_DllMemFree($a)
$Free   = TimerDiff($begin)

MsgBox(0,"Speeds:",_
    "_DllMemCreate(): " & $Create & @CRLF & _
    "10 int _DllMemSet(): " & $Set & @CRLF & _
    "10 int _DllMemGet(): " & $Get & @CRLF & _
    "10 str _DllMemSetString(): " & $SetStr & @CRLF & _
    "10 str _DllMemGetString(): " & $GetStr & @CRLF & _
    "_DllMemFree(): " & $Free)
Edited by Ejoc
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

So I'm writing the help files and I had a question:

Under ###Syntax### should I write

DllStructFree ( $avArray ) <= This is technically true, but could be misleading

Or make a new variable name for the special struct array?

DllStructFree ( $avStruct )

Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

The syntax shouldn't have variable names.  Notice that with most (all?) the other built-in functions, the parameters are described with words, not with variable names.

<{POST_SNAPBACK}>

Doh, thats what I get for using a UDF as my refernce :)
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

Current code if you wanna look. Dunno when it will find it's way to a beta near you, which will help since I cant make any DllCall()'s so there might be bugs, but it looks like it should work.

Read fun lines like:

*((__int32*)(iBaseAddr+iOffset)) = (__int32)vParams[2].n64Value();

vResult = (__int64)*((__int32 *)(iBaseAddr + iOffset));

:)

500 lines of typecasting mayham:

DllStruct.zip

Edited by Ejoc
Start -> Programs -> AutoIt v3 -> AutoIt Help File -> Index -> (The Function you are asking about)----- Links -----DllStruct UDFsRSA Crypto UDFs
Link to comment
Share on other sites

Templates are very useful for generalizing casts...

Edit:

As an example, this template might work (Untested) for the second example ine:

/* Your method
vResult = (__int64)*((__int32 *)(iBaseAddr + iOffset));
*/

// My method
template<typename R, typename C, typename B> ptr_cast(B ptr)
{
    return reinterpret_cast<R*>(*(reinterpret_cast<C*>(ptr)));
}

vResult = ptr_cast<__int64, __int32>(iBaseAddre + iOffset);

Keep in mind that I did not test it and just wrote it off the top of my head. It could dereference incorrectly in that form. The key thing to look at is the last line. Notice how much cleaner the template format looks. The readability alone is worth the effort it takes to figure out the template(s).

Edited by Valik
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...