How to get pointer to a string stored in an array element?

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

How to get pointer to a string stored in an array element?

09 May 2023, 04:42

As the title says!
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: How to get pointer to a string stored in an array element?

09 May 2023, 04:56

@just me, Does this answer your question?

Code: Select all

a := ['hello']
MsgBox StrPtr(a[1])
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to get pointer to a string stored in an array element?

09 May 2023, 05:06

@iPhilip,

thanks, but it doesn't.

Code: Select all

StrPtr(a[1])
apparently returns the address of a temporary buffer which will be reused by the script.

Code: Select all

Arr := ["Hello!", "Olleh!"]
Ptr1 := StrPtr(Arr[1])
Ptr2 := StrPtr(Arr[2])
MsgBox("This should be 'Hello!': " . StrGet(Ptr1))
teadrinker
Posts: 4336
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to get pointer to a string stored in an array element?

09 May 2023, 06:08

Using bruteforce:

Code: Select all

arr := ['a', 'b', 'c', 'd', 'e']
pObj := ObjPtr(arr)
Loop arr.Length {
    MsgBox StrGet(NumGet(NumGet(pObj + A_PtrSize*4, 'Ptr') + A_PtrSize*2*(A_Index - 1), 'Ptr') + A_PtrSize*2)
}
However, so far it only works for 64 bits.
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to get pointer to a string stored in an array element?

09 May 2023, 06:32

Hi @teadrinker,

thanks. But there's someone called @lexikos always objecting the use of undocumented implementation details. ;)
teadrinker
Posts: 4336
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to get pointer to a string stored in an array element?

09 May 2023, 06:49

I don't think there is a "legal" way.
For both:

Code: Select all

arr := ['a', 'b', 'c', 'd', 'e']
pObj := ObjPtr(arr)
Loop arr.Length {
    MsgBox StrGet(NumGet(NumGet(pObj + 8 + A_PtrSize*3, 'Ptr') + 16*(A_Index - 1), 'Ptr') + A_PtrSize*2)
}
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to get pointer to a string stored in an array element?

09 May 2023, 07:16

I agree. I looked for a replacement for Obj.GetAddress() but it seems to be a thing for the wish list.
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: How to get pointer to a string stored in an array element?

09 May 2023, 11:34

This approach seems to work:

Code: Select all

Arr := ["Hello!", "Olleh!"]
o1 := Buffer(20)
StrPut(Arr[1], o1)
o2 := Buffer(20)
StrPut(Arr[2], o2)
MsgBox("This should be 'Hello!': " . StrGet(o1))
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
teadrinker
Posts: 4336
Joined: 29 Mar 2015, 09:41
Contact:

Re: How to get pointer to a string stored in an array element?

09 May 2023, 11:48

@iPhilip
Ha-ha, no. o1.ptr is not the actual address of the first array item.
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to get pointer to a string stored in an array element?

09 May 2023, 13:54

@iPhilip, thanks. Your suggestion actually shows the problem. You have to copy the string to get a valid reliable pointer.
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: How to get pointer to a string stored in an array element?

09 May 2023, 19:16

teadrinker wrote:
09 May 2023, 11:48
@iPhilip
Ha-ha, no. o1.ptr is not the actual address of the first array item.
@teadrinker, You are right. That was the only way I could figure to save an address to the string. :think:
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: How to get pointer to a string stored in an array element?

09 May 2023, 19:18

just me wrote:
09 May 2023, 13:54
@iPhilip, thanks. Your suggestion actually shows the problem. You have to copy the string to get a valid reliable pointer.
I guess this should go into a wish list request. It seems important, though @lexikos might look for a use case to justify the effort.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
just me
Posts: 9467
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: How to get pointer to a string stored in an array element?

10 May 2023, 04:43

Hi @iPhilip,

my use case:

The TaskDialogIndirect() funktion expects a TASKDIALOGCONFIG structure containing pointers to arrays of TASKDIALOG_BUTTON structures which contain the ID and a pointer to the caption string of the buttons.

In v1, it was possible to use an AHK array for the button captions and get the pointers using Array.GetAddress(Index). GetAddress() has been removed in v2. The new funktion StrPtr() cannot be used because for array elements it obviously returns a pointer to an internal buffer which AHK might reuse as soon as required. So I have to copy the strings from the array, e.g.

