Конференция "Прочее" » Никто не хочет задачку от GunSmoker-а решить? :)
 
  • Rouse_ © (29.04.15 21:56) [0]
    Сама задача: http://www.gunsmoker.ru/2015/04/task-18.html
    Если чесно я не смог, и сделал обоснование почему не смог:
    http://alexander-bagel.blogspot.ru/2015/04/18-gunsmoker.html
  • Дмитрий С © (29.04.15 22:10) [1]
    Код в задаче и у тебя разный.
  • Kilkennycat © (29.04.15 22:12) [2]
    if AWnd = Wnd then

    после си я такое видеть спокойно не могу...
  • Дмитрий С © (29.04.15 22:21) [3]
    Мне кажется дело вот в чем:
    Передаем мы значение LPARAM(Wnd)
    А ожидаем указатель на значение  const AParam: LPARAM
  • Rouse_ © (29.04.15 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 © (29.04.15 23:00) [5]
    Не совсем понятно, в чем суть задачи.

    Это я прочитал от предыдущего вопроса.

    >> Не обращайте внимание на его бессмысленность, вопрос не в этом, а в корректности кода.

    Но код то вполне рабочий, по крайней мере у меня.
  • Rouse_ © (29.04.15 23:00) [6]

    > Передаем мы значение LPARAM(Wnd)
    > А ожидаем указатель на значение  const AParam: LPARAM

    Это как так? Что передали на EnumWindows то и получили в LPARAM без указателей а как есть.
  • Rouse_ © (29.04.15 23:01) [7]

    > Eraser ©   (29.04.15 23:00) [5]
    > Не совсем понятно, в чем суть задачи.

    В том что в данном коде есть ошибка.
  • Кто б сомневался © (29.04.15 23:21) [8]
    Вариант A с багом, почему Rouse рассказал, даже на него попадал,  

    Поэтому так делаю:


    var
     vData: TDataRec;

     function EnumWindowsProc(aWindow: HWND; aData: LPARAM): Bool; stdcall;
     ..

    EnumWindows(@EnumWindowsProc, LPARAM(@vData));

    Вариант отработан годами.

    в варианте B вроде нет проблем, кроме того что меня const смущают, но разбираться влом :) .
  • Eraser © (29.04.15 23:33) [9]
    да вариант A вообще дырявый, чего только стоит обращение к Caption, а вот со вторым засада )
  • Rouse_ © (29.04.15 23:37) [10]
    Второй меня вообще убил - ну нет там блин ошибки :)))
  • Rouse_ © (29.04.15 23:41) [11]

    > кроме того что меня const смущают, но разбираться влом :
    > ) .

    const перепроверял - асм выхлоп идентичен.
  • Rouse_ © (29.04.15 23:43) [12]
    Да и тем более параметры идут не BYREF, а const - сугубо дельфийский момент работающий  как директива.
  • Eraser © (29.04.15 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;



    аналогично.
  • Кто б сомневался © (29.04.15 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_ © (30.04.15 00:02) [15]

    > Eraser ©   (29.04.15 23:52) [13]
    > В варианте А у меня ошибку гарантированно дает вот такой
    > код

    Так ясен пень, тыж мое обоснование сначала прочти.
    http://alexander-bagel.blogspot.ru/2015/04/18-gunsmoker.html
    Кому ты Caption меняешь, если Self не доступен?
  • Кто б сомневался © (30.04.15 00:03) [16]
    Второму Eraser: в EnumWindowsProc нельзя обращаться к любым переменным, которые находятся вне EnumWindowsProc = AV. Только перекидывать адрес через LPARAM.
  • Rouse_ © (30.04.15 00:04) [17]
    Народ вон уже сделал первое предположение что CONST в 64 битах может повести себя не так как задумано:
    http://www.gunsmoker.ru/2015/04/task-18.html
    Завтра буду проверять.
  • Eraser © (30.04.15 00:08) [18]

    > Кто б сомневался ©   (30.04.15 00:03) [16]

    я это понимаю, там другой менеджер памяти. просто в том исследовании, что провел Rouse_, на сколько я понял, выявлены ошибки, помимо этой.
  • Германн © (30.04.15 00:56) [19]

    > Никто не хочет задачку от GunSmoker-а решить? :)
    >
    > Rouse_ ©   (29.04.15 21:56)  

    Комментарий от АА в твоём блоге просто убил.
  • Дмитрий С © (30.04.15 03:42) [20]

    > Это как так? Что передали на EnumWindows то и получили в
    > LPARAM без указателей а как есть.

    Разве const не превращает параметр в переданный по ссылке? Тем самым неявно ожидая указатель вместо значения.
  • brother © (30.04.15 08:00) [21]
    ну яб еще
    Result := False;
    в начале функции поставил, но это так... для явного так сказать
  • Дмитрий С © (30.04.15 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

  • Дмитрий С © (30.04.15 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_ © (30.04.15 11:02) [24]

    > Дмитрий С ©   (30.04.15 10:08) [22]

    Ага, я тоже этот момент проверил и уже в статейке обновил :)
    Вот только причину такого поведения не стал искать :)
  • Rouse_ © (30.04.15 11:06) [25]
    Ещеб понять что это за пресловутое значение в R8 передается, ну да шут с ним, главное ошибка прояснилась :)
  • Дмитрий С © (30.04.15 12:28) [26]
    Кстати я с тобой не согласен на счет того что плохо, что компилятор дает компилировать такое. Я думаю что плохо то, что это работает не так как ожидается.
  • Rouse_ © (30.04.15 13:09) [27]
    Спорный момент.
  • Юрий Зотов © (30.04.15 13:40) [28]
    Я на эту ошибку напоролся лет 15 назад, когда еще не было ни 64 бит, ни описателя const в параметрах. Все оказалось просто: вынес вложенный  callback наружу - и заработало.
  • Rouse_ © (30.04.15 17:16) [29]
    ЗЫ: обновил обзорку, раскрыл тему относящуюся к вопросу:

    > Дмитрий С ©   (30.04.15 12:28) [26]


    Добавил описание причин такого поведения по второй части.
    http://alexander-bagel.blogspot.ru/2015/04/18-gunsmoker.html

    Почти статья получилась :)))
  • Palladin © (30.04.15 17:28) [30]

    > Я на эту ошибку напоролся лет 15 назад,

    +1
  • Palladin © (30.04.15 17:30) [31]
    вообще хотелось бы сказать, что вложенная в процедуру процедура является процедурой, вложенная процедура в метод, является методом
  • Rouse_ © (30.04.15 21:39) [32]
    Сашка крут, и специально под меня, после моего анализа выложил третий вариант проблемы :)
    http://www.gunsmoker.ru/2015/04/task-18-3.html
    Жалко что данная задача легко решилась (небольшая девиация), но, впрочем, вот вам задачка на выходные (кому не лень).
    ЗЫ: сразу скажу там не все так просто как кажется, с учетом моего предыдущего анализа кода :)
  • Юрий Зотов © (30.04.15 22:15) [33]
    Даже без анализа - коллбэк должен возвращать BOOL, а не Boolean.
  • Rouse_ © (30.04.15 22:28) [34]

    > Юрий Зотов ©   (30.04.15 22:15) [33]

    Допустим, но зачем, если учитывать что данные на стеке 4 байтовые (после любого PUSH) да и EAX регистр 32 бита? :)
  • Rouse_ © (30.04.15 22:36) [35]
    Блин - пардоньте, именно этот цимус я тебе и рассказывал.
    Юрч не давай пока ответ плз.
  • Дмитрий С © (01.05.15 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_ © (01.05.15 14:00) [37]
    cравнение идет test eax, eax
    суть не в этом
  • Rouse_ © (01.05.15 14:04) [38]
    ну либо в 64 битах
    xor ebx,ebx
    call r15
    cmp eax,ebx
    jz

  • Дмитрий С © (01.05.15 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_ © (01.05.15 14:09) [40]
    Показывает False, ты уверен что пример правильный?
  • Дмитрий С © (01.05.15 14:11) [41]
    32 бита скомпилируй
  • Дмитрий С © (01.05.15 14:12) [42]
    И у меня только в Debug проявляется.
  • Rouse_ © (01.05.15 14:13) [43]
    А, все - поигрался с настройками среды (отключил оптимизацию) и проявилось.
    Ну что - молодец, почти нашел :)
  • Rouse_ © (01.05.15 14:16) [44]
    Ан нет - я поторопился. Не воспроизвелось.
  • Дмитрий С © (01.05.15 14:22) [45]
    Покажи asm
    Debug 32x, только перебилди
  • Rouse_ © (01.05.15 14:33) [46]
    Все разобрался, да именно на это ты и вышел, что я Зотычу объяснял в свое время (ошибка на SBB после сравнения из-за неверно выставленного CF), но тут есть еще один цимус :)
  • Rouse_ © (01.05.15 14:46) [47]
    ЗЫ, дополню - данная ошибка (именно в твоем, Дим, примере) из-за того что используется CMP а не TEST, который дергает EnumWindows
  • Кто б сомневался © (06.05.15 19:36) [48]
    Если честно то это баг, имхо - т. к. неудобно.
    Неудобно жеж - придется выносить тип PTempData = ^TTempData;
     TTempData = record из главной функции, в которой EnumWindowsProc была вложенной - переносить их в модуль на самый вверх.  А так все на виду..
  • Кто б сомневался © (06.05.15 19:37) [49]
    Баг из за того что работает по разному.
  • Кто б сомневался © (06.05.15 19:43) [50]

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


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

    procedure TClass,DoSmth;
    begin
    end;

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

    type
     PTempData = ^TTempData;
     TTempData = record
     end;

    // продолжаем
    procedure TClass.DoSmthelse;
    begin
    end;
 
Конференция "Прочее" » Никто не хочет задачку от GunSmoker-а решить? :)
Есть новые Нет новых   [134434   +28][b:0][p:0.005]