Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.03.11;
Скачать: CL | DM;

Вниз

ProcessMessages   Найти похожие ветки 

 
dmirror   (2006-10-31 14:08) [0]

В чистом приложении вызов Application.processmessages работает.
Создаю поток

type
TServiceThread = class(TThread)
 public
   procedure Execute; override;
 end;
---
var
 ServiceThread: TServiceThread;

и на processmessages компилятор начинает ругаться что не видит такой функции.

что может быть и как исправить?


 
Eraser ©   (2006-10-31 14:13) [1]

> [0] dmirror   (31.10.06 14:08)


> и на processmessages компилятор начинает ругаться что не
> видит такой функции.

код показываей, где ругается.

ЗЫ
 не вздумай вызывать processmessages из доп. потока.


 
Сергей М. ©   (2006-10-31 14:14) [2]

processmessages - это не функция, а процедурный метод объекта класса TApplication.


 
YuRock ©   (2006-10-31 15:55) [3]


> Eraser ©   (31.10.06 14:13) [1]
>
> ЗЫ
>  не вздумай вызывать processmessages из доп. потока.
>


Почему?


 
Ketmar ©   (2006-10-31 16:02) [4]

>[3] YuRock(c) 31-Oct-2006, 15:55
>Почему?
поверь на слово пока. ибо это с 1917 года надо про шпингалеты пояснять.


 
YuRock ©   (2006-10-31 16:05) [5]


> поверь на слово пока. ибо это с 1917 года надо про шпингалеты
> пояснять.


Хорошо. Я тогда тоже дам совет. Не пользуйся никогда компонентом TButton. Почему? Поверь на слово - я знаю, почему...


 
Ketmar ©   (2006-10-31 16:10) [6]

>[5] YuRock(c) 31-Oct-2006, 16:05
ещё один надмозг. сезон, что ли? игнор.


 
Eraser ©   (2006-10-31 16:13) [7]

> [3] YuRock ©   (31.10.06 15:55)


> Почему?

Зачем?
Зачем понадобилось вызывать ProcessMessages в доп. потоке?

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


 
Сергей М. ©   (2006-10-31 16:17) [8]


> YuRock ©   (31.10.06 15:55) [3]



> Почему?


Дурацкий вопрос.

Ну, если желаешь ответ на него, то хотя бы потому что поле TApplication.FTerminate не защищено крит.секцией. И при этом нет никаких гарантий, что потоку не послано WM_QUIT.

Смотреть и изучать исходники класса TApplication до полного просветления)


 
Игорь Шевченко ©   (2006-10-31 16:44) [9]

Eraser ©   (31.10.06 16:13) [7]


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


С этого момента подробнее - каким образом ProcessMessages вызыванный из неосновного потока позволяет перейти к обработке всей очереди сообщений основного потока приложения.


 
Eraser ©   (2006-10-31 16:47) [10]

> [9] Игорь Шевченко ©   (31.10.06 16:44)

в том то и дело что никаким.


 
YuRock ©   (2006-10-31 17:07) [11]

> Ketmar c   (31.10.06 16:10) [6]
> Eraser c   (31.10.06 16:13) [7]
> Сергей М. c   (31.10.06 16:17) [8]

Пасиба, олбанский выучил!

> dmirror   (31.10.06 14:08)

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

TApplication.ProcessMessages вполне допустимо для выкрутки сообщений любого потока. Ведь это простой цикл PeekMessage. Единственное, с чем может случиться заморочка - это со свойством OnMessage у TApplication. Если оно присвоено - то будет вызываться из того потока, откуда вызвано ProcessMessages. И тут уже все зависит от того, что за код там написан. Если этого свойства нет - проблем быть не может.

Другой вопрос - зачем вызывать ProcessMessages? Оно удобно для того, чтобы выкрутить накопившуюся очередь. Принудительно.
Но не предназначено для ожидания и выкрутки сообщений, тут надо использовать цикл GetMessage.

Ниже пример с использованием Application.ProcessMessages в другом потоке. Все работает великолепно - только
неправильно логически - "оно" для другого надо. И из-за этого 100% проца жрется. Да и далеко не все сообщения "оно" обрабатывает.
Так что если этот цикл закомментить и раскомментить следующий - будет намного лучше.


unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type
 TTestThread = class( TThread )
 protected
   procedure Execute; override;
 end;

 TForm1 = class(TForm)
   procedure FormCreate(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
 private
   FTread: TTestThread;
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

function TestThreadWndProc( hWindow: HWND; msg: Cardinal; wParam: WPARAM; lParam: LPARAM ): Integer; stdcall;
begin
 Result := DefWindowProc( hWindow, msg, wParam, lParam );
end;

procedure TTestThread.Execute;
var
 hWindow: HWND;
 Msg: TMSG;
begin
 hWindow := CreateWindow( "___TestThreadWndClass", "Îêíî èç äðóãîãî ïîòîêà ( Îáðàáàòûâàåòñ&# 255; Application.ProcessMessages )", WS_VISIBLE or WS_SIZEBOX or WS_SYSMENU or WS_MINIMIZEBOX or WS_MAXIMIZEBOX, 100, 100, 600, 200, 0, 0, hInstance, nil );

 while not Terminated do
   Application.ProcessMessages;

 {while not Terminated and GetMessage( Msg, 0, 0, 0 ) do begin
   TranslateMessage( Msg );
   DispatchMessage( Msg );
 end;}

 DestroyWindow( hWindow );
end;

procedure TForm1.FormCreate(Sender: TObject);
var
 wc: WNDCLASS;
begin
 FillChar( wc, sizeof( WNDCLASS ), 0 );
 wc.lpfnWndProc := @TestThreadWndProc;
 wc.hInstance := hInstance;
 wc.hCursor := LoadCursor( 0, IDC_ARROW );
 wc.lpszClassName := "___TestThreadWndClass";
 wc.hbrBackground := CreateSolidBrush( GetSysColor( COLOR_BTNFACE ) );
 Windows.RegisterClass( wc );

 FTread := TTestThread.Create( True );
 with FTread do begin
   FreeOnTerminate := True;
   Resume;
 end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 FTread.Terminate;
end;

end.


 
Eraser ©   (2006-10-31 17:17) [12]

> [11] YuRock ©   (31.10.06 17:07)


> Пасиба, олбанский выучил!

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

> Да и далеко не все сообщения "оно" обрабатывает.

это с каких пор?


 
YuRock ©   (2006-10-31 17:21) [13]

> Eraser ©   (31.10.06 17:17) [12]

1. Йа пастаянна учу, пасиба исчо рас! Да, приложения, написанные мной, работают месяцами, пока винда не сдохнет.

2. С тех пор, как борланд так реализовал этот метод. Как минимум с D6 - более старых версий у меня нет под рукой.


 
Игорь Шевченко ©   (2006-10-31 17:22) [14]

Eraser ©   (31.10.06 16:47) [10]


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



> в том то и дело что никаким.


Вот две твоих цитаты. Ты их связать можешь ? А то у меня не получается.


 
@!!ex ©   (2006-10-31 17:46) [15]

А я почемуто всегда думал, что ProcessMessages нужно для того чтобы прервать текущее действие основного потока и обработать мессаги....
Вопрос: зачем из стороннего потока вызывать обработку сообщений главного потока?
Ответ: Чтобы напороться на AV.


 
YuRock ©   (2006-10-31 17:48) [16]


> @!!ex ©   (31.10.06 17:46) [15]
> Вопрос: зачем из стороннего потока
> вызывать обработку сообщений главного потока?Ответ: Чтобы
> напороться на AV.


:))))))))))))))))))))))))))))))))))))))))))))))


 
Eraser ©   (2006-10-31 17:57) [17]

> [14] Игорь Шевченко ©   (31.10.06 17:22)

криво мысль изложил ) согласен.
надо было уточнить, что вызывать ProcessMessages следует из осн. потока.

> зачем из стороннего потока вызывать обработку сообщений
> главного потока?

именно это сделать нельзя. можно только если вызов обернуть в Synchronize.


 
YuRock ©   (2006-10-31 18:00) [18]

Я извиняюсь перед админами форума, просто нервы - ни к черту...
Через пару часов на стадион идти - Шахтер-Валенсия - и меня колбаси не по детски... Делать ничего не могу.

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

Так что еще раз прошу прощения и понимания. Кстати, надеюсь, какую-то пользу автору темы, к-рый задавал вопрос, я все же принес. Так что это смягчающее обстоятельство ;)


 
Игорь Шевченко ©   (2006-10-31 18:09) [19]

Eraser ©   (31.10.06 17:57) [17]


> надо было уточнить, что вызывать ProcessMessages следует
> из осн. потока.


Почему ?


 
Eraser ©   (2006-10-31 18:13) [20]

> [19] Игорь Шевченко ©   (31.10.06 18:09)

