Конференция "KOL" » KOL 3.23 [Delphi, Windows]
 
  • Vladimir Kladov © (21.02.15 10:24) [0]
    [-] Исправления в KOL: WStrRScan - код скопирован из StrRScan. Исходная версия WStrRScan работала некорректно в случае отсутствия искомого образца.
    [-] Исправления в обработчике WM_NCDESTROY для корректного уничтожения меню (не мог быть разрушен после разрушения окна-владельца).
    [*] Улучшена функция ClipboardHasText - удален ненужный код.
    [+] Метод TBitmap.CopyToClipboard переименован в CopyToClipboardAsDIB, добавлена другая версия CopyToClipboard, использующая формат CF_BITMAP (существенно более короткий код).

  • QAZ (21.02.15 14:00) [1]

    > для корректного уничтожения меню

    и какие такие дефины в проекте должны стоять, чтоб до этого исправления дошёл код вообще????

    при закрытии в тестовом приложении как были утечки меню из под дельфи, так и остались, а в крупном проекте еще и ошибки памяти вылезли, попытка модификации после освобождения
  • QAZ (21.02.15 14:05) [2]
    какая связь между этими адресами?
    http://sourceforge.net/projects/kolmck/
    http://sourceforge.net/projects/keyobjectslibrary/
  • Vladimir Kladov © (21.02.15 19:29) [3]

    > чтоб до этого исправления дошё

    Да, я забыл про kol_asm.inc. Перевыложил, заодно и в kol.pas пару исправлений внес. В частности, добавил, что по заклинанию LET_MENU_LEAK все будет как раньше. Еще раз проверил в MemProof 0.9.4.8 и с FastMM3. Все чисто.


    > какая связь между этими адресами?http://sourceforge.net/projects/kolmck/http:
    > //sourceforge.net/projects/keyobjectslibrary/

    Один из них не мой.
  • QAZ (21.02.15 19:59) [4]

    > Один из них не мой.

    не ну я так-то догадался, просто они тож чето там улучшают
    вы типа не скооперированы вообще?
  • QAZ (21.02.15 20:08) [5]

    > Да, я забыл про kol_asm.inc. Перевыложил, заодно и в kol.
    > pas пару исправлений внес. В частности, добавил, что по
    > заклинанию LET_MENU_LEAK все будет как раньше. Еще раз проверил
    > в MemProof 0.9.4.8 и с FastMM3. Все чисто.

    не, не работает
    вот проверь тут полный комплект https://yadi.sk/d/1JxuHV9kedCXf запускай из под среды
  • QAZ (21.02.15 20:22) [6]
    если это - это, то это копец, такая куча дефинов что до Final вообще недоходит

       WM_NCDESTROY:
                          {$IFnDEF SMALLER_CODE}
                          if  fHandle = Msg.hwnd then
                          {$ENDIF}
                          begin
                              {$IFNDEF LET_MENU_LEAK}
                              if  IsForm then
                              begin
                                  {$IFNDEF SMALLER_CODE}
                                  Hide;  // VK: to destroy form visually faster, 18.02.2015
                                  {$ENDIF}
                                  {$IFNDEF SMALLEST_CODE}
                                  Final; // VK: to provide correct menu destroying, 18.02.2015
                                  {$ENDIF}
                              end;
                              {$ENDIF}
                              {$IFnDEF SMALLER_CODE}
                                  {$IFDEF USE_PROP}
                                  RemoveProp( fHandle, ID_SELF ); //********* Added By M.Gerasimov
                                  {$ELSE}
                                  SetWindowLong( fHandle, GWL_USERDATA, 0 ); // VK + Alexey Kirov, 23.02.2012
                                  {$ENDIF}
                              {$ENDIF} //-------------------------------------------
                              Default;
                              Exit;
                          end;


    с PAS_VERSION вообще ниодна строчка в function TControl.WndProc( var Msg: TMsg ): Integer; неактивна в KOL.Pas
  • Vladimir Kladov © (22.02.15 10:52) [7]
    Вообще-то, все доходит. Это у Вас что-то неправильно. Например, не та версия исходников компилируется.

    Мои исправления вообще не касались утечек памяти. FastMM3 их не показывал. Я решал проблему утечки ресурса меню. Пытался решить. Сейчас выкладываю новое исправление. На этот раз удалось лучше. И заодно проблемы с FastMM4 устраняются. Но исправление слишком радикальное, меняется порядок уничтожения окон. Может вылезти что угодно. Поэтому все можно будет вернуть по заклинанию LET_MENU_LEAK.

    Уже выложил.
  • QAZ (22.02.15 11:18) [8]
    ну во первых в комплекте отсутствует koladd.pas хотя требуется для установки
  • QAZ (22.02.15 11:30) [9]
    во вторых чую придется снимать кино....
  • QAZ (22.02.15 12:40) [10]
    в третьих вот видео (15Мб) https://yadi.sk/d/NLj7kB7NeppV9
    а вот фастмм из видео https://yadi.sk/d/zqkEhLZbeppNk
    условия съемки - чистая ХРшка + нулевая 5ка
    что я там делаю не так?
  • Vladimir Kladov © (22.02.15 13:12) [11]
    Сразу: FastMM я скачал сам, версия 4.991, ваша 4.97. Вряд ли много отличий, но лучше, если Вы обновитесь. Дальше: я использовал Delphi7 под XP SP3 (виртуалка) со всеми обновлениями. delphi5 я давно не использую, но даже если с ней работать, для нее есть обновления. Слово нулевая нехорошо звучит.

    Далее, для проверки с FastMM он должен быть первым в проекте. Рекомендую проверять это перед каждым билдом. MCK любит ссылку на KOL ставить на первое место.

    Кроме того, для лучшей диагностики надо править опции проекта, убирать оптимизацию, добавлять в линкере символы TD32, тогда диагностика показывает красивше. Если до нее доходит дело, конечно.
  • QAZ (22.02.15 14:03) [12]

    > нулевая нехорошо звучит

    это звучит как "с обновой, без экспертов, без компонентов, с дефолтными настройками"
    XP SP3 (виртуалка) со всеми обновлениями  - тоже самое
    рабочий Delphi7 + полуживая Win7x64 - тот же результат
    кудаб не писал FastMM, даже в сам кол.пас - никакой разницы
    хоть с какими настройками отладки
    версию FastMM попробую канешн обновить, но веть логично, что если  например в 2.79 такого не происходит, то проблема не в FastMM?
  • Vladimir Kladov © (22.02.15 14:25) [13]
    Да, не в нем. Потому что я уже попробовал и с вашей версией FastMM, и с Delphi5 уже (и даже без обновлений). И у меня все чисто. Еще подумал, может, FastMM молча падает. Нет, останавливается на строке кода FinalizeMemoryManager, по F8, выполняет и хочет работать дальше. Ни сообщений, ни логов. Добавляю опцию LET_MENU_LEAK, сообщения про утечки есть.

    Проверьте, что с сайта KOL скачалась именно версия 3.23 (в начале kol.pas  VERSION 3.23+). MCK я не менял с июня.

    Если не компилятор (версия Delphi), остается только железо и ОС, а это очень странно.
  • QAZ (22.02.15 14:31) [14]
    вобщем с "новым" фастмм и всеми дебугами без оптимизаций
    без LET_MENU_LEAK без среде в винде также ошибка
    с LET_MENU_LEAK в винде без ошибки, а в среде вот такой вот файл с номерами строк, все по ГОСТу
    https://yadi.sk/i/znRAQNpxepuP4
  • Vladimir Kladov © (22.02.15 17:42) [15]
    Обновил только что, 3.23++. Удалось получить сообщения под win7. Не знаю, виртуалка виновата, или еще что, но под XP оно как-то не детектило.
  • QAZ (22.02.15 17:52) [16]
    если DEP включен для всех прог и делфи с проектным файлом не внесено в исключения, тогда может проглатывать
  • QAZ (22.02.15 19:22) [17]
    так так так...
    с меню вроде норм стало, по крайней мере, тестовый примитив и прога средней сложности молчит
    однако в навороченной есть косяк. но уже не с меню, а похоже на Tlist, тоже из под делфи
  • QAZ (22.02.15 19:42) [18]
    чет не пойму толи он врет с номерами строк толи с названием функций, причем через раз
    глянь лог может поймешь https://yadi.sk/i/0Qq_PaHaeqA7T
  • QAZ (22.02.15 20:11) [19]
    о еще косяк в другой поделке
    если я впихиваю формы-фрэймы в таб контрол вот так (может это через Ж..)

    NewForm2(Form2,TabControl1.Pages[2]);
    NewForm3(Form3,TabControl1.Pages[1]);

    то из под делфи опятьже утечка по этим 2м вкладкам или фрэмам, когда табконтроле были панели такого не было
    https://yadi.sk/i/2iRkCf-NeqC5P
    с какой версии эти глюки не скажу, ибо они прятались среди громадья глюков меню
  • Vladimir Kladov © (22.02.15 20:12) [20]
    Вот здесь полезная информация:
    Текущий дамп памяти из 256 байт начиная с адреса 7EF43120:



    Запускаем программу (F8), в Watches добавляем PDWORD($7EF43120), ставим "Break when changed", и каждый раз, когда первые 4 байта меняются, будет останов. Тут можно посмотреть, кто выделил.

    Вообще похоже на то, что было добавление в TList, сам TList никто не освободил.
  • Vladimir Kladov © (22.02.15 20:18) [21]
    Фреймы даже не буду сейчас смотреть, уже просто не помню, что там и как.

    Я вообще не вижу проблемы с утечками памяти. Если не мегабайтами течет. В современных приложениях вообще всё течет. Вин-8 - это просто одна сплошная протечка. Проги на шарпах со сборщиками мусора - там вообще не поймешь, то ли они текут беспрерывно, то ли это стратегия такая - мусор собирать раз в сутки.

    Вот утечки ресурсов - это серьезно. Можно винду завалить, даже и 7-ку. 8-ку не пробовал (мало я с ней работал), но почему-то есть подозрение, что там ничего не изменилось.
  • QAZ (22.02.15 20:26) [22]

    > Проги на шарпах

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

    для меня утечка это как минимум сигнал что что то не так, а если что то не так, то в итоге накопится куча неразгребешь
    вот с меню разобрались, сразу стали видны "скрытые" им другие проблемы

    про фреймы хотяб скажи правильно ли им так назначать "родителя" и как их освобождать, просто фри или еще чего надо?
  • QAZ (22.02.15 20:42) [23]

    > [+] Метод TBitmap.CopyToClipboard переименован в CopyToClipboardAsDIB,
    >  добавлена другая версия CopyToClipboard, использующая формат
    > CF_BITMAP (существенно более короткий код).

    и пока я шарю в клипбордах :)
    CopyToClipboardAsDIB - вообще нафиг не нужна
    CF_DIB, CF_DIBV5 и CF_BITMAP взаимно конвертируются самой виндой при запросе конкретного варианта, а в 8ке вся эта метрошная лабуда вообще только CF_BITMAP должна посылать в буфер
  • Vladimir Kladov © (22.02.15 21:17) [24]

    > правильно ли им так назначать "родителя" и как их освобождать

    Я сейчас точно уже не скажу как. В свете сегодняшних рытьёв наверное правильно сказать MyFrame.Form.Close; И да, я знаю, что это не форма, а, в общем-то, панель. Просто отправляется WM_CLOSE, дальше все по свистку от винды.


    > CopyToClipboardAsDIB - вообще нафиг не нужна

    Пусть останется. Я работал с битмапами, которые бывают только в DIB'е, потому что handle винде выделить не получается, слишком большой. И для совместимости.
  • Thaddy © (23.02.15 17:34) [25]
    I've merged 3.23++ into 64 bit unofficial. Plz test.
    Link is:
    http://thaddy.org/kol323-x64-unofficial.7z
  • Thaddy © (23.02.15 17:47) [26]
    This also contains function format for Freepascal and updated koldef.inc for Freepascal 3.0.1/3.1.1
  • Vladimir Kladov © (24.02.15 11:09) [27]

    > merged 3.23++

    too fast. An error in asm version of run. it should be:

    procedure Run( var AppletCtl: PControl );
    asm
    //----- if  AppletCtl = nil then Exit;
           TEST      EAX, EAX
           JZ        @@exit
           PUSH      EBX
           XCHG      EBX, EAX

    //----- AppletRunning := TRUE;
           INC       [AppletRunning]

    //----- Applet := AppletCtl;
           MOV       EAX, [EBX]
           MOV       [Applet], EAX

    //----- AppletCtl.CreateWindow;
           CALL      CallTControlCreateWindow

    //----- WHILE NOT AppletTerminated DO
    @@loop: CMP       [AppletTerminated], 0
           JNZ       @@end_loop

    //----- WaitMessage;
           CALL      WaitMessage

    //----- AppletCtl.ProcessMessages;
           MOV       EAX, [EBX]
           CALL      TControl.ProcessMessages

           {$IFDEF   USE_OnIdle}
    //----- ProcessIdle(AppletCtl);
           MOV       EAX, [EBX]
           CALL      [ProcessIdle]
           {$ENDIF}

           JMP       @@loop
    @@end_loop:

           {$IFDEF LET_MENU_LEAK}
           MOV       ECX, [EBX]
           XCHG      EAX, EBX
           POP       EBX
           JECXZ     @@exit
           {$ELSE}
           POP       EBX
           LEA       EAX, [Applet]
           CMP       [EAX], 0
           JZ        @@exit
           {$ENDIF}
           CALL      TerminateExecution
    @@exit:
    end;

  • Vladimir Kladov © (24.02.15 11:09) [27]

    > merged 3.23++

    too fast. An error in asm version of run. it should be:

    procedure Run( var AppletCtl: PControl );
    asm
    //----- if  AppletCtl = nil then Exit;
           TEST      EAX, EAX
           JZ        @@exit
           PUSH      EBX
           XCHG      EBX, EAX

    //----- AppletRunning := TRUE;
           INC       [AppletRunning]

    //----- Applet := AppletCtl;
           MOV       EAX, [EBX]
           MOV       [Applet], EAX

    //----- AppletCtl.CreateWindow;
           CALL      CallTControlCreateWindow

    //----- WHILE NOT AppletTerminated DO
    @@loop: CMP       [AppletTerminated], 0
           JNZ       @@end_loop

    //----- WaitMessage;
           CALL      WaitMessage

    //----- AppletCtl.ProcessMessages;
           MOV       EAX, [EBX]
           CALL      TControl.ProcessMessages

           {$IFDEF   USE_OnIdle}
    //----- ProcessIdle(AppletCtl);
           MOV       EAX, [EBX]
           CALL      [ProcessIdle]
           {$ENDIF}

           JMP       @@loop
    @@end_loop:

           {$IFDEF LET_MENU_LEAK}
           MOV       ECX, [EBX]
           XCHG      EAX, EBX
           POP       EBX
           JECXZ     @@exit
           {$ELSE}
           POP       EBX
           LEA       EAX, [Applet]
           CMP       [EAX], 0
           JZ        @@exit
           {$ENDIF}
           CALL      TerminateExecution
    @@exit:
    end;

  • QAZ (24.02.15 11:20) [28]

    >  Но исправление слишком радикальное, меняется порядок уничтожения
    > окон. Может вылезти что угодно. Поэтому все можно будет
    > вернуть по заклинанию LET_MENU_LEAK.

    в общем печаль-тоска подобралась незаметно, есть новый виновник утечек и вылетов ---- KOLApplet
    обнаружил при попытке разборок с фреймами, мысль была что может без него им плохо живется, ну типа по аналогии с несколькими формами
    ток положил на форму и хобана + еще 8 утечек

    потом
    1)беру болванку эксперимента с меню, что выкладывал здесь, для приличия добавил 2ю форму, без апплета, запустил\закрыл - чисто
    2) кладу аплет, запустил\закрыл - стоп в CPU-окне отладчика на user32.DestroyWindow
    3) думаю, предупреждал же...
    4) ставлю дефин LET_MENU_LEAK, удалил меню, для чистоты эксперимента, запустил\закрыл - 9 утечек, включая те самые Тлисты....
    5) убираю аплетт, , запустил\закрыл - портянка на весь экран ошибка памяти
    6) убираю дефин LET_MENU_LEAK, запустил\закрыл - чисто

    кино ннада?
  • QAZ (24.02.15 11:20) [28]

    >  Но исправление слишком радикальное, меняется порядок уничтожения
    > окон. Может вылезти что угодно. Поэтому все можно будет
    > вернуть по заклинанию LET_MENU_LEAK.

    в общем печаль-тоска подобралась незаметно, есть новый виновник утечек и вылетов ---- KOLApplet
    обнаружил при попытке разборок с фреймами, мысль была что может без него им плохо живется, ну типа по аналогии с несколькими формами
    ток положил на форму и хобана + еще 8 утечек

    потом
    1)беру болванку эксперимента с меню, что выкладывал здесь, для приличия добавил 2ю форму, без апплета, запустил\закрыл - чисто
    2) кладу аплет, запустил\закрыл - стоп в CPU-окне отладчика на user32.DestroyWindow
    3) думаю, предупреждал же...
    4) ставлю дефин LET_MENU_LEAK, удалил меню, для чистоты эксперимента, запустил\закрыл - 9 утечек, включая те самые Тлисты....
    5) убираю аплетт, , запустил\закрыл - портянка на весь экран ошибка памяти
    6) убираю дефин LET_MENU_LEAK, запустил\закрыл - чисто

    кино ннада?
  • QAZ (24.02.15 11:26) [29]

    > беру болванку эксперимента с меню

    с дефином PAS_VERSION, чудеса не менее интересные, включая "рунтаймеррор"
  • QAZ (24.02.15 11:26) [29]

    > беру болванку эксперимента с меню

    с дефином PAS_VERSION, чудеса не менее интересные, включая "рунтаймеррор"
  • Thaddy © (24.02.15 12:31) [30]
    Package is now updated as per Vladimir's change. (kol_asm.inc)
  • Thaddy © (24.02.15 12:31) [30]
    Package is now updated as per Vladimir's change. (kol_asm.inc)
  • Vladimir Kladov © (24.02.15 13:08) [31]
    Вот где ошибка:

    procedure TerminateExecution( var AppletCtl: PControl );
    var App: PControl;
       Appalreadyterminated: Boolean;
    begin
     Appalreadyterminated := AppletTerminated;
     AppletTerminated := TRUE;
     AppletRunning := FALSE;
     App := Applet;
     Applet := nil;
     if (App <> nil) {and (App.RefCount >= 0)} then
     begin
       {$IFDEF LET_MENU_LEAK} //was IFNDEF !!!
       App.RefInc;
       {$ENDIF}
       if not Appalreadyterminated then
       begin
         App.ProcessMessages;
         App.Perform( WM_CLOSE, 0, 0 );
       end;
       AppletCtl := nil;
       {$IFNDEF LET_MENU_LEAK}            //   версия KOL 3.23+:
               DestroyWindow(App.Handle); //** В этом варианте вызывается не деструктор
       {$ELSE}                            //   объекта, а функция закрытия окна. Вызов
               App.Free;
               App.RefDec;                //   деструктора выполнится в обработчике
       {$ENDIF}                           //   события WM_DESTROY. В результате, сначала
     end;                                 //   успешно разрушится меню формы. 22.02.2015
    end;


    и вот тут, соответственно (kol_asm.inc, + перенос кода за скобки ifdef'а, так что лучше всю процедуру заменить):
    procedure TerminateExecution( var AppletCtl: PControl );
    asm
             PUSH EBX
             PUSH ESI
             MOV  BX, $0100
             XCHG BX, word ptr [AppletRunning]
             XOR  ECX, ECX
             XCHG ECX, [Applet]
             JECXZ @@exit

             PUSH EAX

             {$IFDEF LET_MENU_LEAK} // Was IFNDEF !!!
             XCHG EAX, ECX
             MOV  ESI, EAX
             CALL TObj.RefInc
             {$ENDIF}

             TEST BH, BH
             JNZ  @@closed

             MOV  EAX, ESI
             CALL TControl.ProcessMessages
             PUSH 0
             PUSH 0
             PUSH WM_CLOSE
             PUSH ESI
             CALL TControl.Perform
    @@closed:
             POP  EAX
             XOR  ECX, ECX
             MOV  dword ptr [EAX], ECX
             {$IFDEF LET_MENU_LEAK}
                  MOV  EAX, ESI
                  CALL TObj.RefDec
                  XCHG EAX, ESI
                  CALL TObj.RefDec
             {$ELSE}
                  PUSH [ESI].TControl.FHandle
                  CALL Windows.DestroyWindow
             {$ENDIF}
    @@exit:
             POP  ESI
             POP  EBX
    end;

  • Vladimir Kladov © (24.02.15 13:08) [31]
    Вот где ошибка:

    procedure TerminateExecution( var AppletCtl: PControl );
    var App: PControl;
       Appalreadyterminated: Boolean;
    begin
     Appalreadyterminated := AppletTerminated;
     AppletTerminated := TRUE;
     AppletRunning := FALSE;
     App := Applet;
     Applet := nil;
     if (App <> nil) {and (App.RefCount >= 0)} then
     begin
       {$IFDEF LET_MENU_LEAK} //was IFNDEF !!!
       App.RefInc;
       {$ENDIF}
       if not Appalreadyterminated then
       begin
         App.ProcessMessages;
         App.Perform( WM_CLOSE, 0, 0 );
       end;
       AppletCtl := nil;
       {$IFNDEF LET_MENU_LEAK}            //   версия KOL 3.23+:
               DestroyWindow(App.Handle); //** В этом варианте вызывается не деструктор
       {$ELSE}                            //   объекта, а функция закрытия окна. Вызов
               App.Free;
               App.RefDec;                //   деструктора выполнится в обработчике
       {$ENDIF}                           //   события WM_DESTROY. В результате, сначала
     end;                                 //   успешно разрушится меню формы. 22.02.2015
    end;


    и вот тут, соответственно (kol_asm.inc, + перенос кода за скобки ifdef'а, так что лучше всю процедуру заменить):
    procedure TerminateExecution( var AppletCtl: PControl );
    asm
             PUSH EBX
             PUSH ESI
             MOV  BX, $0100
             XCHG BX, word ptr [AppletRunning]
             XOR  ECX, ECX
             XCHG ECX, [Applet]
             JECXZ @@exit

             PUSH EAX

             {$IFDEF LET_MENU_LEAK} // Was IFNDEF !!!
             XCHG EAX, ECX
             MOV  ESI, EAX
             CALL TObj.RefInc
             {$ENDIF}

             TEST BH, BH
             JNZ  @@closed

             MOV  EAX, ESI
             CALL TControl.ProcessMessages
             PUSH 0
             PUSH 0
             PUSH WM_CLOSE
             PUSH ESI
             CALL TControl.Perform
    @@closed:
             POP  EAX
             XOR  ECX, ECX
             MOV  dword ptr [EAX], ECX
             {$IFDEF LET_MENU_LEAK}
                  MOV  EAX, ESI
                  CALL TObj.RefDec
                  XCHG EAX, ESI
                  CALL TObj.RefDec
             {$ELSE}
                  PUSH [ESI].TControl.FHandle
                  CALL Windows.DestroyWindow
             {$ENDIF}
    @@exit:
             POP  ESI
             POP  EBX
    end;

  • Vladimir Kladov © (24.02.15 13:10) [32]

    > Package is now updated as per Vladimir's change. (kol_asm.
    > inc)

    Thaddy, you are still too fast! :)
  • Vladimir Kladov © (24.02.15 13:10) [32]

    > Package is now updated as per Vladimir's change. (kol_asm.
    > inc)

    Thaddy, you are still too fast! :)
  • QAZ (24.02.15 15:41) [33]

    > Vladimir Kladov ©   (24.02.15 13:08) [31]

    да-да по крайней мере паскальный вариант, самый большой проект, где был Tlist в логе - это и было изза апплета, сейчас все чисто

    остался только косяк с фреймами (или табами) в другом

    > Запускаем программу (F8), в Watches добавляем PDWORD($7EF43120),
    >  ставим "Break when changed", и каждый раз, когда первые
    > 4 байта меняются, будет останов. Тут можно посмотреть, кто
    > выделил.

    чет в 7ке нет такого "Break when changed" и пролетает мимо ненаходит
  • QAZ (24.02.15 15:41) [33]

    > Vladimir Kladov ©   (24.02.15 13:08) [31]

    да-да по крайней мере паскальный вариант, самый большой проект, где был Tlist в логе - это и было изза апплета, сейчас все чисто

    остался только косяк с фреймами (или табами) в другом

    > Запускаем программу (F8), в Watches добавляем PDWORD($7EF43120),
    >  ставим "Break when changed", и каждый раз, когда первые
    > 4 байта меняются, будет останов. Тут можно посмотреть, кто
    > выделил.

    чет в 7ке нет такого "Break when changed" и пролетает мимо ненаходит
  • Vladimir Kladov © (24.02.15 15:59) [34]
    PDWORD(адрес)^ - разыменовать надо.
  • Vladimir Kladov © (24.02.15 15:59) [34]
    PDWORD(адрес)^ - разыменовать надо.
  • Vladimir Kladov © (24.02.15 16:07) [35]
    Обновил KOL.zip на kolmck.net.
  • Vladimir Kladov © (24.02.15 16:07) [35]
    Обновил KOL.zip на kolmck.net.
  • QAZ (24.02.15 20:40) [36]
    табконтрол вроде не причём, на панелях также
    фастмм указывает на создание фрейма в файлах типа Unit2_1.inc
    procedure NewForm2( var Result: PForm2; AParent: PControl );
    begin

     {$IFDEF KOLCLASSES}
     Result := PForm2.Create;
     {$ELSE OBJECTS}
     New( Result, Create );<<<<<<<<<<<<<<<<<<<<<<<<<<
     {$ENDIF KOL CLASSES/OBJECTS}
     Result.Form := NewPanel( AParent, esNone ).MarkPanelAsForm;
     Result.Form.DF.FormAddress := @ Result.Form;
     Result.Form.DF.FormObj := Result;
       Result.Form.SetClientSize( 468, 278 );
       Result.EditBox1 := NewEditBox( Result.Form, [  ] ).SetPosition( 168, 104 );
       Result.EditBox1.Text := 'EditBox1';
       Result.EditBox1.Color := TColor(clWindow);
       Result.Form.CreateWindow;

    end;

    показано <<<<<<<<<<<<<
    хоть free, хоть close - одинаково
  • QAZ (24.02.15 20:40) [36]
    табконтрол вроде не причём, на панелях также
    фастмм указывает на создание фрейма в файлах типа Unit2_1.inc
    procedure NewForm2( var Result: PForm2; AParent: PControl );
    begin

     {$IFDEF KOLCLASSES}
     Result := PForm2.Create;
     {$ELSE OBJECTS}
     New( Result, Create );<<<<<<<<<<<<<<<<<<<<<<<<<<
     {$ENDIF KOL CLASSES/OBJECTS}
     Result.Form := NewPanel( AParent, esNone ).MarkPanelAsForm;
     Result.Form.DF.FormAddress := @ Result.Form;
     Result.Form.DF.FormObj := Result;
       Result.Form.SetClientSize( 468, 278 );
       Result.EditBox1 := NewEditBox( Result.Form, [  ] ).SetPosition( 168, 104 );
       Result.EditBox1.Text := 'EditBox1';
       Result.EditBox1.Color := TColor(clWindow);
       Result.Form.CreateWindow;

    end;

    показано <<<<<<<<<<<<<
    хоть free, хоть close - одинаково
  • Dimaxx © (25.02.15 00:43) [37]
    KOL_asm.inc:

    procedure Run( var AppletCtl: PControl );
    asm
    //----- if  AppletCtl = nil then Exit;
          TEST      EAX, EAX
          JZ        @@exit
          PUSH      EBX
          XCHG      EBX, EAX

    //----- AppletRunning := TRUE;
          INC       [AppletRunning]

    //----- Applet := AppletCtl;
          MOV       EAX, [EBX]
          MOV       [Applet], EAX

    //----- AppletCtl.CreateWindow;
          CALL      CallTControlCreateWindow

    //----- WHILE NOT AppletTerminated DO
    @@loop: CMP       [AppletTerminated], 0
          JNZ       @@end_loop

    //----- WaitMessage;
          CALL      WaitMessage

    //----- AppletCtl.ProcessMessages;
          MOV       EAX, [EBX]
          CALL      TControl.ProcessMessages

          {$IFDEF   USE_OnIdle}
    //----- ProcessIdle(AppletCtl);
          MOV       EAX, [EBX]
          CALL      [ProcessIdle]
          {$ENDIF}

          JMP       @@loop
    @@end_loop:

          {$IFDEF LET_MENU_LEAK}
          MOV       ECX, [EBX]
          XCHG      EAX, EBX
          POP       EBX
          JECXZ     @@exit
          {$ELSE}
          POP       EBX
          LEA       EAX, [Applet]
          CMP       [EAX], 0         <-ОШИБКА!!!!
          JZ        @@exit
          {$ENDIF}
          CALL      TerminateExecution
    @@exit:
    end;

  • Dimaxx © (25.02.15 00:43) [37]
    KOL_asm.inc:

    procedure Run( var AppletCtl: PControl );
    asm
    //----- if  AppletCtl = nil then Exit;
          TEST      EAX, EAX
          JZ        @@exit
          PUSH      EBX
          XCHG      EBX, EAX

    //----- AppletRunning := TRUE;
          INC       [AppletRunning]

    //----- Applet := AppletCtl;
          MOV       EAX, [EBX]
          MOV       [Applet], EAX

    //----- AppletCtl.CreateWindow;
          CALL      CallTControlCreateWindow

    //----- WHILE NOT AppletTerminated DO
    @@loop: CMP       [AppletTerminated], 0
          JNZ       @@end_loop

    //----- WaitMessage;
          CALL      WaitMessage

    //----- AppletCtl.ProcessMessages;
          MOV       EAX, [EBX]
          CALL      TControl.ProcessMessages

          {$IFDEF   USE_OnIdle}
    //----- ProcessIdle(AppletCtl);
          MOV       EAX, [EBX]
          CALL      [ProcessIdle]
          {$ENDIF}

          JMP       @@loop
    @@end_loop:

          {$IFDEF LET_MENU_LEAK}
          MOV       ECX, [EBX]
          XCHG      EAX, EBX
          POP       EBX
          JECXZ     @@exit
          {$ELSE}
          POP       EBX
          LEA       EAX, [Applet]
          CMP       [EAX], 0         <-ОШИБКА!!!!
          JZ        @@exit
          {$ENDIF}
          CALL      TerminateExecution
    @@exit:
    end;

  • Dimaxx © (25.02.15 00:46) [38]
    В destructor TMenu.Destroy не используется (но определяется) Next.
  • Dimaxx © (25.02.15 00:46) [38]
    В destructor TMenu.Destroy не используется (но определяется) Next.
  • Vladimir Kladov © (25.02.15 05:35) [39]

    > CMP       [EAX], 0         <-ОШИБКА!!!!

    Какая? В Delphi7 ошибки нет. У вас что, Free Pascal? Delphi 201x? Пишите яснее.


    > В destructor TMenu.Destroy не используется (но определяется)
    > Next.


    destructor TMenu.Destroy;
    var Next, Prnt: PMenu;
       {$IFNDEF LET_MENU_LEAK}
       Save_Ref: Integer;
       {$ENDIF}
    begin
     {$IFDEF DEBUG_MENU_DESTROY}
     LogFileOutput( GetStartDir + 'TMenu.Destroy.txt',
       Int2Hex( DWORD( @ Self ), 6 ) + ' ' + Int2Str( RefCount ) );
     {$ENDIF}
     if Count > 0 then
     begin
       FMenuItems.ReleaseObjects;
       FMenuItems := NewList;
     end;
     if FParentMenu <> nil then
     begin
       {$IFNDEF LET_MENU_LEAK}
       Save_Ref := Self.fRefCount; //** Очень грязный хак, конечно. Цель: предотвратить
       Self.fRefCount := 17;       //   попытку повторного уничтожения этого объекта меню.
       {$ENDIF}
           Prnt := FParentMenu;
           Next := Prnt.RemoveSubMenu( FId );
           FParentMenu := nil;
           Prnt.FMenuItems.Remove( @ Self );
       {$IFNDEF LET_MENU_LEAK}
           Self.fRefCount := Save_Ref; //** Можно было бы и не восстанавливать.
       {$ELSE}
           if Next = nil then Exit;    //** Пришлось закомментарить. Вызывало утечку.
       {$ENDIF}
     end;
      if (FControl <> nil) and (FControl.fMenu = FHandle) and (FHandle <> 0) then
      begin
        if  {$IFDEF USE_FLAGS} not (G2_Destroying in FControl.fFlagsG2)
            {$ELSE} not FControl.fDestroying {$ENDIF} then //!!!fix by Galkov
        begin
          Windows.SetMenu( FControl.fHandle, 0 );
          // this removes main menu from window, but does not destroy it
        end;
        FControl.fMenu := 0;
        Next := PMenu( FControl.fMenuObj );
        while Next <> nil  do
        begin
          if Next.fNextMenu = @Self then
          begin
            Next.fNextMenu := fNextMenu;
            break;
          end;
          Next := Next.fNextMenu;
        end;
      end;
      Next := fNextMenu;
      if FBitmap <> 0 then
        Bitmap := 0;
      if FHandle <> 0 then
      begin
        //if not
        DestroyMenu( FHandle )
        // then LogFileOutput( GetStartDir + 'err.log.txt', SysErrorMessage( GetLastError ) )
        ;
      end;
      FCaption := '';
      FMenuItems.Free;
      Next.Free;
      inherited;
      // all later created (popup) menus (of the same control)
      // are destroyed too
    end;


    Расскажите уже, каким компилятором пользуетесь, что он такую чушь сказал.
  • Vladimir Kladov © (25.02.15 05:35) [39]

    > CMP       [EAX], 0         <-ОШИБКА!!!!

    Какая? В Delphi7 ошибки нет. У вас что, Free Pascal? Delphi 201x? Пишите яснее.


    > В destructor TMenu.Destroy не используется (но определяется)
    > Next.


    destructor TMenu.Destroy;
    var Next, Prnt: PMenu;
       {$IFNDEF LET_MENU_LEAK}
       Save_Ref: Integer;
       {$ENDIF}
    begin
     {$IFDEF DEBUG_MENU_DESTROY}
     LogFileOutput( GetStartDir + 'TMenu.Destroy.txt',
       Int2Hex( DWORD( @ Self ), 6 ) + ' ' + Int2Str( RefCount ) );
     {$ENDIF}
     if Count > 0 then
     begin
       FMenuItems.ReleaseObjects;
       FMenuItems := NewList;
     end;
     if FParentMenu <> nil then
     begin
       {$IFNDEF LET_MENU_LEAK}
       Save_Ref := Self.fRefCount; //** Очень грязный хак, конечно. Цель: предотвратить
       Self.fRefCount := 17;       //   попытку повторного уничтожения этого объекта меню.
       {$ENDIF}
           Prnt := FParentMenu;
           Next := Prnt.RemoveSubMenu( FId );
           FParentMenu := nil;
           Prnt.FMenuItems.Remove( @ Self );
       {$IFNDEF LET_MENU_LEAK}
           Self.fRefCount := Save_Ref; //** Можно было бы и не восстанавливать.
       {$ELSE}
           if Next = nil then Exit;    //** Пришлось закомментарить. Вызывало утечку.
       {$ENDIF}
     end;
      if (FControl <> nil) and (FControl.fMenu = FHandle) and (FHandle <> 0) then
      begin
        if  {$IFDEF USE_FLAGS} not (G2_Destroying in FControl.fFlagsG2)
            {$ELSE} not FControl.fDestroying {$ENDIF} then //!!!fix by Galkov
        begin
          Windows.SetMenu( FControl.fHandle, 0 );
          // this removes main menu from window, but does not destroy it
        end;
        FControl.fMenu := 0;
        Next := PMenu( FControl.fMenuObj );
        while Next <> nil  do
        begin
          if Next.fNextMenu = @Self then
          begin
            Next.fNextMenu := fNextMenu;
            break;
          end;
          Next := Next.fNextMenu;
        end;
      end;
      Next := fNextMenu;
      if FBitmap <> 0 then
        Bitmap := 0;
      if FHandle <> 0 then
      begin
        //if not
        DestroyMenu( FHandle )
        // then LogFileOutput( GetStartDir + 'err.log.txt', SysErrorMessage( GetLastError ) )
        ;
      end;
      FCaption := '';
      FMenuItems.Free;
      Next.Free;
      inherited;
      // all later created (popup) menus (of the same control)
      // are destroyed too
    end;


    Расскажите уже, каким компилятором пользуетесь, что он такую чушь сказал.
  • Vladimir Kladov © (25.02.15 05:48) [40]
    Во вчерашнем обновлении не довставил новый TerminateExecution в KOL_ASM.INC. Поправить смогу только вечером. Берите код, что я здесь привел вчера, и вставьте сами (отличается комментариями с паскаль-кодом). Либо включите PAS_VERSION.
  • Vladimir Kladov © (25.02.15 05:48) [40]
    Во вчерашнем обновлении не довставил новый TerminateExecution в KOL_ASM.INC. Поправить смогу только вечером. Берите код, что я здесь привел вчера, и вставьте сами (отличается комментариями с паскаль-кодом). Либо включите PAS_VERSION.
  • Владимир Кладов (07.05.15 16:33) [55]
    Я в курсе. Начиная с Windows 8.1, GetVersion/GetVersionEx объявлена устаревшей. Для того, чтобы приложение правильно определяло версию, к нему нужен специально оформленный манифест.
  • DWorker (07.05.15 18:12) [56]
    Короткий вариант, определяет до 10 версии (9х поддержки нет):


    function WinVerShort: TWindowsVersion;
    begin
     case LoWord(GetVersion) of
       $0005: Result := wvY2K;
       $0105: Result := wvXP;
       $0205: Result := wvServer2003;
       $0006: Result := wvVista;
       $0106: Result := wvSeven;
       $0206: Result := wvEight;
       $0306: Result := wvEight_1;
       $000A: Result := wvTen;
       else
         Result := wvNT;
     end;
    end;



    Нужен подобный манифест:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
       <assemblyIdentity
           type="win32"
           name="DelphiApplication"
           version="1.0.0.0"
           processorArchitecture="*"
       />
       <description> my foo exe </description>
       <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
           <security>
               <requestedPrivileges>
                   <requestedExecutionLevel
                       level="asInvoker"
                       uiAccess="false"
                   />
               </requestedPrivileges>
           </security>
       </trustInfo>
       <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
           <application>
               <!-- Windows 10 -->
               <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
               <!-- Windows 8.1 -->
               <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
               <!-- Windows Vista -->
               <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
               <!-- Windows 7 -->
               <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
               <!-- Windows 8 -->
               <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
           </application>
       </compatibility>
    </assembly>

  • alexacolor (08.05.15 11:06) [57]
    актуальный манифест нынче очень полезен.

    функция _WStrLComp в паскалевском исполнении за гранью добра и зла
    из за неё не работают Name Value в WStrList, например
  • alexacolor (08.05.15 14:09) [58]
    p.s. Ну не то что бы за гранью, но может запилить SVN комюнити?
    Образовалось ещё одно применение для KOL: firemonkey программы для Windows. Всякие Tray Icon, tree и прочее
  • Dimaxx © (11.05.15 22:12) [59]
    При создании приложения в KOLProject меняем шрифт - в проекте в файле .inc меняются параметры любые, кроме имени шрифта. В итоге шрифт ВСЕГДА System независимо от заданного. Эта шляпа тянется уже давно - то работает, то после очередного обновления КОЛ опять не работает.
  • Thaddy © (26.05.15 12:20) [60]

       Form.Font.ReleaseHandle;
       Form.Font.AssignHandle(GetStockObject(DEFAULT_GUI_FONT));



    But I also have a better, but more complicated solution.
  • Netspirit (10.03.17 12:59) [61]
    Ошибка в PAS_ONLY версии функции StrScan - функция никогда не возвращает nil, что приводит к ошибке, если символ не найден. Правильный код:


    function StrScan(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
    begin
     Result := nil;
     if Str = nil then Exit;
     
     while Str^ <> #0 do
     begin
       if Str^ = Chr then
       begin
         Result := Str;
         Break;
       end;
       Inc(Str);
     end;
    end;

  • DKOL (16.03.17 13:06) [62]
    А если StrScan исправить, то другие функции начнут глючить... Во многих местах не проверки на nil

    ps. вроде как то обсуждалось уже, надо поискать..
  • Netspirit (16.03.17 15:11) [63]

    > А если StrScan исправить, то другие функции начнут глючить.

    Нет, в том то и смысл, что из описания этой функции следует, что она должна вернуть nil, если символ не найден. Соответственно, весь код и так проверяет возвращаемый результат. И в случае PAS_ONLY успешно падает при ненахождении символа. Когда-то в старых версиях этот же баг был и в ASM-версии, но его исправили, а в PAS - забыли.


    > вроде как то обсуждалось уже, надо поискать

    Сравнительно недавно то же обсуждали и правили в WStrScan. Так сказать, по образу и подобию...
  • Netspirit (16.03.17 15:32) [64]
    Напомню. Оригинал выглядит так:
    function StrScan(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
    begin
       while Str^ <> Chr do
       begin
           if Str^ = #0 then break;
           inc(Str);
       end;
       Result := Str;
    end;


    В случае ненахождения символа возвращается не nil, а указатель на терминирующий #0.

    Ну, и без проверки if Str = nil then Exit сама функция StrScan не падает только потому, что при вызове её обычно как if StrScan(PChar(S), 'A') <> nil then, Delphi при приведении строки к PChar вставляет ещё один вызов функции, которая проверяет строку на пустоту и для пустой строки возвращает действительный указатель на заранее заготовленный символ #0, лежащий где-то в области констант или глобальных переменных.
    Так вот, если захочется ускориться, чтобы Delphi не вызывал дополнительную функцию, и вызвать StrScan как if StrScan(Pointer(S), 'A') <> nil then, то без проверки параметра Str на nil функция упадёт.

    Я только что глянул, WStrScan тоже надо поправлять.
  • DKOL (17.03.17 08:06) [65]

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

    Например функция StrScan, проверок нету.


    > function StrScan(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
    .....

    Изменения на svn внёс, StrScan пофиксил заодно.

    WStrScan и ASM версии - не смотрел...
  • DKOL (17.03.17 08:07) [66]

    > Например функция StrScan, проверок нету.


    Имелась ввиду функция StrCat, копи-паста она такая)
  • Netspirit (17.03.17 12:57) [67]
    А-а-а, там ещё и StrCat есть. А может кто-то на пальцах объяснить логику этой функции? Как я понимаю, эта функция объединяет две строки в одну, результат заносит по указателю в Dest, в качестве результата возвращает указатель на Dest. Типа, так?

    procedure Test;
    var
     Src, Dst: string;
    begin
     Dst := 'ABC';
     Src := 'DEF';
     
     MessageBox(0, StrCat(PAnsiChar(Dst), PAnsiChar(Src)), '', 0);
     // PS: Этот код выдаёт ошибку!
    end;


    Вопрос: а кто ж в этой фунции занимается выделением памяти под результат объединения, а затем должен освободить эту память?
    Чтоб далеко не ходили, приведу оригиналы этих функций:

    function StrScan(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
    begin
       while Str^ <> Chr do
       begin
           if Str^ = #0 then break;
           inc(Str);
       end;
       Result := Str;
    end;

    function StrCopy( Dest, Source: PAnsiChar ): PAnsiChar;
    var L: Integer;
    begin
       L := StrLen(Source);
       Move(Source^, Dest^, L+1);
       Result := Dest;
    end;

    function StrCat( Dest, Source: PAnsiChar ): PAnsiChar;
    begin
     // Итак. Оригинальная StrScan найдёт #0 в конце Dest
     // и вернёт нам указатель на конец Dest
     // Функция StrCopy должна скопировать Source в конец Dest
     // Спрашивается: а кто должен дать гарантию, что после
     // оригинального Dest есть свободное место, откуда оно взялось,
     // и кто отвечает за его освобождение?
     StrCopy( StrScan( Dest, #0 ), Source );
     Result := Dest;
    end;


    Исходя из выше озвученных рассуждений правильное использование должно выглядеть так:

    procedure Test;
    var
     Src, Dst: string;
    begin
     Dst := 'ABC';
     Src := 'DEF';
     SetLength(Dst, Length(Dst)+Length(Src)); // Выделили память в Dst, чтобы уместить Dst+Src
     
     MessageBox(0, StrCat(PAnsiChar(Dst), PAnsiChar(Src)), '', 0);
    end;


    Где в цепочке вызовов StrCat->StrCopy+StrLen->StrScan находится термин "fast" из описания функции StrCat (в отличие от обычного Dst := Dst + Src;)?

    Нюанс: в моей поправке StrScan символ #0 не найдётся. Потому что этот символ - это ограничитель null-terminated строки (используемой с типом PChar). Он не может являться частью строки (в отличие от дельфийского string). Единственная необходимость в получении указателя на #0 - это определение конца строки. И зачем это необходимо? Для определения количества символов, расположенных по указателю PChar (до терминирующего #0), используется функция StrLen().
  • DKOL (23.03.17 12:01) [68]

    > Нюанс: в моей поправке StrScan символ #0 не найдётся.

    Ну вот, как и говорил, исправили одно - сломали другое...


    > Единственная необходимость в получении указателя на #0 -
    >  это определение конца строки. И зачем это необходимо? Для
    > определения количества символов, расположенных по указателю
    > PChar (до терминирующего #0), используется функция StrLen().
    >

    В StrCat же и используется.


    > Где в цепочке вызовов StrCat->StrCopy+StrLen->StrScan находится
    > термин "fast" из описания функции StrCat (в отличие от обычного
    > Dst := Dst + Src;)?

    Не совсем понимаю, а зачем здесь термин fast?


    > // Спрашивается: а кто должен дать гарантию, что после
    >   // оригинального Dest есть свободное место, откуда оно
    > взялось,
    >   // и кто отвечает за его освобождение?


    Гарантий никто не дает. Просто бывает с PChar строками так работают. Выделяют память с запасом, а потом через StrCat клеят.
  • Netspirit (23.03.17 16:20) [69]

    > исправили одно - сломали другое...

    Описание StrScan():
    {* Fast search of given character in a string. Pointer to found character  (or nil) is returned. }

    То-есть, должна вернуть nil, если искомый символ не найден. А условием ненахождения искомого символа является достижение символа #0. Тогда для поиска #0 нужно добавлять ещё условие. Например, так:
    function StrScan(Str: PAnsiChar; Chr: AnsiChar): PAnsiChar;
    begin
     Result := nil;
     if Str = nil then Exit;
     
     while Str^ <> #0 do
     begin
       if Str^ = Chr then
       begin
         Result := Str;
         Exit;
       end;
       Inc(Str);
     end;
     
     if (Chr = #0) and (Str^ = #0) then Result := Str;  
    end;



    > а зачем здесь термин fast?

    Я ни при чем. Описание функции StrCat:
    {* Append source string to destination (fast). Pointer to Dest is returned. }


    > Выделяют память с запасом, а потом через StrCat клеят.

    Я бы использовал Move() и не заморачивался (тем более, что вызывающему обычно точно известно, сколько места уже занято в том участке памяти, и сколько его выделено, следовательно, лишние StrLen ему не нужны).

    Сделайте эту StrCat так:

    function StrCat(Dest, Source: PAnsiChar): PAnsiChar;
    begin
     Result := Dest;
     if (Dest = nil) or (Source = nil) then Exit;
     Move(Source^, Dest[StrLen(Dest)], StrLen(Source)+1);
    end;
  • Netspirit (23.03.17 17:02) [70]
    PS: условие and (Str^ = #0) в вышеприведенному коде StrScan, наверное, можно выбросить.
  • Dimaxx © (23.03.17 21:07) [71]
    >> Сделайте эту StrCat так:
    Вкорне неверно. У вас не выделена память для строки Dest, чтобы принять Source простым копированием данных. Для начала нужно выделить память, а уж после копировать.
  • Dimaxx © (23.03.17 21:16) [72]
    Я чет ваще не тащу - зачем так сделано?

    function StrCopy( Dest, Source: PAnsiChar ): PAnsiChar;
    var L: Integer;
    begin
       L := StrLen(Source);
       Move(Source^, Dest^, L+1);
       Result := Dest;
    end;



    Это ж бред. К примеру, есть у нас две строки "AAA" и "BBB". Мы передаем указатели в StrCopy и что получается? "BBB" копируется после "AAA" и получится "AAABBB". Но! Память для строки "AAA" у нас выделена только на три(!!) символа! А мы тупо копируем в область после первой строки (которая по идее ей еще не принадлежит) вторую строку. Это все равно что пытаться копировать один массив, выделенный GetMem, в конец второго массива. Но память-то выделена только под каждый размер массивов раздельно! Для слияния массивов нам надо Realloc памяти первого массива, с размером суммарных размеров массивов.
  • Dimaxx © (23.03.17 21:21) [73]
    И еще. Move(Source^, Dest^, L+1) скопирует содержимое Source в НАЧАЛО Dest!!! Разве это верно?
  • Dimaxx © (23.03.17 21:24) [74]
    Тьфу, я все напутал - думаю про StrCat, а пишу про StrCopy...

    StrCopy должна сначала сделать длину Dest равной длине Source, а потом копировать. Ведь размеры строк могут различаться.

    А вот в [72] все сказанное верно для StrCat в [69].
  • Netspirit (24.03.17 11:40) [75]

    > StrCopy должна сначала сделать длину Dest равной длине Source

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


    > скопирует содержимое Source в НАЧАЛО Dest

    Это так и задумано - вызывающий сам передаёт указатель, по которому нужно записать данные. А указывать этот указатель может куда угодно. Например, StrCat находит указатель на завершающий #0 и передаёт его в эту функцию.

    Напоминаю: если вы пользуетесь типом string, то вместо StrCat лучше использовать Dst := Dst + Src, а если таких операций много (типа, for i := 1 to 100000 do S := S + S2;) то такой код заменяется на такой:
    L := Length(S2);
    if L = 0 then Exit;
    SetLength(S, 100000 * L);
    i := 1;
    while i <= 100000 do
    begin
     Move(S2[1], S[i], L);
     Inc(i, L);
    end;

  • Dimaxx © (24.03.17 23:53) [76]
    >> для этих функций вызывающий сам должен беспокоиться куда будут помещаться новые данные
    Не соглашусь. Я, к примеру, этими функциями не пользовался и если бы стал - даже не подумал бы, что я сам должен чего-то увеличивать, прежде чем вызывать. Это все должно делаться внутри функции, а не до ее вызова.
  • Netspirit (27.03.17 11:16) [77]
    Так и я тоже не подозревал о существовании этих функций. Просто пришлось делать выводы, глядя на их код.
  • Dimaxx © (09.04.17 10:54) [78]
    Еще один момент. Интенсивное использование Stream (проверял на открытом большом файле и из него копировал подряд куски в другие файлы - порядка 1000+ файлов) роняет приложение. Сначала все идет норм, потом АВ. То же самое на стандартном дельфевом TFileStream без проблем и падений.
  • DKOL (10.04.17 08:33) [79]
    Dimaxx, а как то отладчиком реально поймать? или тулзами типа madExcept?
  • Netspirit (10.04.17 10:40) [80]
    Dimaxx, ты бы выложил минимальную процедурку, которая делает что надо. Может быть, где-то с указателями на буфер и размером данных напутал.
  • Dimaxx © (10.04.17 23:49) [81]
    >> а как то отладчиком реально поймать? или тулзами типа madExcept?
    По идее при АВ выдается адрес исключения. Надо по нему прыгнуть в код и увидеть где произошло исключение.

    >> ты бы выложил минимальную процедурку, которая делает что надо. Может быть, где-то с указателями на буфер и размером данных напутал.
    Я ж говорю - дельфевый выполняет ту же операцию без проблем. Размеры файлов все известны - они в виде списка типа "имя-размер":

    SomeDir/SomeFile.dat 12345



    Сами файлы все слиты один за одним в один огромный файл без заголовков. По сути различия только в коде со Stream. В выходные постараюсь найти код и опробовать, я уже не помню что и как делал.
  • PrnZ (12.04.17 05:01) [82]
    Насчёт Stream. Адаптировал на КОЛ библиотеки NewAC и LZMA2 - может конечно я чёто неправильно делаю - смысл такой -

    type PA=^TA;
    TA=object(TObj)
    ...
    FStream:PStream;
    ...
    // etc
    end;

    Ну и соответственно процедуры типа ReadLZMA(...) SeekLZMA(...) etc в соответствующей структуре.

    ДАК ВОТ - пишу прогу с использованием оригинальных классов LZMA и соответственно с моим объектом. Разница - 160К. НО!!! прога с классами быстрее раз в 5. всё делал вроде бы по закону. Такое же наблюдается с адаптационными объектами NewAC (при чтении и распаковке файлов, но там возможно ДЛЛ гонит... но в классах же не гонит... хз), и не только. Некоторые адаптации с сайта (DlUCL напр.) тоже тормозят в сравнении с классом.

    Делал тестовый класс/объект с рандомным потоком - вроде всё норм... хз...
  • Netspirit (12.04.17 14:35) [83]
    Не представляю что там может тормозить. Сколько там того объекта?
    Может где-то в часто вызываемые процедуры объект передаётся не по ссылке, а по значению? Всё равно, разница в скорости вряд-ли была бы больше 20%, хотя зависит от кода...
  • Dimaxx © (12.04.17 23:07) [84]
    Вопрос по падение снимается. Нашел старый проект, скомпилировал - 2 гиговый файл "разложился" без проблем.
  • PrnZ (15.04.17 10:13) [85]
    to:Netspirit
    Вот и я не могу понять. Оригинальный класс наследуется от TFileStream. Я же делаю объект от KOL.TObj, делаю поле Stream:PStream; делаю в конструкторе NewStream(ProcRec), где ProcRec - record ReadProc, WriteProc, SeekProc etc. end; соответственно перевожу методы из оригинального класса в функции Read,Write,Seek итд. Короче вроде всё правильно. О том что "вызываемые процедуры объект передаётся не по ссылке, а по значению" - не, я уже забыл когда на ВЦЛ писАл. Да и компилятор не позволит. ХЗ чё за фигня... Могу выложить модуль на справедливый народный суд. Модуль сколько весит - не помню, не от себя сейчас сижу. Чё-то около 2000-2500 строк.
  • Dimaxx © (18.04.17 20:32) [86]
    Шрифт в КОЛ уже реально выбешивает.

    Задаешь шрифт (Tahoma, height=-11, он по умолчанию), в дизайнере все нормально. Компиляция, запуск. Какого хрена??? Шрифт, мать его, System (корявый растровый .fon), размер, мать его, 10. В unit1_1.inc про шрифт вообще ни строчки. Ничего не меняется, даже если в коде руками поставить имя шрифта (Tahoma) и высоту (-11). Ставишь -12 - шрифт Tahoma, высота -12 - все верно, но мне надо стандартный. Любое FontQuality не меняет ничего. Выставляешь fqProof - в unit1_1.inc ко всем контролам формы прописывается высота шрифта, но не та, что я задал (-11), а -13. Опять-таки WTF?? В итоге шрифт все же становится Tahoma, но размер неверный. И после возвращения FontQuality=fqDefault ничего не меняется, потому что весь unit1_1.inc испещрен FontHeight:=-13. Убрал руками все. Скомпилировал - шрифт опять System. То есть КОЛ игнорирует заданное и пихает свое. DefFont в KOL.pas установлен точно также - Tahoma, -11. Пишу руками в unit1_1.inc - FontHeight:=-11. Компилирую и все становится на свои места, но! После закрытия и открытия проекта файл unit1_1.inc перегенерируется заново и снова все через опу. Почему игнорит КОЛ - я хз. Имхо при записи кода создания формы в unit1_1.inc надо принудительно выставить параметры шрифта, либо искать где он гадит, если шрифт не задан и используется дефолтный.

    Далее: в dfm объект формы стоит первым. У всех контролов в dfm Font.FontHeight = -13. Откуда??? Я не задавал -13 вообще. С какого потолка оно взято? И почему KOL берет значения свойств из TForm, а не из TKOLForm???

    Помогло только принудительное создание шрифта DefFont

    procedure TForm1.KOLForm1BeforeCreateWindow(Sender: PObj);
    begin
     DeleteObject(Form.Font.ReleaseHandle);
     Form.Font.Assign(NewFont);
    end;

  • DKOL (13.05.17 18:09) [87]
    Если вдруг интересно кому - то вырезал кучу старого хлама из KOL.pas (типа нерабочей Linux поддержки, "очень важной" поддержки делфи 2 и т.д).
    Cкинул на свн https://sourceforge.net/projects/kolmck/

    зы. возможно что отвалилось\сломалось...
  • Vladimir Kladov © (17.05.17 21:15) [88]
    http://clavier.link (язык AL-IV - АЛФОР):
    18.05.2017 v0.62 Добавлена поддержка платформы Win32/Delphi/KOL (версия KOL 3.23) - на данный момент только не визуальной его части (работа продолжается).
  • Dimaxx © (01.07.17 19:05) [89]
    Столкнулся с глюком TBitmap. Гружу 24-битное, преобразовываю дизерингом в 8-битное. Затем мне надо, чтобы размеры (если они меньше заданных) были подогнаны под один и тот же размер (добавляются поля черного). Так вот после увеличения только ширины картинки изображение становится 32-битным (с какого перепугу??). Если сначала увеличить высоту, а потом ширину, то изображение остается 8-битным.
  • QAZ (07.07.17 19:38) [90]

    > Vladimir Kladov ©   (17.05.17 21:15) [88]

    регистрозависимость это дичь ....
    нет элементарной документации аля "хеловёрд" по спецификациям начать что то писать невозможно
  • sheleh (21.07.17 20:02) [91]
    Привет спецам!
    Помогите пжлст. Под андрюшу вышел бинарный транслятор x86 в ARM от программистов из Сколково, что писали нечто подобное под Эльбрус.
    В общем эти ребята в Play Market выложили свое творение - wine 1.9, работающий под андройдом на любом ARM устройстве. Там они его распространяют преимущественно для запуска старых игр. Называется ExaGear.
    И действительно, на нем работает куча программ. Но только не мои, написанные на delphi с применением библиотеки KOL. А так хотелось.....
    Вылетает даже минимальная программа, создающая пустую форму.
    Вот скрин https://s1.postimg.org/vkb1liaan/20170722_005204.jpg
    Компилирую в delphi 6, запущенной в этой среде. Отладчик не ссылается ни на какой участок кода. Как узреть, что именно приводит к вылету?
  • L`Autour (01.08.17 10:27) [92]
    по функции:
    function Extended2Str( E: Extended ): KOLString;

    нужно кроме предвартельной проверки E на 0, еще добавить проверку на Infinity и NAN, иначе уйдет в бесконечный цикл.
  • Dimaxx © (28.08.17 20:25) [93]
    Сделал для себя новый Format для КОЛ - старый слишком убог по функционалу. Абсолютно весь функционал вводить не стал, взял только самое распространенное.

    // для unicode - vswprintf_s

    function vsprintf_s(Buffer: PChar; BufferSize: integer; const Fmt: PChar; Args: pointer): integer; cdecl; external 'msvcrt.dll';

    function Format(const Fmt: string; Params: array of const): string;
    var
     VA,Tmp: PByte;
     Buffer: array[0..4095] of Char;
     I,A,Size: integer;
     D: double;
    begin
     FillChar(Buffer,sizeof(Buffer),0);
     if High(Params)>=0 then
       begin
         Size:=0;
         // Считаем размер буфера для аргументов
         for I:=0 to High(Params) do
           with Params[I] do
             case VType of
               vtInteger: Inc(Size,sizeof(Integer));
               vtChar: Inc(Size,sizeof(Char));
               vtWideChar: Inc(Size,sizeof(WideChar));
               vtPChar,vtAnsiString,vtPWideChar,vtWideString,vtPointer: Inc(Size,sizeof(Pointer));
               vtExtended: Inc(Size,sizeof(Double));
             end;
         GetMem(VA,Size);
         FillChar(VA^,Size,0);
         Tmp:=VA;
         for I:=0 to High(Params) do
           begin
             A:=sizeof(Pointer);
             with Params[I] do
               case VType of
                 vtInteger:
                   begin
                     A:=sizeof(Integer);
                     PInteger(Tmp)^:=VInteger;
                   end;
                 vtChar:
                   begin
                     A:=sizeof(Char);
                     PChar(Tmp)^:=VChar;
                   end;
                 vtPChar: PPointer(Tmp)^:=VPChar;
                 vtAnsiString: PPointer(Tmp)^:=VString;
                 vtWideChar:
                   begin
                     A:=sizeof(WideChar);
                     PWideChar(Tmp)^:=VWideChar;
                   end;
                 vtPWideChar: PPointer(Tmp)^:=VPWideChar;
                 vtWideString: PPointer(Tmp)^:=VWideString;
                 vtExtended:
                   begin
                     A:=sizeof(Double);
                     D:=VExtended^;
                     PDouble(Tmp)^:=D;
                   end;
               end;
             Inc(Tmp,A);
           end;
         I:=vsprintf_s(@Buffer[0],4096,PChar(Fmt),VA);
         if I>0 then
           begin
             SetLength(Result,I);
             Result:=Buffer;
           end;
         if VA<>nil then FreeMem(VA);
       end;
    end;



    Все символы описаны в https://msdn.microsoft.com/ru-ru/library/hf4y5e3w.aspx
  • QAZ © (06.09.17 17:26) [94]

    > L`Autour   (01.08.17 10:27) [92]
    > по функции:function Extended2Str( E: Extended ): KOLString;
    > нужно кроме предвартельной проверки E на 0, еще добавить
    > проверку на Infinity и NAN, иначе уйдет в бесконечный цикл.
    >

    незнай как там с проверками, но Extended2Str в 6 раз!!! медленней стандартной Str и в 4.5 раз FloatToStr из сисутилсов
  • DKOL (07.09.17 06:30) [95]
    >Сделал для себя новый Format для КОЛ - старый слишком убог по функционалу.

    А в чем убогость то заключается? Вроде основное все было..

    >незнай как там с проверками, но Extended2Str в 6 раз!!! медленней стандартной Str и в 4.5 раз FloatToStr из сисутилсов

    Получается у Extended2Str нет никаких преимуществ перед стандартной Str?
  • QAZ © (07.09.17 16:56) [96]

    > Получается у Extended2Str нет никаких преимуществ перед
    > стандартной Str?

    нету, так же как и у FloatToSt,IntToStr,Int2Str
  • L`Autour (08.09.17 10:24) [97]
    И как же KOLString, UNICODE_CTRLS?
  • QAZ © (08.09.17 14:22) [98]

    > И как же KOLString, UNICODE_CTRLS?

    а без разницы, Str в топе
  • Dimaxx © (08.09.17 18:02) [99]
    >> А в чем убогость то заключается? Вроде основное все было..
    Типа старые функции небезопасны. И старый Format не поддерживает и половины возможностей. Насколько помню, плавающий формат он не переваривал. Была доработка, но она криво отображала float.
  • dlf (06.10.17 22:42) [100]
    если не ошибаюсь, в ТВижн чё то такое было, и с плавающими итп... без всяких vsprintf_s. по крайней мере видел в исходниках Дос Навигатора
  • Dimaxx © (16.02.18 14:04) [101]
    Бился сейчас с bitmap. До чего же он кривой!

    1) Assign иногда работает, иногда падает на ровном месте. В частности пытался сделать копию одного битмапа в другом, так после assign второй битмап упал на Free.
    2) Проблема была в глюке, когда присваиваешь ширину (или высоту, не помню уже сейчас), потом ее увеличиваешь, а потом уменьшаешь и scanline пользоваться невозможно = nil.
    3) NewDIBBitmap(ширина,высота,pf4bit) - делаем битмап подобным другому. Но scanline выдает nil. А достаточно сделать Canvas.FillRect(BoundsRect), чтоб залить всю канву черным (и, тем самым, "включить" наконец scanline) и все нормализуется. Спрашивается, какого хрена? По идее мы создали битмап, данные указаны, память под битовые данные выделена, а данных на самом деле нет.

    Имхо надо выбрасывать этот глюкавый битмап и делать на основе стандартного новый.
  • Netspirit (16.02.18 15:03) [102]
    Ну, так поправить Bitmap чтобы выделял память после создания и все свойства корректно заполнял (если текущее поведение не было сделано с целью отодвинуть алокацию ресурсов до первого использования - тогда надо искать/добавить возможность делать это по требованию).
  • Dimaxx © (16.02.18 17:16) [103]
    Так если бы это было только в этом. А с падениями на Free после Assign или (о, боже!) SaveToFile после работы со scanline, которые вылетают в ntdll, как быть? Ошибка в коде исключена - тоже самое в VCL работает без запинки. Вышеописанное на одном изображении проходит нормально, на следующем - падает. Причем меняешь изображения местами - сначала падающее, потом нет - все равно на втором падает.
  • Dimaxx © (16.02.18 17:26) [104]
    Кстати, в NewDIBBitmap память для DIBBits выделяется сразу, но непонятно, почему scanline выдает nil. И на кой черт в GetScanline:

    Result := Pointer( PAnsiChar( fDIBBits ) + fScanLineSize * Y );

    указатель fDIBBits оборачивается PAnsiChar?? Откуда такая дичь? Мб тут проблема? Неужели сложно сделать:

    Result := Pointer( DWORD( fDIBBits ) + fScanLineSize * Y );
  • Netspirit (16.02.18 18:26) [105]

    > Откуда такая дичь?

    Ну, так арифметика с Pointer-ами (до недавнего времени) работает только с PAnsiChar(). Так и привыкли.

    > Мб тут проблема?

    Да, вроде, вполне безобидный код. Возвратит лажу, если fDIBBits указывает на что-то левое или fScanLineSize вычислен неправильно.
  • Dimaxx © (19.02.18 11:54) [106]
    Проблему с падением при уменьшении глубины цвета решил - тупо загнал одинаковые палитры в битмапы и отрисовал большую глубину на меньшую. Все "сконвертилось", палитра не искажена, запись и удаление без вылетов. Костыль, конечно, но другого выхода пока нет.
  • Styx © (19.02.18 22:59) [107]

    > отрисовал большую глубину на меньшую

    А разве есть какой-то другой способ?
  • Dimaxx © (20.02.18 10:04) [108]
    >> А разве есть какой-то другой способ?
    Руками. Тем более, если палитра заранее неизвестна (дизеринг). В данном случае палитра была известна и "умещалась" в 16 цветов. Но могут быть варианты, когда исходная палитра имеет цветов больше, чем результирующая.
 
Конференция "KOL" » KOL 3.23 [Delphi, Windows]
Есть новые Нет новых   [119362   +18][b:0.001][p:0.016]