Сейчас на форуме: 2nd, morgot, Rio, CDK123, zds, tyns777, tihiy_grom (+5 невидимых)

 eXeL@B —› Программирование —› GetMessage. Отрисовка окна.
Посл.ответ Сообщение


Ранг: 156.2 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 05 января 2009 01:08 · Поправил: Mavlyudov
· Личное сообщение · #1

Столкнулся с такой проблемой.
Как-то заметил, что откомпилированная программа
жрет много памяти. Зашел в процессы (у меня через TaskInfo)
и вот, что увидел на закладке Thread:

Thread Stack::
Symbol:
user32 ! PeekMessageA() + 0xa5
a + 16A3
a + 16F6
a + 2466

По разным адресам(или смещениям? например 0xa5,0x95,..) все время
появляется и исчезает PeekMessageA и еще какая-то процедура.
причем загрузка процессора до 80%.

Посмотрел, например, для блокнота. Там(в стеке) висит TranslateMEssage.
И не меняется.
Программа, которую компилирую, использует модуль WinCrt.
В этом модуле прорисовка окна происходит как-то не совсем понятно.
Всем изветно, что создавать окно нужно примено так(последовательность):

Заполнение структуры WinClass (типа TWndClass);

RegisterClass(WinClass);

Handle := CreateWindowEx(0, 'Class', 'Form',
WS_OVERLAPPEDWINDOW or
WS_VISIBLE, ....);

while(GetMessage(Msg, Handle, 0, 0)) do
begin
TranslateMessage(Msg); //прием сообщений
DispatchMessage(Msg); //удаление сообщений из очереди
end;

Но в модуле WinCrt это сделано иначе(см. листинг1). Там создание окна происходит
в отдельной процедуре InitWinCrt, а обработка сообщений в другой процедуре (KeyPressed).
Причем не через GetMessage, а через PeekMessage. Поэтому-о я и думаю, что PeekMessage,
который вск время воявляется в стеке в диспетчере процессов это и есть тот, что
крутится в цикле в процедуре ReadKey.


Далее я создаю программу (листинг2). И в этой программе мне нужно сделать, чтобы
программа ожидала от пользователя нажатие клавиши, что я и делаю(CH:=READKEY;).

Но при запуске, сразу видно, чо загрузка процессора очень большая.
Вот теперь и возникает вопрос: можно ли как-то оптимизировать программу
(точнее модуль wincrt) так, чтобы использовать минимум ресурсов и не загружать
так сильно процессор? Возможно(как один из вариантов) даже использовать
вместо readkey что-то другое(альтернативную процедуру), только я не знаю что.
бУду рад советам. Модуль и программу прикрепляю.

Code:
  1. <b>Листинг1</b>
  2. var
  3. CrtWindow: HWnd;
  4. .......
  5. procedure InitWinCrt;
  6. begin
  7. ...
  8.  CrtWindow := CreateWindow(....);
  9.  ShowWindow(CrtWindow, CmdShow);
  10.  UpdateWindow(CrtWindow);
  11. end;
  12. function KeyPressed: Boolean;
  13. var
  14.   M: TMsg;
  15. begin
  16.   InitWinCrt;
  17.   while PeekMessage(M, 0, 0, 0 ,pm_Remove) do
  18.   begin
  19.     if M.Message = wm_Quit then Terminate;
  20.     TranslateMessage(M);
  21.     DispatchMessage(M);
  22.   end;
  23.   KeyPressed := KeyCount > 0;
  24. end;
  25. function ReadKey: Char;
  26. begin
  27.   TrackCursor;
  28.   if not KeyPressed then
  29.   begin
  30.     Reading := True;
  31.     if Focused then ShowCursor;
  32.     repeat until KeyPressed;
  33.     if Focused then HideCursor;
  34.     Reading := False;
  35.   end;
  36.   ReadKey := KeyBuffer[0];
  37.   Dec(KeyCount);
  38.   Move(KeyBuffer[1], KeyBuffer[0], KeyCount);
  39. end;


Code:
  1. <b>Листинг2</b>
  2. uses wincrt;
  3. VAR
  4. CH:CHAR;
  5. BEGIN
  6. INITWINCRT;
  7. CH:=READKEY;
  8. DONEWINCRT;
  9. END.




Ранг: 203.3 (наставник)
Активность: 0.220
Статус: Участник
UPX Killer -d

Создано: 05 января 2009 13:32 · Поправил: AlexZ
· Личное сообщение · #2

Или я не понимаю новых технологий, или листинг 1 - чушь.

Строка 20 - при каждом обращении к KeyPressed вызывается InitWinCrt.

