recreating AHK v2's Buffer object

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

30 May 2019, 17:17

Here's a BufferAlloc function:

BufferAlloc - Syntax & Usage | AutoHotkey v2
https://lexikos.github.io/v2/docs/commands/BufferAlloc.htm
Buffer Object - Definition & Usage | AutoHotkey v2
https://lexikos.github.io/v2/docs/objects/Buffer.htm

Code: Select all

BufferAlloc(Size)
{
	return new Buffer(Size)
}
class Buffer
{
	;note: Buffer.Data does not handle nulls as AHK v2 does
	__New(Size)
	{
		this.SetCapacity("_buf", Size)
		this._size := size
		DllCall("ntdll\RtlFillMemory", "Ptr",this.GetAddress("_buf"), "UPtr",Size, "UChar",0)
	}
	Size
	{
		get
		{
			return this._size
		}
		set
		{
			if !(value = this._size)
				this.SetCapacity("_buf", value)
			if (value > this._size)
				DllCall("ntdll\RtlFillMemory", "Ptr",this.GetAddress("_buf")+this._size, "UPtr",value-this._size, "UChar",0)
			return this._size := value
		}
	}
	Ptr
	{
		get
		{
			return this.GetAddress("_buf")
		}
		set
		{
			throw Exception("Invalid usage.", -1)
		}
	}
	Data
	{
		get
		{
			return StrGet(this.GetAddress("_buf"), this._size/2, "UTF-16")
		}
		set
		{
			throw Exception("Invalid usage.", -1)
		}
	}
	__Get(k, Params*)
	{
		if !(k = "Ptr")
		&& !(k = "Size")
			throw Exception("Unknown property.", -1)
	}
	__Set(k, Params*)
	{
		if !(k = "_size")
		&& !(k = "Data")
		&& !(k = "Ptr")
		&& !(k = "Size")
			throw Exception("Unknown property.", -1)
	}
	__Call(m, Params*)
	{
		if !(m = "GetAddress")
		&& !(m = "SetCapacity")
			throw Exception("Unknown method.", -1)
	}
}
old versions
Last edited by jeeswg on 31 May 2019, 14:32, edited 12 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: commands as functions (AHK v2 functions for AHK v1)

30 May 2019, 21:11

jeeswg wrote:
30 May 2019, 17:17
Here's a BufferAlloc function:

Code: Select all

BufferAlloc(Size)
{
	return new Buffer(Size)
}
class Buffer
{
	static __id := 0
	__New(Size)
	{
		global
		Buffer.__id++
		zAHKFC_BufferTemp := Buffer.__id
		VarSetCapacity(zAHKFC_Buffer%zAHKFC_BufferTemp%, Size)
		this.__id := Buffer.__id
		this.Ptr := &zAHKFC_Buffer%zAHKFC_BufferTemp%
		this.Size := Size
	}
	__Delete()
	{
		global
		zAHKFC_BufferTemp := this.__id
		zAHKFC_Buffer%zAHKFC_BufferTemp% := ""
	}
	Data
	{
		get
		{
			global
			zAHKFC_BufferTemp := this.__id
			return StrGet(this.Ptr, this.Size/2, "UTF-16")
		}
	}
}
do you really need to populate global scope?

swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 05:54

please, replace this with a proper GlobalAlloc raii class lol
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 07:09

You should also read the docs on Buffer.data. Although I don't think this property is generally useful. I don't think you can implement .data without relying on undocumented behaviour in v1. Disregarding the pollution of the global variable namespace, interruptions may cause very undesirable behaviour.

Cheers-
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 07:46

@guest3456: do you really need to quote the whole post? Hehe.
Perhaps I can pipe everything through a general '_Main' method in the class, hmm. And store the data as static variables inside it.

@Helgef: Doesn't AHK v1 always truncate returned values, and so there isn't really a solution. Yes, I had thought that .Data wasn't generally too useful.
I've improved the code, and added a comment re. .Data.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:06

Code: Select all

static ID := 0
ID++
VarSetCapacity(zAHKFC_Buffer%ID%, Size, 0)
this.__id := ID
This is still not safe with interruptions.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:20

OK, I've fixed the class. Please state if any problems remain with the old/new versions. Cheers.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:31

Code: Select all

static Count := 0
Count++
this.__id := Count
still not safe with interruptions.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:41

- I've changed it to this:
this.__id := Count++
- Would anything else remain after that?

