Sign in to follow this  
Followers 0

DllStruct Dev

71 posts in this topic

Posted (edited)

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

Share this post


Link to post
Share on other sites



Posted

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

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Posted

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

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Posted

$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

Share this post


Link to post
Share on other sites

Posted

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.

Share this post


Link to post
Share on other sites

Posted

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

Share this post


Link to post
Share on other sites

Posted

Ok got a working version, I'll get a submision setup, I need to make a help file explaining how the functions work and that file saying where to put the new code.

:)

Share this post


Link to post
Share on other sites

Posted

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)

Share this post


Link to post
Share on other sites

Posted

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"! :)

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Posted

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 )

Share this post


Link to post
Share on other sites

Posted

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.

Share this post


Link to post
Share on other sites

Posted

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

Share this post


Link to post
Share on other sites

Posted

Is there anyway to know if my submission found it's way to the right place?

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Posted (edited)

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

Share this post


Link to post
Share on other sites

Posted

Templates are very useful for generalizing casts...

<{POST_SNAPBACK}>

Thats one of those C++ thingies

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