потому что borland не рекомендует вызывать методы VCL объектов из доп. потока.


 
YuRock ©   (2006-10-31 18:14) [21]

> Игорь Шевченко ©   (31.10.06 18:09) [19]
> Почему ?

Я уже задавал этот вопрос  - [3].
Поступило около 15 ответов - неужели Вам не достаточно? :)


 
@!!ex ©   (2006-10-31 18:16) [22]


> 1. Йа пастаянна учу, пасиба исчо рас! Да, приложения, написанные
> мной, работают месяцами, пока винда не сдохнет.


Винда дохнет из-за ваших приложений? ;)


> Игорь Шевченко ©   (31.10.06 18:09) [19]

Теоретически может привести к AB  в ОЧЕНЬ редких случаях как уже было сказано в > Сергей М. ©   (31.10.06 16:17) [8] .
Мьютекс на FTerminate...
ТОка это всего лишь один из вариантов, которые могут привести к AV.


 
Игорь Шевченко ©   (2006-10-31 18:21) [23]

Eraser ©   (31.10.06 18:13) [20]


> потому что borland не рекомендует вызывать методы VCL объектов
> из доп. потока.


Все методы всех объектов ?


 
Eraser ©   (2006-10-31 18:22) [24]

> [21] YuRock ©   (31.10.06 18:14)

вот код метода ProcessMessage, который вызывается в цикле из ProcessMessages.
function TApplication.ProcessMessage(var Msg: TMsg): Boolean;
var
 Unicode: Boolean;
 Handled: Boolean;
 MsgExists: Boolean;
begin
 Result := False;
 if PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE) then
 begin
   Unicode := (Msg.hwnd <> 0) and IsWindowUnicode(Msg.hwnd);
   if Unicode then
     MsgExists := PeekMessageW(Msg, 0, 0, 0, PM_REMOVE)
   else
     MsgExists := PeekMessage(Msg, 0, 0, 0, PM_REMOVE);
   if not MsgExists then Exit;
   Result := True;
   if Msg.Message <> WM_QUIT then
   begin
     Handled := False;
     if Assigned(FOnMessage) then FOnMessage(Msg, Handled); // может привести к серьезным проблемам,
                                                            // если этот обработчик расчитан для работы в осн. потоке.
     if not IsPreProcessMessage(Msg) and not IsHintMsg(Msg) and // есть подозрение, что эти методы тоже не потоко-безопасны.
       not Handled and not IsMDIMsg(Msg) and // тут вообще код лезет к объекту TScreen...
       not IsKeyMsg(Msg) and not IsDlgMsg(Msg) then
     begin
       TranslateMessage(Msg);
       if Unicode then
         DispatchMessageW(Msg)
       else
         DispatchMessage(Msg);
     end;
   end
   else
     FTerminate := True; // про это сказано в [8].
 end;
end;


 
Eraser ©   (2006-10-31 18:25) [25]

> [23] Игорь Шевченко ©   (31.10.06 18:21)

не всех конечно, но всех визуальных объектов. не визуальные, чаще всего (но не всегда) можно использовать не только в гл. потоке, но и в доп., но желательно только в том, где данный объект и был создан.


 
YuRock ©   (2006-10-31 18:37) [26]

> if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
> // может привести к серьезным проблемам,
> // если этот обработчик расчитан для работы в осн. потоке.

А может и не привести. Все зависит от того, что за код программист написал в OnMessage. И вообще - написал ли. Я этот момент упомянул в [11].

> // есть подозрение, что эти методы тоже не потоко-безопасны.

Они вполне безопасны. В них используются только элементарные функции WinApi - и нечего более.

> FTerminate := True; // про это сказано в [8].

Ну и что там сказано про это? Читаем: "поле TApplication.FTerminate не защищено крит.секцией. И при этом нет никаких гарантий, что потоку не послано WM_QUIT."

Что из этого? Ну послано - отлично! Присвоется эта переменная - так она и должна была присвоиться. НИЧЕГО страшного в этом нет.


 
Eraser ©   (2006-10-31 18:45) [27]

> [26] YuRock ©   (31.10.06 18:37)


> Они вполне безопасны. В них используются только элементарные
> функции WinApi - и нечего более.

уверен?
CancelHint к примеру? или ObjectFromHWnd? а в IsMDIMsg прямо вся состоит из вызова API? )


 
Eraser ©   (2006-10-31 18:52) [28]

> [26] YuRock ©   (31.10.06 18:37)


> Что из этого? Ну послано - отлично! Присвоется эта переменная
> - так она и должна была присвоиться. НИЧЕГО страшного в
> этом нет.

таки слона то мы все и не приметели )) как только доп. потоку будет послано WM_QUIT - приложение завершиться )


 
YuRock ©   (2006-10-31 19:02) [29]


> уверен?CancelHint к примеру? или ObjectFromHWnd? а в IsMDIMsg
> прямо вся состоит из вызова API? )


Уверен на 100%. К этой строке выполнение может дойти только тогда, когда в потоке созданы VCL-ные хинты. А в дополнительных потоках их создать и работать с ними если не невозможно, то довольно сложно, как и с любыми VCL-объектами.

А IsMDIMsg, да, состоит вся из вызова API.


> таки слона то мы все и не приметели )) как только доп. потоку
> будет послано WM_QUIT - приложение завершиться )


Да, должно завершиться. Ну и? А в чем еще смысл посылки WM_QUIT? Обычно для этого как раз...

P.S. Все, спасибо всем за положительные эмоции - пора выдвигаться на стадио :)


 
Eraser ©   (2006-10-31 19:17) [30]

> [29] YuRock ©   (31.10.06 19:02)


> А IsMDIMsg, да, состоит вся из вызова API.

и чтения свойств визуальных VCL объектов.
при завершении приложения, если доп. поток еще будет ативен, в этом месте AV обязательно вылетит.
function TApplication.IsMDIMsg(var Msg: TMsg): Boolean;
begin
 Result := False;
 if (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm) and
    (Screen.ActiveForm <> nil) and (Screen.ActiveForm.FormStyle = fsMDIChild) then
   Result := TranslateMDISysAccel(MainForm.ClientHandle, Msg);
end;


> Да, должно завершиться.

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

не слишкол ли много "если" надо учесть, чтобы код работал как надо?
по-моему
while not Terminated and GetMessage(Msg, 0, 0, 0) do begin
  TranslateMessage( Msg );
  DispatchMessage( Msg );
end;

гораздо проще и безопаснее.


 
@!!ex ©   (2006-10-31 20:46) [31]


> YuRock

ощущени, что вы с потоками не работали....
В курсе, что будет если к одной переменной одновременно обратяться из двух разных потоков?
Семафоры и мьютексы не просто так придумали.


 
Дмитрий Белькевич ©   (2006-11-01 02:44) [32]

Господа, вам в жизни проблем мало, что бы еще и на эти грабли наступать - в appllication.processmessage может случится многое - нажатия на кнопки, перерисовка итд. И коматоз обеспечен.


 
Игорь Шевченко ©   (2006-11-01 10:53) [33]

Eraser ©   (31.10.06 19:17) [30]


>  if (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)


property FormStyle: TFormStyle read FFormStyle

property ActiveForm: TForm read FActiveForm;

И чего ?


> при завершении приложения, если доп. поток еще будет ативен,
>  в этом месте AV обязательно вылетит.


Пример не затруднит ?


 
dmirror   (2006-11-01 11:58) [34]

ProcessMessagess запускается в основной программе а не в потоке, в потоке обслуживается генераторно-осцилографическая часть. А ProcessMessagess нужен для отслеживания событий системы позиционирования, просто без него не могу получить сигнал готовности.

Код слующий

procedure TForm1.ScanStartClick(Sender: TObject);
var
 i,j : integer;
 sx,sy,vx,vy : string;
 uclen, k,h  : integer;
 temp : real;

begin
 vx := Edit16.Text;
 vy := Edit17.Text;
 sx := Edit18.Text;
 sy := Edit19.Text;
 Stringcounter :=1;
 IsFastScan:=true;
 cRecBufSizeMaxF:=trunc(cSamplPS*StrToInt(sx)/StrToInt(vx));
 cRecBufSizeMaxFBin:=(cRecBufSizeMaxF - (cRecBufSizeMaxF mod 2))*2;

 for i:=1 to StrToInt(numlines.Text) do
   begin
     sleep(200);
     isReady :=false;

     cport.WriteStr("@0A 0,5000,"+sy+","+vy+#13#10);
     start;

     j:=0;

     repeat
     inc(j);
      application.ProcessMessages();
     until IsReady;{ or (j>=15);
     if (j>=15) then begin
      ShowMessage("Каретка не дошла до конца");
     end;           }

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A 0,5000,"+"-"+sy+","+vy+#13#10);
     repeat
       application.ProcessMessages();
     until isReady = true;

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A"+sx+","+vx+",0,5000"+#13#10);
     repeat
      stringcounter:=Stringcounter+1;
      application.ProcessMessages();
     until isReady;

   end;

 IsFastScan:=false;
end;

А ларчик открывался достаточно просто - нужно было убить библиотеку svcmgr. После чего ProcessMessages заработал. А вот первопричина не понятна, в чистом приложении без потоков даже с  svcmgr код работал

Всем спасибо!


 
dmirror   (2006-11-01 11:58) [35]

ProcessMessagess запускается в основной программе а не в потоке, в потоке обслуживается генераторно-осцилографическая часть. А ProcessMessagess нужен для отслеживания событий системы позиционирования, просто без него не могу получить сигнал готовности.

Код слующий

procedure TForm1.ScanStartClick(Sender: TObject);
var
 i,j : integer;
 sx,sy,vx,vy : string;
 uclen, k,h  : integer;
 temp : real;

begin
 vx := Edit16.Text;
 vy := Edit17.Text;
 sx := Edit18.Text;
 sy := Edit19.Text;
 Stringcounter :=1;
 IsFastScan:=true;
 cRecBufSizeMaxF:=trunc(cSamplPS*StrToInt(sx)/StrToInt(vx));
 cRecBufSizeMaxFBin:=(cRecBufSizeMaxF - (cRecBufSizeMaxF mod 2))*2;

 for i:=1 to StrToInt(numlines.Text) do
   begin
     sleep(200);
     isReady :=false;

     cport.WriteStr("@0A 0,5000,"+sy+","+vy+#13#10);
     start;

     j:=0;

     repeat
     inc(j);
      application.ProcessMessages();
     until IsReady;{ or (j>=15);
     if (j>=15) then begin
      ShowMessage("Каретка не дошла до конца");
     end;           }

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A 0,5000,"+"-"+sy+","+vy+#13#10);
     repeat
       application.ProcessMessages();
     until isReady = true;

     sleep(200);
     isReady :=false;
     Cport.WriteStr("@0A"+sx+","+vx+",0,5000"+#13#10);
     repeat
      stringcounter:=Stringcounter+1;
      application.ProcessMessages();
     until isReady;

   end;

 IsFastScan:=false;
end;

А ларчик открывался достаточно просто - нужно было убить библиотеку svcmgr. После чего ProcessMessages заработал. А вот первопричина не понятна, в чистом приложении без потоков даже с  svcmgr код работал

Всем спасибо!


 
Сергей М. ©   (2006-11-01 13:30) [36]


> нужно было убить библиотеку svcmgr


А как она у тебя оказалась в проекте обычного GUI-приложения ?


 
YuRock ©   (2006-11-01 15:17) [37]


> ощущени, что вы с потоками не работали....В курсе, что будет
> если к одной переменной одновременно обратяться из двух
> разных потоков?Семафоры и мьютексы не просто так придумали.
>


Да, знаю. В худшем случае - логические ошибки. Которые, конечно, могут повлечь за собой все, что угодно. А могут и не повлечь, как в случае с безобидным сравнение двух чисел:
 if (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)


 
Eraser ©   (2006-11-01 15:20) [38]

> [33] Игорь Шевченко ©   (01.11.06 10:53)

мда.. насчет AV в (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm) эт я погорячился, не учел тот факт, что форма не уничтожается, когда заканчивается Run. Но сути дела это не меняет. Я б не стал использовать методы TApplication для обработки сообщений в доп. потоке.


 
Anatoly Podgoretsky ©   (2006-11-01 15:23) [39]

> Eraser  (01.11.2006 15:20:38)  [38]

>  (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)

С потоками, я бы не назвал это код безобидным, легко получить как минимум AV
Это не атомарная операция.


 
Eraser ©   (2006-11-01 15:24) [40]

> [37] YuRock ©   (01.11.06 15:17)


> (MainForm <> nil) and (MainForm.FormStyle = fsMDIForm)

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



Страницы: 1 2 3 вся ветка

Текущий архив: 2007.03.11;
Скачать: CL | DM;

Наверх




Память: 0.6 MB
Время: 0.037 c
2-1170926380
astronom
2007-02-08 12:19
2007.03.11
Копирование директорий


15-1171639983
Parus
2007-02-16 18:33
2007.03.11
Мостостроительство:)


15-1171479416
Вольный Стрелок
2007-02-14 21:56
2007.03.11
Отключить отладчик в системе


15-1171307046
bmw0
2007-02-12 22:04
2007.03.11
Длинные числа


8-1147019307
Константинов
2006-05-07 20:28
2007.03.11
WaveOut