Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / rsdn.ru

 
Чтобы не потерять эту дискуссию, сделайте закладку « предыдущая ветвь | форум | следующая ветвь »

KOL 3.23 [Delphi, Windows]


Vladimir Kladov ©   (21.02.15 10:24

[-] Исправления в 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;


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, чудеса не менее интересные, включая "рунтаймеррор"


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: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" и пролетает мимо ненаходит


Vladimir Kladov ©   (24.02.15 15:59[34]

PDWORD(адрес)^ - разыменовать надо.


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 - одинаково


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.


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.


QAZ   (25.02.15 11:07[41]

в фрейме видимо не освобождается сама форма или как там ее назвать
если делать так, уничтожая по клику кнопки
procedure TForm1.KOLFormFormCreate(Sender: PObj);
begin
NewForm2(Form2,form1.Panel1);
NewForm3(Form3,form1.Panel2);
end;

procedure TForm1.Button1Click(Sender: PObj);
begin
Form2.Form.Free;
Form3.Form.Free;
Free_And_Nil(Form2);
Free_And_Nil(Form3);
end;

то случайным образом в 4 из 5 случаев, потом, приложение закроется молча, а в 1 случае портянка на весь экран, без Free_And_Nil "корневой" формы стабильно небольшая утечка


QAZ   (25.02.15 11:47[42]

обнаружил также избыточную генерацию бесполезного кода со стороны MCK в *.inc файлах
простой пример, главная форма с центрированием по эрану + панели с выравниванием
procedure NewForm1( var Result: PForm1; AParent: PControl );
begin

 {$IFDEF KOLCLASSES}
 Result := PForm1.Create;
 {$ELSE OBJECTS}
 New( Result, Create );
 {$ENDIF KOL CLASSES/OBJECTS}
 Result.Form := NewForm( AParent, 'Form1' ).SetPosition( 333, 228 );
 Applet :=  Result.Form;
 Result.Form.Add2AutoFree( Result );
   Result.Form.SetClientSize( 649, 361 );
   Result.Form.Font.FontHeight := -11;
   Result.Panel1 := NewPanel( Result.Form, esRaised ).SetAlign ( caBottom ).SetSize( 0, 191 );
   Result.Panel2 := NewPanel( Result.Form, esRaised ).SetAlign ( caRight ).SetSize( 305, 0 );
   Result.Button1 := NewButton( Result.Form, 'Button1' ).SetPosition( 128, 16 );
     Result.Button1.OnClick := Result.Button1Click;
   Result.Form.CenterOnParent;
   Result.KOLFormFormCreate( Result );

end;

сначала форма создается с координатами дизайнтайма SetPosition( 333, 228 );
потом уже под конец центруется на десктопе Result.Form.CenterOnParent;
понятно что при включеных свойствах CenterOnScreen и CenterOnCurrentScreen генерация кода вызова SetPosition( 333, 228 ) нафиг не нужна

панели SetAlign ( caBottom ).SetSize( 0, 191 )
при  наличии включенного свойства выравнивания, должен генерироваться только код SetSize( 0, 191 ), т.к. стартовый размер уже расчивается сразу в дезайнтайме, а SetAlign ( caBottom ) интерактивная рунтайм процедура, которая при создании формы конкретного стартового размера не имеет смысла

думаю таких моментов можно найти еще много при желании
итог - весь тот код что пытаемся экономить в KOL, транжирит MCK


QAZ   (25.02.15 12:48[43]


> а SetAlign ( caBottom ) интерактивная рунтайм процедура

пардон SetAlign странная процедура, ее логичней перевести исключительно в установщик флага выравнивания, без последующего вызова AlignChildrenProc
или выделить подобные функции каким нибуть префиксом типа MCK_UseOnly_ чтобы они только отвечали за установку свойств без интерактива, который при запуске приложения не имеет смысла


Vladimir Kladov ©   (25.02.15 19:46[44]

Обновил.


> избыточную генерацию бесполезного кода

Тоже мне новость. Кому нужен супер-компактный код, пишет "на чистом KOL".


Dimaxx ©   (25.02.15 21:41[45]

2 Vladimir Kladov: Delphi 5

[Error] KOL_ASM.inc(773): Invalid combination of opcode and operands.

По поводу Next - [Hint] KOL.pas(28984): Value assigned to 'Next' never used
при клике ссылается на Next := Prnt.RemoveSubMenu( FId ); в деструкторе.


Dimaxx ©   (25.02.15 21:46[46]

CMP dword ptr [EAX], 0 прокатывает, но я не знаю какая именно разрядность используется - byte/word/dword.


Vladimir Kladov ©   (26.02.15 18:39[47]

Добрался до Delphi5.


> Next - [Hint] KOL.pas(28984): Value assigned to 'Next' never
> used

Хорошо, это есть в Delphi5, согласен. Но это ни на что не влияет. Присваивается, дальше не используется, неприятность -только само сообщение.

Ошибка в CMP [EAX], 0 -- да, пока не поставил Update1, не показывал и компилировал правильно. Конечно, правильно CMP dword ptr [EAX], 0
Ведь в EAX был загружен адрес указателя (LEA EAX, Applet), и этот указатель сравнивается с NIL. Размер указателя в 32-битной платформе был DWORD.

Сейчас буду обновлять версию на сайте.


Dimaxx ©   (26.02.15 22:46[48]

Я проверил в портабельной Д7: CMP [EAX],0 в дизассемблированном виде как раз CMP dword ptr [EAX], 0.

Насчет хинта про неиспользованность - да, этим Д5 частит (а иногда задалбывает). Чем ей не нравится, что переменная используется только в левой части? Я понимаю, когда объявлена переменная, но ее ни разу не использовали в коде. А чем тут не понравилось, хз?


ParanoiS ©   (03.03.15 21:02[49]

Первым делом при получении новой версии KOL.pas изменяю в нем ParamStr и ParamCount.

var
 CmdLineParams: array of String;

function CommandLineToArgvW(lpCmdLine: PWideChar; var pNumArgs: Integer): PPWideChar;
 stdcall; external 'shell32.dll';

function ParamStr( Idx: Integer ): KOLString;
begin
 if (Idx in [0..ParamCount]) then
 Result:=CmdLineParams[Idx] else
 Result:='';
end;

function ParamCount: Integer;
var
 i:Integer;
 p:PPWideChar;
 c:PWideChar;
begin
 if Length(CmdLineParams)=0 then begin
   p:=CommandLineToArgvW(GetCommandLineW,i);
   while p^<>'' do begin
     SetLength(CmdLineParams,Length(CmdLineParams)+1);
     c:=p^;
     CmdLineParams[Length(CmdLineParams)-1]:=KOLString(c);//(OleStrToString(c));
     inc(p);
   end;
 end;
 Result:=Length(CmdLineParams)-1;
end;


Dimaxx ©   (13.04.15 20:21[50]

KOL 3.23.4
Ни с того, ни с сего стал выеживаться StrList. Любой. То постоянно падал на AddStrings - причем и в асме, и в паскалевской реализации. Создал пустой проект для проверки, все работает. O_o. Пересоздал проект заново, глюк исчез. Но когда скомпилировал проект оказалось, что StrList не видит текст внутри себя. Текст грузится из Stream (я для контроля сохранил в промежуточный файл - текст на месте, какой и должен быть). Но Count=0, соответственно цикл перебора строк не начинается, а сразу завершается. Кто-нить сталкивался с подобным? Я впервые столкнулся за много лет использования KOL...


DWorker   (17.04.15 10:03[51]

Давно столкнулся с этим - TStrList.AddStrings асм-версия приводила к падению(кстати подобное было еще у каких-то асм-функций).. Проблему не искал, просто отключил асм версию(на свне отключена до сих пор), пас-версия вроде не падает..


alexacolor   (29.04.15 18:49[52]

пора бы обновить TWindowsVersion, уже есть 8, 8.1, 10!


Владимир Кладов   (05.05.15 21:10[53]

2 alexcolor
До Win8 - можно использовать старый GetVersion[Ex]. Дальше начинаются проблемы. Чтобы просто проверить версию, надо такого нагородить... Рука-лицо, в общем. Смотрю, народ уже сильно не заморачиваясь, просто проверяет ветку реестра. Или версию kernel32.dll. Я пока до проверки Win8 догоню в следующем выпуске, а дальше посмотрим.

Предложения на самый короткий код, решающий эту задачу, принимаются. Можно здесь.

Пока код такой (Паскаль):
function WinVer : TWindowsVersion;
var MajorVersion, MinorVersion: Byte;
   dwVersion, tstVersion: Integer;
begin
 if SaveWinVer <> $FF then Result := TWindowsVersion( SaveWinVer )
 else
 begin
   dwVersion := GetVersion;
   MajorVersion := LoByte( dwVersion );
   MinorVersion := HiByte( LoWord( dwVersion ) );
   tstVersion := ((MajorVersion and 127) shl 8) or MinorVersion;
   {$IFDEF SUPPORT_WIN9X}
   if dwVersion < 0 then
   begin
     case tstVersion of
       $000..$3FF: Result := wv31;
       $400..$409: Result := wv95;
     //$40A..$459: Result := wv98;
       $45A:       Result := wvME;
       else        Result := wv98;
     end;
   end;
   SaveWinVer := Ord( Result );
   Exit;
   {$ENDIF}
   case tstVersion of
   $000..$499: Result := wvNT;
   $500:       Result := wvY2K;
   $501:       Result := wvXP;
   $502..$5FF: Result := wvServer2003;
   $600:       Result := wvVista;
   $601:       Result := wvSeven;
   $602:       Result := wvEight;
   $603:       Result := wvEight_1;
   else        Result := wvTen;
   end;
   SaveWinVer := Ord( Result );
 end;
end;


DWorker   (06.05.15 09:19[54]

Код получился типа такого же, только без SaveWinVer. Только проблема в том что на 8.1 и 10 винде показывает wvEight


Владимир Кладов   (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 простым копированием данных. Для начала нужно выделить память, а уж после копировать.


версия для печати

Написать ответ

Ваше имя (регистрация  E-mail 







Разрешается использование тегов форматирования текста:
<b>жирный</b> <i>наклонный</i> <u>подчеркнутый</u>,
а для выделения текста программ, используйте <code> ... </code>
и не забывайте закрывать теги! </b></i></u></code> :)


Наверх

  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо