-
-
Код в задаче и у тебя разный.
-
if AWnd = Wnd then после си я такое видеть спокойно не могу...
-
Мне кажется дело вот в чем: Передаем мы значение LPARAM(Wnd) А ожидаем указатель на значение const AParam: LPARAM
-
-
Не совсем понятно, в чем суть задачи.
Это я прочитал от предыдущего вопроса.
>> Не обращайте внимание на его бессмысленность, вопрос не в этом, а в корректности кода.
Но код то вполне рабочий, по крайней мере у меня.
-
> Передаем мы значение LPARAM(Wnd) > А ожидаем указатель на значение const AParam: LPARAM
Это как так? Что передали на EnumWindows то и получили в LPARAM без указателей а как есть.
-
> Eraser © (29.04.15 23:00) [5] > Не совсем понятно, в чем суть задачи.
В том что в данном коде есть ошибка.
-
Вариант A с багом, почему Rouse рассказал, даже на него попадал,
Поэтому так делаю:
var vData: TDataRec;
function EnumWindowsProc(aWindow: HWND; aData: LPARAM): Bool; stdcall; ..
EnumWindows(@EnumWindowsProc, LPARAM(@vData));
Вариант отработан годами.
в варианте B вроде нет проблем, кроме того что меня const смущают, но разбираться влом :) .
-
да вариант A вообще дырявый, чего только стоит обращение к Caption, а вот со вторым засада )
-
Второй меня вообще убил - ну нет там блин ошибки :)))
-
> кроме того что меня const смущают, но разбираться влом : > ) .
const перепроверял - асм выхлоп идентичен.
-
Да и тем более параметры идут не BYREF, а const - сугубо дельфийский момент работающий как директива.
-
В варианте А у меня ошибку гарантированно дает вот такой код (причем 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
vData: Integer;
function EnumWindowsProc(const AWnd: HWND; const AParam: LPARAM): BOOL; stdcall;
begin
Caption := 'OK';
Result := True;
end;
begin
EnumWindows(@EnumWindowsProc, LPARAM(@vData));
end; аналогично.
-
> 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';
Вас там двое чтоле?
-
-
Второму Eraser: в EnumWindowsProc нельзя обращаться к любым переменным, которые находятся вне EnumWindowsProc = AV. Только перекидывать адрес через LPARAM.
-
-
> Кто б сомневался © (30.04.15 00:03) [16]
я это понимаю, там другой менеджер памяти. просто в том исследовании, что провел Rouse_, на сколько я понял, выявлены ошибки, помимо этой.
-
> Никто не хочет задачку от GunSmoker-а решить? :) > > Rouse_ © (29.04.15 21:56)
Комментарий от АА в твоём блоге просто убил.
-
> Это как так? Что передали на EnumWindows то и получили в > LPARAM без указателей а как есть.
Разве const не превращает параметр в переданный по ссылке? Тем самым неявно ожидая указатель вместо значения.
-
ну яб еще Result := False; в начале функции поставил, но это так... для явного так сказать
-
> 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
-
-
> Дмитрий С © (30.04.15 10:08) [22]
Ага, я тоже этот момент проверил и уже в статейке обновил :) Вот только причину такого поведения не стал искать :)
-
Ещеб понять что это за пресловутое значение в R8 передается, ну да шут с ним, главное ошибка прояснилась :)
-
Кстати я с тобой не согласен на счет того что плохо, что компилятор дает компилировать такое. Я думаю что плохо то, что это работает не так как ожидается.
-
Спорный момент.
-
Я на эту ошибку напоролся лет 15 назад, когда еще не было ни 64 бит, ни описателя const в параметрах. Все оказалось просто: вынес вложенный callback наружу - и заработало.
-
-
> Я на эту ошибку напоролся лет 15 назад,
+1
-
вообще хотелось бы сказать, что вложенная в процедуру процедура является процедурой, вложенная процедура в метод, является методом
-
Сашка крут, и специально под меня, после моего анализа выложил третий вариант проблемы :) http://www.gunsmoker.ru/2015/04/task-18-3.htmlЖалко что данная задача легко решилась (небольшая девиация), но, впрочем, вот вам задачка на выходные (кому не лень). ЗЫ: сразу скажу там не все так просто как кажется, с учетом моего предыдущего анализа кода :)
-
Даже без анализа - коллбэк должен возвращать BOOL, а не Boolean.
-
> Юрий Зотов © (30.04.15 22:15) [33]
Допустим, но зачем, если учитывать что данные на стеке 4 байтовые (после любого PUSH) да и EAX регистр 32 бита? :)
-
Блин - пардоньте, именно этот цимус я тебе и рассказывал. Юрч не давай пока ответ плз.
-
> да и 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 будут остатки от хендлов.
-
cравнение идет test eax, eax суть не в этом
-
ну либо в 64 битах xor ebx,ebx
call r15
cmp eax,ebx
jz
-
> суть не в этом
В этом. Вот пример наглядно демонстрирующий:
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;
-
Показывает False, ты уверен что пример правильный?
-
32 бита скомпилируй
-
И у меня только в Debug проявляется.
-
А, все - поигрался с настройками среды (отключил оптимизацию) и проявилось. Ну что - молодец, почти нашел :)
-
Ан нет - я поторопился. Не воспроизвелось.
-
Покажи asm Debug 32x, только перебилди
-
Все разобрался, да именно на это ты и вышел, что я Зотычу объяснял в свое время (ошибка на SBB после сравнения из-за неверно выставленного CF), но тут есть еще один цимус :)
-
ЗЫ, дополню - данная ошибка (именно в твоем, Дим, примере) из-за того что используется CMP а не TEST, который дергает EnumWindows
-
Если честно то это баг, имхо - т. к. неудобно. Неудобно жеж - придется выносить тип PTempData = ^TTempData; TTempData = record из главной функции, в которой EnumWindowsProc была вложенной - переносить их в модуль на самый вверх. А так все на виду..
-
Баг из за того что работает по разному.
-
> переносить их в модуль на самый вверх.
Не на самый верх оказывается, а просто над функцией тип дописать, раньше кажись нельзя было в разных частях кода описывать типы.
procedure TClass,DoSmth; begin end;
// где то в середине модуля
type PTempData = ^TTempData; TTempData = record end;
// продолжаем procedure TClass.DoSmthelse; begin end;
|