Потом, происходит постоянная дрючка PeekMessage, вот её описание:
function PeekMessage(var Msg: TMsg; Wnd: HWnd; MsgFilterMin, MsgFilterMax: Word): Bool;

Пpовеpяет очеpедь пpикладной задачи на сообщение и копиpует его в Msg. Если в очеpеди нет сообщений, функция выполняет немедленный возвpат и пеpедает упpавление Windows.

Параметры:
Msg: Пpинимающая стpуктуpа TMsg.
Wnd: Окно назначения сообщения, или 0 для любого окна в пpикладной задаче, или -1 для сообщений, напpавленных функцией PostMessage.
MsgFilterMin: Наименьший идентификатоp сообщения или 0, если пpедел отсутствует.
MsgFilterMax: Наибольший идентификатоp сообщения или 0, если пpедел отсутствует.
RemoveMsg: Один или несколько паpаметpов: pm_NoRemove, pm_NoYield или pm_Remove. См. pаздел "Паpаметpы сообщений, pm_" в главе 1.

Возвpащаемое значение:
Не нуль, если сообщение имеется; 0 - если нет.

См. также: GetMessage, WaitMessage



Функцией ReadKey вы снова продрючиваете весь клубок хитрозадых вызовов... Ну кто же так пишет?

-----
Я медленно снимаю с неё UPX... *FF_User*




Ранг: 203.3 (наставник)
Активность: 0.220
Статус: Участник
UPX Killer -d

Создано: 05 января 2009 13:42
· Личное сообщение · #3

Можно поставить где-нибудь в функции READKEY задержку по Sleep(1) - юзер не заметит тормозов, а сообщения из очереди никуда не денутся.

-----
Я медленно снимаю с неё UPX... *FF_User*





Ранг: 156.2 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 05 января 2009 18:04 · Поправил: Mavlyudov
· Личное сообщение · #4

AlexZ пишет:
Или я не понимаю новых технологий, или листинг 1 - чушь.

Исходниу WinCrt.pas щел вместе с Borland Pascal или TPW - не помню точно

Пробовал откомпилировать на делфи(смысла нет, но все же), компилирует, но не работает программа.
Думаю, нужно как-то разобраться с отрисовкой окна.
А также как-то переделать процедуру READKEY, потому что мне в моей программе эта процедура нужна.
Программа должна ожидать от пользователя нажатия клавиш все время.

В архиве a.exe и исходники (a.PAS, wincrt.PAS)

ce52_05.01.2009_CRACKLAB.rU.tgz - CRT.rar




Ранг: 156.2 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 11 марта 2009 22:22
· Личное сообщение · #5

AlexZ
Вот, ты был прав по поводу Sleep(1). Вот, куда я вставил:

Code:
  1. function ReadKey: Char;
  2. begin 
  3.   TrackCursor;
  4.   if not KeyPressed then 
  5.   begin 
  6.     Reading := True;
  7.     if Focused then ShowCursor;
  8.     repeat 
  9. SLEEP(1);
  10.     until KeyPressed;
  11.     if Focused then HideCursor;
  12.     Reading := False;
  13.   end;
  14.   ReadKey := KeyBuffer[0];
  15.   Dec(KeyCount);
  16.   Move(KeyBuffer[1], KeyBuffer[0], KeyCount);
  17. end;


Хм..Получается, что "приостанавливает выполнение текущей нити" на 1 мс.
Но все-таки заметны задержки. Например, при масштабировании или повороте изображения в программе, задержка чувствуется.
Может быть можно добиться лучшего результата какой-то другой функцией?
Думаю, что функция MsgWaitForMultipleObjects особо ничего нового не даст по сравнению со sleep.



Ранг: 116.5 (ветеран), 3thx
Активность: 0.070
Статус: Участник

Создано: 11 марта 2009 22:47 · Поправил: Valemox
· Личное сообщение · #6

Mavlyudov пишет:
Думаю, что функция MsgWaitForMultipleObjects особо ничего нового не даст по сравнению со sleep.

Думаю, что здесь ты всеж не прав, т.к. MsgWaitForMultipleObjects, способна "просыпаться", когда в очереди потока появляется новое сообщение и это значительнее луче, чем убогий Sleep.
вличко




Ранг: 156.2 (ветеран), 2thx
Активность: 0.090
Статус: Участник

Создано: 12 марта 2009 00:27 · Поправил: Mavlyudov
· Личное сообщение · #7

Valemox
Т.к. без sleep прога загружает процессор всё время, то логично предположить, что сообщения приходят в очередь постоянно. Подскажи, как правильно заюзать MsgWaitForMultipleObjects, чтобы не обломаться.


 eXeL@B —› Программирование —› GetMessage. Отрисовка окна.
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати