Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2016.01.03;
Скачать: CL | DM;

Вниз

Никто не хочет задачку от 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, ты уверен что пример правильный?


 
Дмитрий С ©   (2015-05-01 14:11) [41]

32 бита скомпилируй


 
Дмитрий С ©   (2015-05-01 14:12) [42]

И у меня только в Debug проявляется.


 
Rouse_ ©   (2015-05-01 14:13) [43]

А, все - поигрался с настройками среды (отключил оптимизацию) и проявилось.
Ну что - молодец, почти нашел :)


 
Rouse_ ©   (2015-05-01 14:16) [44]

Ан нет - я поторопился. Не воспроизвелось.


 
Дмитрий С ©   (2015-05-01 14:22) [45]

Покажи asm
Debug 32x, только перебилди


 
Rouse_ ©   (2015-05-01 14:33) [46]

Все разобрался, да именно на это ты и вышел, что я Зотычу объяснял в свое время (ошибка на SBB после сравнения из-за неверно выставленного CF), но тут есть еще один цимус :)


 
Rouse_ ©   (2015-05-01 14:46) [47]

ЗЫ, дополню - данная ошибка (именно в твоем, Дим, примере) из-за того что используется CMP а не TEST, который дергает EnumWindows


 
Кто б сомневался ©   (2015-05-06 19:36) [48]

Если честно то это баг, имхо - т. к. неудобно.
Неудобно жеж - придется выносить тип PTempData = ^TTempData;
 TTempData = record из главной функции, в которой EnumWindowsProc была вложенной - переносить их в модуль на самый вверх.  А так все на виду..


 
Кто б сомневался ©   (2015-05-06 19:37) [49]

Баг из за того что работает по разному.


 
Кто б сомневался ©   (2015-05-06 19:43) [50]


>  переносить их в модуль на самый вверх.


Не на самый верх оказывается, а просто над функцией тип дописать, раньше кажись нельзя было в разных частях кода описывать типы.

procedure TClass,DoSmth;
begin
end;

// где то в середине модуля

type
 PTempData = ^TTempData;
 TTempData = record
 end;

// продолжаем
procedure TClass.DoSmthelse;
begin
end;



Страницы: 1 2 вся ветка

Текущий архив: 2016.01.03;
Скачать: CL | DM;

Наверх




Память: 0.61 MB
Время: 0.018 c
2-1403935862
cr@nk
2014-06-28 10:11
2016.01.03
on E: Exception do в DataModule и консольное приложение


6-1279021557
Black123
2010-07-13 15:45
2016.01.03
IdHTTP.Post и глобальные переменные.


15-1430848589
ВладОшин
2015-05-05 20:56
2016.01.03
NCONVERT, PDF -> Jpeg (Error: Don t know how to read..)


15-1429530476
4h Q
2015-04-20 14:47
2016.01.03
Посоветуйте снифер, пожалуйста


15-1431207001
Юрий
2015-05-10 00:30
2016.01.03
С днем рождения ! 10 мая 2015 воскресенье