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

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

WndProc


dmk ©   (04.01.19 19:19

Всем привет! Почему в такой конфигурации PostQuitMessage не срабатывает?

class function TRenderForm.WndProc(Wnd: HWND; Msg: NativeInt; WParam: WParam; LParam: LParam): LResult;
var
 LMsg: TMessage;
 CanClose: Boolean;

begin
 LMsg.Msg := Msg;
 LMsg.WParam := WParam;
 LMsg.LParam := LParam;
 LMsg.Result := 0;

 case LMsg.Msg of

 WM_CLOSE:
 begin
   FWnd.DoCloseQuery(FWnd, CanClose);
   if CanClose then
   begin
     FWnd.DoClose(FWnd);
     PostQuitMessage(0); //<- Размещаем в очереди WM_QUIT
   end;
 end;

 WM_NCHITTEST,
 WM_MOUSEMOVE:
 begin
   FWnd.MessageToChild(LMsg);
   FWnd.Process(LMsg);
 end;

 else FWnd.Process(LMsg);
 end;//case

 Result := DefWindowProc(Wnd, LMsg.Msg, LMsg.WParam, LMsg.LParam);
end;

После PostQuitMessage(0) выборка из очереди прекращается,
т.е. WM_QUIT в очередь не добавляется. Почему так?


dmk ©   (04.01.19 19:24[1]

ЦИкл выборки сообщений такой:
procedure ProcessMessages(AWnd: TRenderForm);
var
 AMsg: tagMSG;
 bRet, bQuit: Boolean;

begin
 if (AWnd <> nil) then
 begin
   repeat
     bRet := PeekMessage(AMsg, AWnd.Handle, 0, 0, PM_REMOVE);
     bQuit := AMsg.message = (WM_QUIT or WM_CLOSE);

     if bRet then
     begin
       TranslateMessage(AMsg); //<- Преобразует коды в символьное представление. Например WM_TEXT
       DispatchMessage(AMsg);
     end
     else //OnIdle
     begin
       AWnd.Render;
     end;

   until bQuit;
 end;
end;


Leonid Troyanovsky ©   (05.01.19 10:25[2]


> dmk ©   (04.01.19 19:24) [1]

Непонятно, где ищется WM_QUIT, бо цикл заканчивается WM_CLOSE.
И почему не WM_DESTROY?

И в [1] очень подозрительная WndProc (class function?)
Должно быть MakeObjectInstance and so on.

--
Regards, LVT.


dmk ©   (05.01.19 13:02[3]

>И почему не WM_DESTROY?
Нигде не используется. Пока не нужно. Только WM_QUIT и WM_CLOSE.

>class function?
class function WndProc(Wnd: HWND; Msg: NativeInt; WParam: WParam; LParam: LParam): LResult; static; stdcall;
Она существует для всех экземпляров объекта.
У меня форма на чистом WinApi.

Внутри класса все class-переменные доступны как обычно.
Без созданного экземпляра класса class-переменные и class-функции доступны для применения. WndProc в TWinControl тоже является не частью класса. Еще переделать на новые «фичи» не успели :)

>И в [1] очень подозрительная WndProc
class-методы можно делать статичными. Как бы внутри класса и вроде как вне класса.
Видимо для удобства сделали.
http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Class_Methods#How_Class_Methods_Work_in_Delphi

>Должно быть MakeObjectInstance and so on.
Окно через RegisterClassEx/CreateWindowEx создается. WndProc тоже через RegisterClassEx назначается. DispatchMessage(AMsg) вызывает WndProc. Если WM_CLOSE, то хочется разместить в очереди сообщение WM_QUIT, а оно не размещается. Это и странно.


Styx ©   (05.01.19 20:55[4]


> bQuit := AMsg.message = (WM_QUIT or WM_CLOSE);

А зачем тут WM_CLOSE?


dmk ©   (05.01.19 21:50[5]

>А зачем тут WM_CLOSE?
WM_CLOSE генерится, когда закрываешь через крестик или меню.
Причем параллельно генерится WM_SYSCOMMAND + SC_CLOSE.


dmk ©   (05.01.19 22:03[6]

В общем разобрался. Нужно 2 цикла. Очередь же постоянно пустеет, поэтому выход из цикла означает состояние OnIdle. Вот так нормально работает и PostQuitMessage(0) тоже работает.
procedure ProcessMessages(AWnd: TRenderForm);
var
 AMessage: tagMSG;
 bMessage, bAppDone: Boolean;

begin
 if (AWnd <> nil) then
 begin
   bAppDone := False;

   while (not bAppDone) do
   begin
     repeat
       bMessage := PeekMessage(AMessage, AWnd.Handle, 0, 0, PM_REMOVE);

       if bMessage then
       begin
         TranslateMessage(AMessage);
         DispatchMessage(AMessage);
       end;

       bAppDone := (AMessage.message = WM_QUIT);

     until (not bMessage) or bAppDone;

     //---------------------------------------------
     // OnIdle
     //---------------------------------------------

     if (not bAppDone) then
     begin
       AWnd.Render;
     end;
   end;
 end;
end;


Leonid Troyanovsky ©   (06.01.19 08:57[7]


> dmk ©   (05.01.19 13:02) [3]

> У меня форма на чистом WinApi.

Да хоть на грязном хаке.
Оконная процедура из метода класса _должна_ создаваться
путем MakeObjectInstance и точка. RTFM.

> функции доступны для применения. WndProc в TWinControl тоже
> является не частью класса. Еще переделать на новые «фичи»
> не успели :)
class function существует с начала дельфи, но использовать ее
в качестве оконной никто никогда не планировал.
Задумайся, что будет если объект/окно не единственный.
С глобальной-то fwnd.

> вызывает WndProc. Если WM_CLOSE, то хочется разместить в
> очереди сообщение WM_QUIT, а оно не размещается. Это и странно.

Тебе уже двое намекнули на лог. ошибку с or WM_CLOSE.

--
Regards, LVT.


Leonid Troyanovsky ©   (06.01.19 09:14[8]


> dmk ©   (05.01.19 22:03) [6]

> В общем разобрался. Нужно 2 цикла. Очередь же постоянно
> пустеет, поэтому выход из цикла означает состояние OnIdle.
>  Вот так нормально работает и PostQuitMessage(0) тоже работает.

WM_QUIT и не должен попадать в оконную процедуру,
это же сигнал о выходе из цикла обработки сообщений.

       while GetMessage(msg, 0, 0, 0) do
       begin
         TranslateMessage(msg);
         DispatchMessage(msg);
       end;

В WM_DESTROY, ну или WM_CLOSE делаем PQM и всё.

А отрисовку обычно делают в WM_PAINT.
Для него уже предусмотрена низкоприоритетная обработка,
безо всяких велосипедов.

--
Regards, LVT.


Leonid Troyanovsky ©   (06.01.19 09:34[9]


> Leonid Troyanovsky ©   (06.01.19 08:57) [7]

> Тебе уже двое намекнули на лог. ошибку с or WM_CLOSE.

Хотя, это не та ошибка,  бо wm_quit or wm_close = wm_quit.
Sorry.

--
Regards, LVT.


dmk ©   (06.01.19 10:34[10]

Дело в этой строчке:
bAppDone := (AMessage.message = WM_QUIT);
Если проверку перед Dispatch поставить, то WM_QUIT не ловится, а если после Dispatch поставить, то ловится. Я же писал выше, что разобрался. PostQuitMessage работает.

MakeObjectInstance - это для VCL. У меня WinApi.

>Задумайся, что будет если объект/окно не единственный. С глобальной-то fwnd.
Можно так:
class var Wnds: TList<TWindow64>;
Тут с NoUser'ом разбирались: http://www.delphimaster.ru/cgi-bin/forum.pl?id=1490153872&n=5

Я свою миссию выполнил. От VCL оторвался.
Леонид, я всего 2 года в программировании. Много не знаю.
До этого были простые студенческие поделки аля AppConsole.
Не пытайте сильно.


Leonid Troyanovsky ©   (06.01.19 11:09[11]


> dmk ©   (06.01.19 10:34) [10]

> MakeObjectInstance - это для VCL. У меня WinApi.

Скопируй себе реализацию из classes, там от силы  несколько десятков строк.

Не знаю, правда, поправили ли они FreeObjectInstance, там была утечка из-за
отсутствия VirtualFree.

> class var Wnds: TList<TWindow64

Можно по-разному.
Можно ссылку на объект хранить в пропертях  или юзердате окна.

Но, аккуратней всего, IMHO,  MakeObjectInstance.

--
Regards, LVT.


dmk ©   (06.01.19 12:01[12]

>поправили ли они FreeObjectInstance
Там адрес в список скидывается. Потом махом освобождается.
Типа сборщика мусора (InstFreeList).

Спасибо!


Leonid Troyanovsky ©   (06.01.19 12:28[13]


> dmk ©   (06.01.19 12:01) [12]

> Типа сборщика мусора (InstFreeList).

InstFreeList там был такой указатель:

procedure FreeObjectInstance(ObjectInstance: Pointer);
begin
 if ObjectInstance <> nil then
 begin
   PObjectInstance(ObjectInstance)^.Next := InstFreeList;
   InstFreeList := ObjectInstance;
 end;
end;

А VirtualFree для того, что было выделено Block := VirtualAlloc(..) - нет.

Ну, для экзешника или для статической линковки длл оно некритично.

--
Regards, LVT.


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

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

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







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


Наверх

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