IPB
ЛогинПароль:

> ВНИМАНИЕ!

Прежде чем задать вопрос, смотрите FAQ.
Рекомендуем загрузить DRKB.

 
 Ответить  Открыть новую тему 
> Память окна, WinAPI
TarasBer
сообщение 29.09.2011 9:38
Сообщение #1


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Мне понадобилось, чтобы каждое окно помнило какую-нибудь дополнительную информацию.
Вариант с хеш-таблицей по описателю, мне кажется, не совсем архитектурен, ну как бы это объяснить, типа окно в винде, а таблица и информация - в программе.
Вот например, любое окно где-то хранит свои координаты, у него есть какой-то свой личный блок памяти, и этот блок как бы на уровне винды, извиняюсь за такую терминологию. И у каждого класса блок памяти разный по размеру и структуре. Ну и мне кажется целесообразным, чтобы эта дополнительная информация хранилась в этом же блоке памяти. В общем как задавать размер этого блока при создании класса окна, как с ним работать?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 29.09.2011 10:31
Сообщение #2


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Ну, сразу напрашивается вариант с GWL_USERDATA:
Как создавая окно передать пользовательские данные, чтобы потом при обр.сообщ. извлеч их?

Пойдет?
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 29.09.2011 16:35
Сообщение #3


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Я немного не понял про функцию GetWindowLongPtr. У меня её нет, её надо самому подключать? А к какой библиотеке и с какой сигнатурой (типа LONG_PTR у меня тоже нет)?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 29.09.2011 17:09
Сообщение #4


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


В общем, я решил сделать свой оконный класс на основе стандартного edit. Ну я, значит взял информацию о классе edit, взял его оконную процедуру запомнил (пригодится), взял его cbWndExtra (оно равно 6 почему-то), увеличил на резмер нужной мне структуры.
Потом при создании вызываю GetWindowLong(H, OldSize) (ну или GetWindowLong(H, GWL_USERDATA)), чтобы получить указатель на нужные мне данные и записать в них стартовые значения, возвращается ноль.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 29.09.2011 17:09
Сообщение #5


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Судя по тому, как оно описано в Д2009:
Прикрепленное изображение
, достаточно сделать:
function GetWindowLongPtr(hWnd: HWND; nIndex: Integer): Integer; stdcall;
external 'user32' name 'GetWindowLongPtrA';

(ну, или 'GetWindowLongPtrW', если нужна юникодная версия, прототип не меняется)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
-TarasBer-
сообщение 29.09.2011 23:13
Сообщение #6


Гость






Ааа, user32, а я её в kernel32 искал...
А что делать с этим результатом integer, если мне нужен pointer? Просто в лоб преобразовать проканает? Или спецфункция есть для этого, типа GlobalLock?
 К началу страницы 
+ Ответить 
IUnknown
сообщение 29.09.2011 23:21
Сообщение #7


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Попробовал:
            if RegisterClassEx(MyEdit) <> 0 then
begin
Result := CreateWindowEx(WS_EX_CLIENTEDGE,
SuperClassedEdit, nil,
WS_CHILD or WS_VISIBLE or ES_LEFT,
8, 16, 220, 21,
Window, 0, System.MainInstance, nil);
GetMem(DataPtr, SizeOf(MyStruct));
with DataPtr^ do
begin
color := 12; // Это так, для теста
backcolor := 18;
end;
SetWindowLongPtr(Result, GWL_USERDATA, Integer(DataPtr));
end;
- проканало, потом в оконной функции нового контрола значения читаются правильно, даже без выделения дополнительной памяти в cbWndExtra. Один указатель через GWL_USERDATA можно засунуть всегда (привожу к Integer, ибо 32-битная система, на 64-битах может сглючить, надо проверять чему равен LONG_PTR там)
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
Lapp
сообщение 30.09.2011 6:22
Сообщение #8


Уникум
*******

Группа: Модераторы
Сообщений: 6 823
Пол: Мужской
Реальное имя: Лопáрь (Андрей)

Репутация: -  159  +


Володь, не поверишь - не заходя на форум, обновил страницу с Алисой (была с тех пор в закладках). Посмотрел и хотел тебе снова посоветовать сменить аватар - теперь на фото 32. Захожу - а оно там, причем вырезано как раз, как я думал )).


--------------------
я - ветер, я северный холодный ветер
я час расставанья, я год возвращенья домой
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 30.09.2011 9:21
Сообщение #9


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


---------------------------
Точка входа в процедуру GetWindowLongPtrA не найдена в библиотеке DLL user32.
---------------------------
ОК
---------------------------


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 30.09.2011 11:16
Сообщение #10


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Цитата(TarasBer @ 30.09.2011 9:21) *
Точка входа в процедуру GetWindowLongPtrA не найдена в библиотеке DLL user32.

Ага. Я свой код компилировал под FPC, использовал готовое описание, сейчас залез в исходники:

Цитата
{$ifdef cpu64}
function GetWindowLongPtrA(hWnd:HWND; nIndex:longint):LONG_PTR; external 'user32' name 'GetWindowLongPtrA';
function SetWindowLongPtrA(hWnd:HWND; nIndex:longint; dwNewLong:LONG_PTR):LONG_PTR; external 'user32' name 'SetWindowLongPtrA';
function GetClassLongPtrA(hWnd:HWND; nIndex:longint):LONG_PTR; external 'user32' name 'GetClassLongPtrA';
function SetClassLongPtrA(hWnd:HWND; nIndex:longint; dwNewLong:LONG_PTR):LONG_PTR; external 'user32' name 'SetClassLongPtrA';
{$else}
function GetWindowLongPtrA(hWnd:HWND; nIndex:longint):LONG_PTR; external 'user32' name 'GetWindowLongA';
function SetWindowLongPtrA(hWnd:HWND; nIndex:longint; dwNewLong:LONG_PTR):LONG_PTR; external 'user32' name 'SetWindowLongA';
function GetClassLongPtrA(hWnd:HWND; nIndex:longint):LONG_PTR; external 'user32' name 'GetClassLongA';
function SetClassLongPtrA(hWnd:HWND; nIndex:longint; dwNewLong:LONG_PTR):LONG_PTR; external 'user32' name 'SetClassLongA';
{$endif}

То есть, можешь заменить на 'GetWindowLongA'. Хотя при более внимательном прочтении MSDN выясняется, что там об этом тоже говорится:
Цитата
Note To write code that is compatible with both 32-bit and 64-bit versions of Windows, use GetWindowLongPtr. When compiling for 32-bit Windows, GetWindowLongPtr is defined as a call to the GetWindowLong function.
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 3.10.2011 9:21
Сообщение #11


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


Ну хорошо, с USER_DATA работает. Но это нечестный метод. А если я захочу на основе этого нового класса составить ещё один класс, с ещё какой-то дополнительной информацией? Тогда ведь USER_DATA нового класса затрёт USER_DATA старого, и что делать, чтобы такого не было?


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
IUnknown
сообщение 3.10.2011 13:48
Сообщение #12


a.k.a. volvo877
*****

Группа: Пользователи
Сообщений: 1 013
Пол: Мужской

Репутация: -  627  +


Что ж нечестного? Все как раз нормально, если ты наследуешься от того, что уже само унаследовано - будь добр в структуре, которую выделяешь в памяти и ссылку на которую оставляешь в USERDATA, предусмотреть поле Parent, которое будет хранить ссылку на данные, выделенные предком. То есть, в инициализаторе (конструкторе) потомка выделяешь память под нужный объем данных + Parent, в Parent считываешь текущее значение GWL_USERDATA, и потом пишешь новый указатель в GWL_USERDATA. Освобождать память - в обратном порядке...

Могу дать ссылку по работе с выделяемой памятью (увеличение cbWndExtra), но это делают только на Бейсике почему-то, ни на Дельфи ни на С++ я такого не встречал. А в том, как оно работает на Бейсике - честно говоря не совсем разобрался. Может у тебя получится? Вот: Take control of your window(s) [SUPERCLASS]
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
TarasBer
сообщение 3.10.2011 16:10
Сообщение #13


Злостный любитель
*****

Группа: Пользователи
Сообщений: 1 755
Пол: Мужской

Репутация: -  62  +


До меня дошло. Я думал, что если я запомню старое значение cbWndExtra и увеличу его, то GetWindowLong от старого зачения даст мне указатель на добавленный хвост буфера. А на самом деле GetWindowLong возвращает указатель, хранящийся в том хвосте!
Теперь работает.


--------------------
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0

 



- Текстовая версия 3.05.2024 16:06
Хостинг предоставлен компанией "Веб Сервис Центр" при поддержке компании "ДокЛаб"