1 (изменено: MandarinKa02, 2018-07-27 00:33:23)

Тема: AHK: как получить адрес переменной внутри класса

Вопрос в заголовке.


Допустим, возьмем какой-нибудь мессенджер. Будет в нем некий класс "обработчик сообщений" (_msgprocessor). Он инициализируется при запуске скрипта.


;start
processor:=new _msgprocessor

;предположим, что здесь идет цикл listen - он слушает порт,
;при получении пакета, обрабатывает его и в конце получает присланное сообщение
num:=439
msg:="Привет, мир!"
processor.new(num,msg) ;посылаем обработчику сообщение

;потом тут идет несколько проверок на целостность пакета, не затерялась ли информация
;и только потом сообщение записывается в файл
processor.set()
return

class _msgprocessor {
	static data, size
	new(num, msg) {
		this.data:="#" num " - " msg "`n"
		this.size:=StrLen(this.data) * A_IsUnicode?2:1
	}
	set() {
		H:=File_Open("Write", A_Desktop "\list.bin")
		File_Write(H, &this.data, this.size) ;ну и здесь не работает, т.к. &this.data = ничему
		File_Close(H)
	}
}


+ lib

CopyBinData(ptrSource, ptrDestination, iLength) {
	If iLength ;Only do it if there's anything to copy
		DllCall("RtlMoveMemory", "Ptr", ptrDestination, "Ptr", ptrSource, "UInt", iLength)
}

/*! TheGood
	Simple file functions
	http://www.autohotkey.com/forum/viewtopic.php?t=56510
*/

File_Open(sType, sFile) {

	bRead := InStr(sType, "READ")
	bSeq  := sType = "READSEQ"

	;Open the file for writing with GENERIC_WRITE/GENERIC_READ, NO SHARING/FILE_SHARE_READ & FILE_SHARE_WRITE, and
	;OPEN_ALWAYS/OPEN_EXISTING, and FILE_FLAG_SEQUENTIAL_SCAN
	hFile := DllCall("CreateFile", "Str", sFile, "UInt", bRead ? 0x80000000 : 0x40000000, "UInt", bRead ? 3 : 0, "Ptr", 0
								 , "UInt", bRead ? 3 : 4, "UInt", bSeq ? 0x08000000 : 0, "Ptr", 0, "Ptr")
	If (hFile = -1 Or ErrorLevel) { ;Check for any error other than ERROR_FILE_EXISTS
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return -1 ;Return INVALID_HANDLE_VALUE
	} Else Return hFile
}

File_Read(hFile, ByRef bData, iLength = 0) {

	;Check if we're reading up to the rest of the file
	If Not iLength ;Set the length equal to the remaining part of the file
		iLength := File_Size(hFile) - File_Pointer(hFile)

	;Prep the variable
	VarSetCapacity(bData, iLength, 0)

	;Read the file
	r := DllCall("ReadFile", "Ptr", hFile, "Ptr", &bData, "UInt", iLength, "UInt*", iLengthRead, "Ptr", 0)
	If (Not r Or ErrorLevel) {
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return -1
	} Else Return iLengthRead
}

File_Write(hFile, ptrData, iLength) {

	;Write to the file
	r := DllCall("WriteFile", "Ptr", hFile, "Ptr", ptrData, "UInt", iLength, "UInt*", iLengthWritten, "Ptr", 0)
	If (Not r Or ErrorLevel) {
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return -1
	} Else Return iLengthWritten
}

File_Pointer(hFile, iOffset = 0, iMethod = -1) {

	;Check if we're on auto
	If (iMethod = -1) {

		;Check if we should use FILE_BEGIN, FILE_CURRENT, or FILE_END
		If (iOffset = 0)
			iMethod := 1 ;We're just retrieving the current pointer. FILE_CURRENT
		Else If (iOffset > 0)
			iMethod := 0 ;We're moving from the beginning. FILE_BEGIN
		Else If (iOffset < 0)
			iMethod := 2 ;We're moving from the end. FILE_END
	} Else If iMethod Is Not Integer
		iMethod := (iMethod = "BEGINNING" ? 0 : (iMethod = "CURRENT" ? 1 : (iMethod = "END" ? 2 : 0)))

	r := DllCall("SetFilePointerEx", "Ptr", hFile, "Int64", iOffset, "Int64*", iNewPointer, "UInt", iMethod)
	If (Not r Or ErrorLevel) {
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return -1
	} Else Return iNewPointer
}

File_Size(hFile) {
	r := DllCall("GetFileSizeEx", "Ptr", hFile, "Int64*", iFileSize)
	If (Not r Or ErrorLevel) {
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return -1
	} Else Return iFileSize
}

File_Close(hFile) {
	If Not (r := DllCall("CloseHandle", "Ptr", hFile)) {
		ErrorLevel := ErrorLevel ? ErrorLevel : A_LastError
		Return False
	} Return True
}

2 (изменено: MandarinKa02, 2018-07-27 00:33:34)

Re: AHK: как получить адрес переменной внутри класса

*DELETED*

3 (изменено: MandarinKa02, 2018-07-27 00:33:40)

Re: AHK: как получить адрес переменной внутри класса

*DELETED*

4 (изменено: stealzy, 2018-04-06 00:55:27)

Re: AHK: как получить адрес переменной внутри класса

static data:="everything", pdata := &data
...
this.pdata

Некоторые команды не умеют работать напрямую с объектами/массивами/..., приходится использовать переменные-посредники.
Мессенджер это круто . У вас уже есть сервер или это для локалки?

5 (изменено: MandarinKa02, 2018-04-06 00:58:22)

Re: AHK: как получить адрес переменной внутри класса

stealzy, да, я заметил ваше сообщение. Сейчас пытаюсь применить.

> Ссылка на переменную меняется.


	;CopyBinData() есть в посте выше
	v1:="text"
	p1:=&v1

	v1:="more text"
	p2:=&v1
	msgbox % p1 "-" p2

	VarSetCapacity(v1, 100,0)
	var:="noname"
	CopyBinData(&var, p1, StrLen(var)*2)
	msgbox % v1
	CopyBinData(&var, p2, StrLen(var)*2)
	msgbox % v1

6

Re: AHK: как получить адрес переменной внутри класса

У вас уже есть сервер или это для локалки?

Я сейчас с пакетами работаю, а мессенджер в качестве примера привел. Но такое в силах организовать :0

7 (изменено: stealzy, 2018-04-06 01:19:57)

Re: AHK: как получить адрес переменной внутри класса

Ясненько. Хотя язык AHK и кажется "безтиповым", типы все-таки внутри есть. Разные типы занимают разное место в памяти.
Если вы записываете в переменную значение, которое не влазит в старый тип, она записывается в другую область памяти.

v1:="text", p1:=&v1
v1:="more te", p2:=&v1 ; < 8 byte
msgbox % p1 "-" p2
v1:="more text", p2:=&v1 ; > 8 byte
msgbox % p1 "-" p2

8 (изменено: teadrinker, 2018-04-06 01:27:51)

Re: AHK: как получить адрес переменной внутри класса

stealzy пишет:

Хотя язык AHK и кажется "безтиповым", типы все-таки внутри есть.

А разве переменные в AHK не являются всегда строками? И разве в этом примере меняется тип данных?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: как получить адрес переменной внутри класса

Я конечно неправильно называю это "типами", потому что не владею терминами, но суть думаю передал.

10

Re: AHK: как получить адрес переменной внутри класса

А разве переменные в AHK не являются всегда строками?

Та ну, если бы они и были строками, то в таком бы случае не работали операторы ><
AHK определяет, что записывают в переменную, строка ли это или может число. И на уровне c++ присваивается тип переменной.
(Лично я думаю, что так и происходит)

11 (изменено: MandarinKa02, 2018-04-06 01:49:53)

Re: AHK: как получить адрес переменной внутри класса

В общем, происходит тут что-то странное..

+ открыть спойлер

v1:="something", p1:=&v1
msgbox % ShowInfo(v1, "v1", p1)

v1:="some" ;уменьшаем кол-во байт (по сути адрес переменой должен остаться без сдвига)
p2:=&v1
msgbox % ShowInfo(v1, "v1", p2) ;убеждаемся в этом :)

v1:="more more more text..."
p3:=&v1
msgbox % ShowInfo(v1, "v1", p3) ;а тут что-то пошло не так

msgbox % p1 "-" p2 "-" p3





ShowInfo(var, name, ptr) {
	msg := name "=" var "`n"
	     . "ptr=" ptr "`n"
	     . "size=" StrLen(var)*(A_IsUnicode?2:1) ;т.к. у меня Unicode32, то у меня строка будет весить - (кол-во символов*2)
	return msg
}

F5::Reload

А теперь давайте, поменяем немного местами переменные. А вернее, значения.

+ открыть спойлер


v1:="some", p1:=&v1
msgbox % ShowInfo(v1, "v1", p1)

v1:="something" ;происходит сдвиг
p2:=&v1
msgbox % ShowInfo(v1, "v1", p2) "`n" "Сдвинули на " p2-p1

v1:="more more more text..."
p3:=&v1
msgbox % ShowInfo(v1, "v1", p3) "`n" "Сдвинули на " p3-p2

msgbox % p1 "-" p2 "-" p3





ShowInfo(var, name, ptr) {
	msg := name "=" var "`n"
	     . "ptr=" ptr "`n"
	     . "size=" StrLen(var)*(A_IsUnicode?2:1) ;т.к. у меня Unicode32, то у меня строка будет весить - (кол-во символов*2)
	return msg
}

F5::Reload

12

Re: AHK: как получить адрес переменной внутри класса

MandarinKa02 пишет:

А разве переменные в AHK не являются всегда строками?

Та ну, если бы они и были строками, то в таком бы случае не работали операторы ><
AHK определяет, что записывают в переменную, строка ли это или может число. И на уровне c++ присваивается тип переменной.
(Лично я думаю, что так и происходит)

Напрасно думаете. Всегда можно проверить, какие данные в переменной, получив их с помощью NumGet по адресу переменной.
Опреаторы >< в AHK работают и со строками.

MsgBox, % ("abc" > "def") "`n" ("abc" < "def")
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

13 (изменено: stealzy, 2018-04-06 03:20:43)

Re: AHK: как получить адрес переменной внутри класса

Все логично, вы неправильно думаете о размещении в памяти как о "сдвиге", это не так. Длина текста не влияет напрямую на размещение, влияет только вмещается ли объем переменной в текущую структуру или нет. И "something", и "more more more text..." вмещается в размер структуры 64 Кб, остальное не важно.

v1:="<8", p1:=&v1

v1:="12345678" ; под переменную выделяется другое место большей вместимости
p2:=&v1

v1:="8 <= chars < 64", p3:=&v1 ; нужды выделять другое место нет - влезает и так

v1:="64 chars here. iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii"
p4:=&v1

msgbox % p1 " " p2 " " p3 " " p4

Представьте себе склад с полками разной высоты для разных товаров. Каждый товар ставят на полку самой маленкой высоты, где он может поместится. Выделение памяти в си организовано аналогичным образом. Даже если над товаром остается много пустого места, на него сверху ничего не кладут. Это называется выравниванием.

14

Re: AHK: как получить адрес переменной внутри класса

Операторы >< в AHK работают и со строками.

Что-то новенькое.
stealzy, спасибо за ответ.

И ещё один конечный вопрос: как задать размер переменной, используя адрес на эту переменную. Проверял проделать такое с VarSetCapacity(), результат немного не тот.


data:="everything", ptr:=&data
VarSetCapacity(ptr, 128,0) ;задается размер для переменной-указатель
VarSetCapacity(*ptr,128,0) ;разименовывание не робит :(

15

Re: AHK: как получить адрес переменной внутри класса

MandarinKa02 пишет:

Операторы >< в AHK работают и со строками.

Что-то новенькое.

Испокон веков работали.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

16 (изменено: MandarinKa02, 2018-04-06 18:34:40)

Re: AHK: как получить адрес переменной внутри класса

teadrinker, а что оно сравнивает? Кол-во символов в строках?(вычитал, что такое организовано в питоне)
На практике мне не приходилось сравнить строки, только числовые переменные. Да и не знал, что такое может быть.

17

Re: AHK: как получить адрес переменной внутри класса

Сравнивает строки по алфавитному порядку.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

18

Re: AHK: как получить адрес переменной внутри класса

MandarinKa02 пишет:

как задать размер

В момент создания.

19 (изменено: MandarinKa02, 2018-04-09 14:10:48)

Re: AHK: как получить адрес переменной внутри класса

Решил проблему, создав в классе такую функцию:


binary(func, ptr=0,len=0) {
		static bin,size:=16
		if (func="getptr") {
			return &bin
		} else if (func="getsize") {
			return size
		} else if(func="set") {
			if(!ptr||!len)
				return 0
			VarSetCapacity(bin, len, 0)
			CopyBinData(ptr, &bin, len)
			size:=len
			return 1
		}
	}