![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
ProcessMessages [D6, D7, NT4, WinXP]
dmirror © (2006-10-31 14:08:00)В чистом приложении вызов Application.processmessages работает.
Создаю поток
type
TServiceThread = class(TThread)
public
procedure Execute; override;
end;
---
var
ServiceThread: TServiceThread;
и на processmessages компилятор начинает ругаться что не видит такой функции.
что может быть и как исправить?
Eraser (2006-10-31 19:17:00) [61]> [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;
гораздо проще и безопаснее.
YuRock (2006-10-31 19:02:00) [62]
> уверен?CancelHint к примеру? или ObjectFromHWnd? а в IsMDIMsg
> прямо вся состоит из вызова API? )
Уверен на 100%. К этой строке выполнение может дойти только тогда, когда в потоке созданы VCL-ные хинты. А в дополнительных потоках их создать и работать с ними если не невозможно, то довольно сложно, как и с любыми VCL-объектами.
А IsMDIMsg, да, состоит вся из вызова API.
> таки слона то мы все и не приметели )) как только доп. потоку
> будет послано WM_QUIT - приложение завершиться )
Да, должно завершиться. Ну и? А в чем еще смысл посылки WM_QUIT? Обычно для этого как раз...
P.S. Все, спасибо всем за положительные эмоции - пора выдвигаться на стадио :)
Eraser (2006-10-31 18:52:00) [63]> [26] YuRock © (31.10.06 18:37)
> Что из этого? Ну послано - отлично! Присвоется эта переменная
> - так она и должна была присвоиться. НИЧЕГО страшного в
> этом нет.
таки слона то мы все и не приметели )) как только доп. потоку будет послано WM_QUIT - приложение завершиться )
Eraser (2006-10-31 18:45:00) [64]> [26] YuRock © (31.10.06 18:37)
> Они вполне безопасны. В них используются только элементарные
> функции WinApi - и нечего более.
уверен?
CancelHint к примеру? или ObjectFromHWnd? а в IsMDIMsg прямо вся состоит из вызова API? )
YuRock (2006-10-31 18:37:00) [65]> if Assigned(FOnMessage) then FOnMessage(Msg, Handled);
> // может привести к серьезным проблемам,
> // если этот обработчик расчитан для работы в осн. потоке.
А может и не привести. Все зависит от того, что за код программистнаписал в OnMessage. И вообще - написал ли. Я этот момент упомянул в [11].
> // есть подозрение, что эти методы тоже не потоко-безопасны.
Они вполне безопасны. В них используются только элементарные функции WinApi - и нечего более.
> FTerminate := True; // про это сказано в [8].
Ну и что там сказано про это? Читаем: "поле TApplication.FTerminate не защищено крит.секцией. И при этом нет никаких гарантий, что потоку не послано WM_QUIT."
Что из этого? Ну послано - отлично! Присвоется эта переменная - так она и должна была присвоиться. НИЧЕГОстрашного в этом нет.
Eraser (2006-10-31 18:25:00) [66]> [23] Игорь Шевченко © (31.10.06 18:21)
не всех конечно, но всех визуальных объектов. не визуальные, чаще всего (но не всегда) можно использовать не только в гл. потоке, но и в доп., но желательно только в том, где данный объект и был создан.
Eraser (2006-10-31 18:22:00) [67]> [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;
Игорь Шевченко (2006-10-31 18:21:00) [68]Eraser © (31.10.06 18:13) [20]
> потому что borland не рекомендует вызывать методы VCL объектов
> из доп. потока.
Все методы всех объектов ?
@!!ex (2006-10-31 18:16:00) [69]
> 1. Йа пастаянна учу, пасиба исчо рас! Да, приложения, написанные
> мной, работают месяцами, пока винда не сдохнет.
Винда дохнет из-за ваших приложений? ;)
> Игорь Шевченко © (31.10.06 18:09) [19]
Теоретически может привести к AB в ОЧЕНЬ редких случаях как уже было сказано в > Сергей М. © (31.10.06 16:17) [8] .
Мьютекс на FTerminate...
ТОка это всего лишь один из вариантов, которые могут привести к AV.
YuRock (2006-10-31 18:14:00) [70]> Игорь Шевченко © (31.10.06 18:09) [19]
> Почему ?
Я уже задавал этот вопрос - [3].
Поступило около 15 ответов - неужели Вам не достаточно? :)
Eraser (2006-10-31 18:13:00) [71]> [19] Игорь Шевченко © (31.10.06 18:09)
потому что borland не рекомендует вызывать методы VCL объектов из доп. потока.
Игорь Шевченко (2006-10-31 18:09:00) [72]Eraser © (31.10.06 17:57) [17]
> надо было уточнить, что вызывать ProcessMessages следует
> из осн. потока.
Почему ?
YuRock (2006-10-31 18:00:00) [73]Я извиняюсь перед админами форума, просто нервы - ни к черту...
Через пару часов на стадион идти - Шахтер-Валенсия - и меня колбаси не по детски... Делать ничего не могу.
Орешник уже перечитал полностью. Оценил :)
Но мало. А, как оказалось, обсуждения обычных вопросов, споры и советы специалистов тут не хуже орехов :)
Так что еще раз прошу прощения и понимания. Кстати, надеюсь, какую-то пользу автору темы, к-рый задавал вопрос, я все же принес. Так что это смягчающее обстоятельство ;)
Eraser (2006-10-31 17:57:00) [74]> [14] Игорь Шевченко © (31.10.06 17:22)
криво мысль изложил ) согласен.
надо было уточнить, что вызывать ProcessMessages следует из осн. потока.
> зачем из стороннего потока вызывать обработку сообщений
> главного потока?
именно это сделать нельзя. можно только если вызов обернуть в Synchronize.
YuRock (2006-10-31 17:48:00) [75]
> @!!ex © (31.10.06 17:46) [15]
> Вопрос: зачем из стороннего потока
> вызывать обработку сообщений главного потока?Ответ: Чтобы
> напороться на AV.
:))))))))))))))))))))))))))))))))))))))))))))))
@!!ex (2006-10-31 17:46:00) [76]А я почемуто всегда думал, что ProcessMessages нужно для того чтобы прервать текущее действие основного потока и обработать мессаги....
Вопрос: зачем из стороннего потока вызывать обработку сообщений главного потока?
Ответ: Чтобы напороться на AV.
Игорь Шевченко (2006-10-31 17:22:00) [77]Eraser © (31.10.06 16:47) [10]
> Нельзя вызывать, потому что ProcessMessages позволяет перейти
> к обработке всей очереди сообщений основного потока приложения,
> тем самым прервав выполнение кода в основном же потоке,
> до тех пор, пока метод ProcessMessages не выполнится.
> Если вызвать ProcessMessages из доп. потока, то программа
> или этот поток, в лучшем случае, скорее всего подвиснут.
>
> в том то и дело что никаким.
Вот две твоих цитаты. Ты их связать можешь ? А то у меня не получается.
YuRock (2006-10-31 17:21:00) [78]> Eraser © (31.10.06 17:17) [12]
1. Йа пастаянна учу, пасиба исчо рас! Да, приложения, написанные мной, работают месяцами, пока винда не сдохнет.
2. С тех пор, как борланд так реализовал этот метод. Как минимум с D6 - более старых версий у меня нет под рукой.
Eraser (2006-10-31 17:17:00) [79]> [11] YuRock © (31.10.06 17:07)
> Пасиба, олбанский выучил!
учи еще.
только потом не удивляйся, что приложение будет "вываливаться" с AV в самых неожиданных местах.
> Да и далеко не все сообщения "оно" обрабатывает.
это с каких пор?
YuRock (2006-10-31 17:07:00) [80]> 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.