Форум: "Прочее";
Текущий архив: 2016.01.03;
Скачать: [xml.tar.bz2];
ВнизНикто не хочет задачку от GunSmoker-а решить? :) Найти похожие ветки
← →
Rouse_ © (2015-04-29 21:56) [0]Сама задача: http://www.gunsmoker.ru/2015/04/task-18.html
Если чесно я не смог, и сделал обоснование почему не смог:
http://alexander-bagel.blogspot.ru/2015/04/18-gunsmoker.html
← →
Дмитрий С © (2015-04-29 22:10) [1]Код в задаче и у тебя разный.
← →
Kilkennycat © (2015-04-29 22:12) [2]
if AWnd = Wnd then
после си я такое видеть спокойно не могу...
← →
Дмитрий С © (2015-04-29 22:21) [3]Мне кажется дело вот в чем:
Передаем мы значение LPARAM(Wnd)
А ожидаем указатель на значение const AParam: LPARAM
← →
Rouse_ © (2015-04-29 22:59) [4]
> Дмитрий С © (29.04.15 22:10) [1]
> Код в задаче и у тебя разный.
Как это?
Первая часть обзора была по первому вопросу: http://www.gunsmoker.ru/2015/04/task-18-1.html
Вторая, по второму: http://www.gunsmoker.ru/2015/04/task-18.html
Собственно первый не интересен, ситуемина именно со вторым :)
← →
Eraser © (2015-04-29 23:00) [5]Не совсем понятно, в чем суть задачи.
Это я прочитал от предыдущего вопроса.
>> Не обращайте внимание на его бессмысленность, вопрос не в этом, а в корректности кода.
Но код то вполне рабочий, по крайней мере у меня.
← →
Rouse_ © (2015-04-29 23:00) [6]
> Передаем мы значение LPARAM(Wnd)
> А ожидаем указатель на значение const AParam: LPARAM
Это как так? Что передали на EnumWindows то и получили в LPARAM без указателей а как есть.
← →
Rouse_ © (2015-04-29 23:01) [7]
> Eraser © (29.04.15 23:00) [5]
> Не совсем понятно, в чем суть задачи.
В том что в данном коде есть ошибка.
← →
Кто б сомневался © (2015-04-29 23:21) [8]Вариант A с багом, почему Rouse рассказал, даже на него попадал,
Поэтому так делаю:
var
vData: TDataRec;
function EnumWindowsProc(aWindow: HWND; aData: LPARAM): Bool; stdcall;
..
EnumWindows(@EnumWindowsProc, LPARAM(@vData));
Вариант отработан годами.
в варианте B вроде нет проблем, кроме того что меня const смущают, но разбираться влом :) .
← →
Eraser © (2015-04-29 23:33) [9]да вариант A вообще дырявый, чего только стоит обращение к Caption, а вот со вторым засада )
← →
Rouse_ © (2015-04-29 23:37) [10]Второй меня вообще убил - ну нет там блин ошибки :)))
← →
Rouse_ © (2015-04-29 23:41) [11]
> кроме того что меня const смущают, но разбираться влом :
> ) .
const перепроверял - асм выхлоп идентичен.
← →
Rouse_ © (2015-04-29 23:43) [12]Да и тем более параметры идут не BYREF, а const - сугубо дельфийский момент работающий как директива.
← →
Eraser © (2015-04-29 23:52) [13]В варианте А у меня ошибку гарантированно дает вот такой код (причем 64 битная версия сыпется с AV)
procedure TForm1.Button2Click(Sender: TObject);
function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall;
begin
Caption := "OK";
Result := True;
end;
begin
EnumWindows(@EnumWindowsProc, 0);
end;
возможно, что-то связанное с этим и в варианте Б.
> Кто б сомневался © (29.04.15 23:21) [8]procedure TForm1.Button2Click(Sender: TObject);
var
//Wnd: HWND;
vData: Integer;
function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall;
begin
Caption := "OK";
Result := True;
end;
begin
//Wnd := Handle;
EnumWindows(@EnumWindowsProc, LPARAM(@vData));
//EnumWindows(@EnumWindowsProc, 0);
end;
аналогично.
← →
Кто б сомневался © (2015-04-29 23:56) [14]
> Eraser © (29.04.15 23:33) [9]
>
> да вариант A вообще дырявый, чего только стоит обращение
> к Caption
> Eraser © (29.04.15 23:52) [13]
> В варианте А у меня ошибку гарантированно дает вот такой
> кодfunction EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall;
begin
Caption := "OK";
Вас там двое чтоле?
← →
Rouse_ © (2015-04-30 00:02) [15]
> Eraser © (29.04.15 23:52) [13]
> В варианте А у меня ошибку гарантированно дает вот такой
> код
Так ясен пень, тыж мое обоснование сначала прочти.
http://alexander-bagel.blogspot.ru/2015/04/18-gunsmoker.html
Кому ты Caption меняешь, если Self не доступен?
← →
Кто б сомневался © (2015-04-30 00:03) [16]Второму Eraser: в EnumWindowsProc нельзя обращаться к любым переменным, которые находятся вне EnumWindowsProc = AV. Только перекидывать адрес через LPARAM.
← →
Rouse_ © (2015-04-30 00:04) [17]Народ вон уже сделал первое предположение что CONST в 64 битах может повести себя не так как задумано:
http://www.gunsmoker.ru/2015/04/task-18.html
Завтра буду проверять.
← →
Eraser © (2015-04-30 00:08) [18]
> Кто б сомневался © (30.04.15 00:03) [16]
я это понимаю, там другой менеджер памяти. просто в том исследовании, что провел Rouse_, на сколько я понял, выявлены ошибки, помимо этой.
← →
Германн © (2015-04-30 00:56) [19]
> Никто не хочет задачку от GunSmoker-а решить? :)
>
> Rouse_ © (29.04.15 21:56)
Комментарий от АА в твоём блоге просто убил.
← →
Дмитрий С © (2015-04-30 03:42) [20]
> Это как так? Что передали на EnumWindows то и получили в
> LPARAM без указателей а как есть.
Разве const не превращает параметр в переданный по ссылке? Тем самым неявно ожидая указатель вместо значения.
← →
brother © (2015-04-30 08:00) [21]ну яб еще
Result := False;
в начале функции поставил, но это так... для явного так сказать
← →
Дмитрий С © (2015-04-30 10:08) [22]
> Rouse_ © (30.04.15 00:04) [17]
{$APPTYPE CONSOLE}
procedure TForm1.Button1Click(Sender: TObject);
function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall;
var
Wnd: HWND;
begin
Wnd := HWND(AParam);
Writeln("C ", Wnd);
if AWnd = Wnd then
Result := True
else
Result := False;
end;
var
Wnd: HWND;
begin
Wnd := Handle;
Writeln("A ", Wnd);
EnumWindows(@EnumWindowsProc, LPARAM(Wnd));
Writeln("B ", Wnd);
end;
Под 32 бита:
A 14681046
C 14681046
B 14681046
Под 64 бита:
A 11668374
C 65535
B 11668374
Под 64 бита без const:
A 19536768
C 65535
B 19536768
Так что явно что-то не так.
Вот асм:
Unit1.pas.31: begin
000000000069BBD0 55 push rbp
000000000069BBD1 4883EC30 sub rsp,$30
000000000069BBD5 488BEC mov rbp,rsp
000000000069BBD8 48894D40 mov [rbp+$40],rcx
000000000069BBDC 48895548 mov [rbp+$48],rdx
000000000069BBE0 4C894550 mov [rbp+$50],r8
Unit1.pas.32: Wnd := HWND(AParam);
000000000069BBE4 488B4550 mov rax,[rbp+$50]
000000000069BBE8 48894520 mov [rbp+$20],rax
Unit1.pas.33: Writeln("C ", Wnd);
000000000069BBEC 488B0DBD6C0400 mov rcx,[rel $00046cbd]
000000000069BBF3 488D154E000000 lea rdx,[rel $0000004e]
000000000069BBFA E8C1F1D6FF call @Write0UString
000000000069BBFF 4889C1 mov rcx,rax
000000000069BC02 488B5520 mov rdx,[rbp+$20]
000000000069BC06 E8355AD7FF call @Write0UInt64
000000000069BC0B 4889C1 mov rcx,rax
000000000069BC0E E81DF3D6FF call @WriteLn
000000000069BC13 E898CFD6FF call @_IOTest
Unit1.pas.34: if AWnd = Wnd then
000000000069BC18 488B4548 mov rax,[rbp+$48]
000000000069BC1C 483B4520 cmp rax,[rbp+$20]
000000000069BC20 7509 jnz EnumWindowsProc + $5B
Unit1.pas.35: Result := True
000000000069BC22 C7452CFFFFFFFF mov [rbp+$2c],$ffffffff
000000000069BC29 EB07 jmp EnumWindowsProc + $62
Unit1.pas.37: Result := False;
000000000069BC2B C7452C00000000 mov [rbp+$2c],$00000000
Unit1.pas.38: end;
000000000069BC32 8B452C mov eax,[rbp+$2c]
000000000069BC35 488D6530 lea rsp,[rbp+$30]
000000000069BC39 5D pop rbp
000000000069BC3A C3 ret
000000000069BC3B 00B0040200FF add [rax-$00fffdfc],dh
000000000069BC41 FFFF db $ff $ff
000000000069BC43 FF02 inc dword ptr [rdx]
000000000069BC45 0000 add [rax],al
000000000069BC47 004300 add [rbx+$00],al
000000000069BC4A 2000 and [rax],al
000000000069BC4C 0000 add [rax],al
000000000069BC4E CC int 3
000000000069BC4F CC int 3
Unit1.pas.42: begin
000000000069BC50 55 push rbp
000000000069BC51 4883EC30 sub rsp,$30
000000000069BC55 488BEC mov rbp,rsp
000000000069BC58 48894D40 mov [rbp+$40],rcx
000000000069BC5C 48895548 mov [rbp+$48],rdx
Unit1.pas.43: Wnd := Handle;
000000000069BC60 488B4D40 mov rcx,[rbp+$40]
000000000069BC64 E82735F2FF call TWinControl.GetHandle
000000000069BC69 48894528 mov [rbp+$28],rax
Unit1.pas.44: Writeln("A ", Wnd);
000000000069BC6D 488B0D3C6C0400 mov rcx,[rel $00046c3c]
000000000069BC74 488D156D000000 lea rdx,[rel $0000006d]
000000000069BC7B E840F1D6FF call @Write0UString
000000000069BC80 4889C1 mov rcx,rax
000000000069BC83 488B5528 mov rdx,[rbp+$28]
000000000069BC87 E8B459D7FF call @Write0UInt64
000000000069BC8C 4889C1 mov rcx,rax
000000000069BC8F E89CF2D6FF call @WriteLn
000000000069BC94 E817CFD6FF call @_IOTest
Unit1.pas.45: EnumWindows(@EnumWindowsProc, LPARAM(Wnd));
000000000069BC99 488D0D30FFFFFF lea rcx,[rel $ffffff30]
000000000069BCA0 488B5528 mov rdx,[rbp+$28]
000000000069BCA4 E84701D8FF call EnumWindows
Unit1.pas.46: Writeln("B ", Wnd);
000000000069BCA9 488B0D006C0400 mov rcx,[rel $00046c00]
000000000069BCB0 488D1545000000 lea rdx,[rel $00000045]
000000000069BCB7 E804F1D6FF call @Write0UString
000000000069BCBC 4889C1 mov rcx,rax
000000000069BCBF 488B5528 mov rdx,[rbp+$28]
000000000069BCC3 E87859D7FF call @Write0UInt64
000000000069BCC8 4889C1 mov rcx,rax
000000000069BCCB E860F2D6FF call @WriteLn
000000000069BCD0 E8DBCED6FF call @_IOTest
Unit1.pas.47: end;
000000000069BCD5 488D6530 lea rsp,[rbp+$30]
000000000069BCD9 5D pop rbp
000000000069BCDA C3 ret
← →
Дмитрий С © (2015-04-30 10:26) [23]Если вынести вложенную функцию - то работает как надо. Да и в документации явно написано:
Nested procedures and functions (routines declared within other routines) cannot be used as procedural values, nor can predefined procedures and functions.
http://docwiki.embarcadero.com/RADStudio/XE8/en/Procedural_Types#Method_Pointers
← →
Rouse_ © (2015-04-30 11:02) [24]
> Дмитрий С © (30.04.15 10:08) [22]
Ага, я тоже этот момент проверил и уже в статейке обновил :)
Вот только причину такого поведения не стал искать :)
← →
Rouse_ © (2015-04-30 11:06) [25]Ещеб понять что это за пресловутое значение в R8 передается, ну да шут с ним, главное ошибка прояснилась :)
← →
Дмитрий С © (2015-04-30 12:28) [26]Кстати я с тобой не согласен на счет того что плохо, что компилятор дает компилировать такое. Я думаю что плохо то, что это работает не так как ожидается.
← →
Rouse_ © (2015-04-30 13:09) [27]Спорный момент.
← →
Юрий Зотов © (2015-04-30 13:40) [28]Я на эту ошибку напоролся лет 15 назад, когда еще не было ни 64 бит, ни описателя const в параметрах. Все оказалось просто: вынес вложенный callback наружу - и заработало.
← →
Rouse_ © (2015-04-30 17:16) [29]ЗЫ: обновил обзорку, раскрыл тему относящуюся к вопросу:
> Дмитрий С © (30.04.15 12:28) [26]
Добавил описание причин такого поведения по второй части.
http://alexander-bagel.blogspot.ru/2015/04/18-gunsmoker.html
Почти статья получилась :)))
← →
Palladin © (2015-04-30 17:28) [30]
> Я на эту ошибку напоролся лет 15 назад,
+1
← →
Palladin © (2015-04-30 17:30) [31]вообще хотелось бы сказать, что вложенная в процедуру процедура является процедурой, вложенная процедура в метод, является методом
← →
Rouse_ © (2015-04-30 21:39) [32]Сашка крут, и специально под меня, после моего анализа выложил третий вариант проблемы :)
http://www.gunsmoker.ru/2015/04/task-18-3.html
Жалко что данная задача легко решилась (небольшая девиация), но, впрочем, вот вам задачка на выходные (кому не лень).
ЗЫ: сразу скажу там не все так просто как кажется, с учетом моего предыдущего анализа кода :)
← →
Юрий Зотов © (2015-04-30 22:15) [33]Даже без анализа - коллбэк должен возвращать BOOL, а не Boolean.
← →
Rouse_ © (2015-04-30 22:28) [34]
> Юрий Зотов © (30.04.15 22:15) [33]
Допустим, но зачем, если учитывать что данные на стеке 4 байтовые (после любого PUSH) да и EAX регистр 32 бита? :)
← →
Rouse_ © (2015-04-30 22:36) [35]Блин - пардоньте, именно этот цимус я тебе и рассказывал.
Юрч не давай пока ответ плз.
← →
Дмитрий С © (2015-05-01 13:55) [36]
> да и EAX регистр 32 бита? :)
Unit1.pas.35: if AWnd <> Wnd then
005B46CC 8B4508 mov eax,[ebp+$08]
005B46CF 3B45F8 cmp eax,[ebp-$08]
005B46D2 7406 jz $005b46da
Unit1.pas.36: Result := True
005B46D4 C645FF01 mov byte ptr [ebp-$01],$01
005B46D8 EB04 jmp $005b46de
Unit1.pas.38: Result := False;
005B46DA C645FF00 mov byte ptr [ebp-$01],$00
Unit1.pas.39: end;
005B46DE 8A45FF mov al,[ebp-$01]
В остальной части EAX будут остатки от хендлов.
← →
Rouse_ © (2015-05-01 14:00) [37]cравнение идет test eax, eax
суть не в этом
← →
Rouse_ © (2015-05-01 14:04) [38]ну либо в 64 битах
xor ebx,ebx
call r15
cmp eax,ebx
jz
← →
Дмитрий С © (2015-05-01 14:06) [39]
> суть не в этом
В этом.
Вот пример наглядно демонстрирующий:
function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): Boolean; stdcall;
var
Wnd: HWND;
begin
Wnd := HWND(AParam);
if AWnd = Wnd then
Result := True
else
Result := False;
end;
procedure TForm1.Button1Click(Sender: TObject);
type
TEnumWindowsProc = function (const AWnd: HWND; const AParam: LPARAM): Bool; stdcall;
var
Proc: TEnumWindowsProc;
begin
Proc := @EnumWindowsProc;
ShowMessage(BoolToStr(Proc(23456789, 98765432), True)); // Показывает True, а должен False
end;
← →
Rouse_ © (2015-05-01 14:09) [40]Показывает False, ты уверен что пример правильный?
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2016.01.03;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.002 c