- So in short, the problems you mention are because static variables in functions can be changed by multiple (i.e. simultaneous/overlapping) function calls.
- One thing that has come up re. that, is it possible to specify a *non-static* variable, in a function where all the variables are static. A non-static variable is safe because it is unique to the function call.
- These problems are fundamental, but I'd never really had to deal with them before.
- Another issue is that using this.key would be safe, but you can't do var%this.key% in AHK v1 (at present).
- As a workaround, when I use a static variable that I'd rather have as non-static, I bunch it up with other statements into multi-statement. I.e. you can safely use the static variable, within the context of a multi-statement, because the multi-statement can't be interrupted.
- Another workaround could be to add a parameter variable, to the list of the function's/method's parameters, and use that.

- [EDIT:] It turns out that you *can* use 'local' to make a variable, in an assume-static function, non-static. This is stated in the documentation, and demonstrated here:

Code: Select all

q:: ;test non-static variable in an assume-static function
oFunc := Func("MyStaticNonStaticFunc").Bind(6)
SetTimer, % oFunc, -500
MyStaticNonStaticFunc(3)
return

MyStaticNonStaticFunc(vNum)
{
	static
	local vNonStat
	vStat := vNum
	vNonStat := vNum
	MsgBox, % vStat " " vNonStat
	MsgBox, % vStat " " vNonStat
}
- One reason for uncertainty, is that 'local' plus 'static', as mentioned in the quote below, results in static variables. This sounds like a contradiction, local (non-static) variables that are static, but, 'local', in this context, is used to avoid situations where dynamic variable names, e.g. %myvar%, refer to global variables.
Functions - Definition & Usage | AutoHotkey
https://autohotkey.com/docs/Functions.htm#static
In assume-static mode, any variable that should not be static must be declared as local or global (with the same exceptions as for assume-local mode, unless force-local mode is also in effect).

[v1.1.27+]: Force-local mode can be combined with assume-static mode by specifying local and then static, as shown below. This allows the function to use force-local rules but create variables as static by default.
Last edited by jeeswg on 31 May 2019, 09:18, edited 3 times in total.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 08:54

So in short
yes
is it possible to specify a *non-static* variable, in a function where all the variables are static
assume-static mode wrote:In assume-static mode, any variable that should not be static must be declared as local or global
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:00

creating one variable per call is still a pretty poor approach. You can use another allocation method than varsetcapacity, either via dllcall or setCapacity.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:37

Can you explain further what you mean? Thanks.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:45

Example

Code: Select all

class Buffer
{
	;note: Buffer.Data does not handle nulls as AHK v2 does
	__New(Size)
	{
		this.setcapacity("buf", size) ; doesn't zero init.
		this._size := size
	}
	Ptr
	{
		get
		{
			return this.getAddress("buf")
		}
		; set should throw
	}
	Size
	{
		get
		{
			return this._size
		}
		; set should realloc
	}
	Data
	{
		get
		{
			return StrGet(this.Ptr, this.Size/2, "UTF-16")
		}
		; set should throw.
	}
	; you can use __set or __get to throw for other invalid use.
}
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:47

ObjSetCapacity to create the key, ObjGetAddress to get the address.
But wasn't there some problem where object keys are automatically updated, and so can't store binary data?
And DllCall, which Winapi function?
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 09:57

But wasn't there some problem where object keys are automatically updated, and so can't store binary data?
No.

You can call malloc, swagfag mentioned GlobalAlloc.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 10:13

- Thanks for the Winapi mentions. Although, I might have thought that AHK variables were better optimised versus using DllCall.

- RtlFillMemory can be used to fill a buffer with zeros, after ObjSetCapacity.

- Here's a link, where StrLen works differently on string variables versus strings stored in object keys.
Allow AutoHotkey to Handle Binary Data - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=13&t=61502&p=265002#p265002
- Since storing binary data in an object key is undocumented, how am I to know that the class will work reliably? You appear to be promoting the use of undocumented functionality, this is surprising!
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 12:06

Hoist with his own petard.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 12:20

When all else fails there's always delusion.
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

Re: commands as functions (AHK v2 functions for AHK v1)

31 May 2019, 12:35

Chickens coming home to roost.

After the way you've attacked people for doing anything not explicitly mentioned in the documentation. I was curious to see how you'd handle the situation ...
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: No registered users and 348 guests