Code: Select all

   Chars := 0
   For Str In Radios ; AHK array of button captions
      Chars += StrLen(Str) + 1
   Tmp := Buffer(Chars * 2, 0)
   Addr1 := Tmp.Ptr
   RBArr := Buffer(TDBSize * RBCount, 0) ; C array of TASKDIALOG_BUTTON structures
   Addr2 := RBArr.Ptr
   For I, V In Radios {
      Len := StrPut(V, Addr1)
      Addr2 := NumPut("Int", MinRID + A_Index, "Ptr", Addr1, Addr2)
      Addr1 += Len
   }
It's neither convenient nor performant respectively resource saving.

@lexikos, any chance for a change?
User avatar
kczx3
Posts: 1643
Joined: 06 Oct 2015, 21:39

Re: How to get pointer to a string stored in an array element?

10 May 2023, 14:29

I think that makes sense based on the documentation for StrPtr since it says, "The address of a temporary string is valid only until evaluation of the overall expression or function call statement is completed...". It doesn't allow for storing of the address and then use later. Since you're trying to put it into a structure first, then send it later it won't work. Bummer.
iseahound
Posts: 1450
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get pointer to a string stored in an array element?

11 May 2023, 14:01

In my opinion, I would go with the hacky route from teadrinker, or force the use of a sentinel.

Code: Select all

#Requires AutoHotkey v2.0

Arr := ["Hello!", "Olleh!"]
Ptr1 := StrPtr(_1 := Arr[1])
Ptr2 := StrPtr(_2 := Arr[2])
MsgBox("This should be 'Hello!': " . StrGet(Ptr1))
You need one sentinel per StrPtr, and this "minimizes" any damage done. (Er, basically just name your array element and pass that onto strptr)
iseahound
Posts: 1450
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get pointer to a string stored in an array element?

11 May 2023, 14:05

But to clarify, StrPtr would only operate on a string. You can't really pass StrPtr(Arr[1]), as it's technically a race condition. You're evaluating Arr[1] into some temporary buffer, and StrPtr gets the address of the temporary buffer. You really should iterate through the object pointer as teadrinker has shown, in lieu of GetAddress.

I think the cleanest approach is to take teadrinker's code, and make it a method of your array and call that GetAddress or GetString :D
iPhilip
Posts: 822
Joined: 02 Oct 2013, 12:21

Re: How to get pointer to a string stored in an array element?

12 May 2023, 01:53

iseahound wrote:
11 May 2023, 14:05
But to clarify, StrPtr would only operate on a string. You can't really pass StrPtr(Arr[1]), as it's technically a race condition. You're evaluating Arr[1] into some temporary buffer, and StrPtr gets the address of the temporary buffer. You really should iterate through the object pointer as teadrinker has shown, in lieu of GetAddress.
@iseahound, Thank you for your explanation. It's very helpful. Can you explain what you mean by race condition in this context? My understanding is that a race condition occurs when two or more threads can access shared data and they try to change it at the same time.
Windows 10 Pro (64 bit) - AutoHotkey v2.0+ (Unicode 64-bit)
Helgef
Posts: 4709
Joined: 17 Jul 2016, 01:02
Contact:

Re: How to get pointer to a string stored in an array element?

12 May 2023, 13:19

I would make a suitable object for the job, eg,

Code: Select all

class str_arr extends array {
	; also do __new if desired
	__item[k]{
		get => strget(super[k])
		set {
			b := buffer(strlen(value) * 2 + 2)
			strput value, b
			return super[k] := b
		}
	}
	ptr(k) => super[k].ptr
}
Cheers.
iseahound
Posts: 1450
Joined: 13 Aug 2016, 21:04
Contact:

Re: How to get pointer to a string stored in an array element?

12 May 2023, 23:15

The temporary buffer can be reused by the next variable assignment. That means there is a race condition, in line with your definition. However, this technically will never occur, as StrPtr() is the next call, and the function that uses the string pointer afterwards.

I think Lexikos also says that it wont be a race condition (implicitly).
https://www.autohotkey.com/docs/v2/v2-changes.htm#EnvUpdate wrote:

Code: Select all

SendMessage(0x1A, 0, StrPtr("Environment"), 0xFFFF)
Notice the use of a temporary string buffer here.
User avatar
kczx3
Posts: 1643
Joined: 06 Oct 2015, 21:39

Re: How to get pointer to a string stored in an array element?

13 May 2023, 07:40

Not really though. StrPtr on a literal will be valid for the length of the process

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: Google [Bot], mikeyww, niCode, william_ahk and 67 guests