![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Почему умирает иконка в трее?
guest_Dmitry © (2004-09-08 19:21:00)Программа читает данные из COM порта. После считывания выполняет ряд запросов к базе данных и возвращается в ожидание. В результате иконка в трее перестает реагировать на попытки открыть меню. В чем может быть причина этого? Использую RxTrayIcon.
guest_Dmitry (2004-09-15 13:46:00) [1]>simpson © (14.09.04 19:34) [21]
Спасибо! Разобрался, все заработало.
guest_Dmitry (2004-09-14 19:44:00) [2]Вроде более-менее понятно... Буду пробовать.
Если статья на этом сайте по работе с com портами некорректна, что можно прочитать по данному вопросу? вот еще нашел статью, в ней вроде описанных ляпов не обнаружено -
http://z-oleg.com/delphi/hardw5.htm
simpson (2004-09-14 19:37:00) [3]> simpson © (14.09.04 19:34) [21]
> использования дополнительных поток отсутствует
дополнительных потоков
simpson (2004-09-14 19:34:00) [4]Хм... сдается, что понимание смысла использования дополнительных поток отсутствует...
Общий алгоритм:
1. Создаещь потомка TThread (это обертка вокруг thread, с которым в твоем примере ты работешь с пом. API-функций).
2. В его Execute (это - собственно поток) ожидаешь данные из порта.
3. Как только данные пришли, вызываешь Synchronize, которому передаешь указатель на метод, в котором, в свою очередь, делаешь все, что тебе надо с визуальщиной.
Двух потоков не создавать не надо.
guest_Dmitry (2004-09-14 19:29:00) [5]Почему? В TMyThread.Execute поместил код из процедуры SetMark
и вместо ее вызова использовал
thread := TMyThread.Create(false);
simpson (2004-09-14 19:22:00) [6]> guest_Dmitry (14.09.04 19:18) [18]
> Пробовал я делать и так, прочитав [3]
Э... т. е. добавил вызов "Application.ProcessMessages" в теле метода Execute? А нафига?
Не, срочно читаем Рихтера.
guest_Dmitry (2004-09-14 19:18:00) [7]Т.е. я так понял создавать еще однин поток и все действия производить в TMyThread.Execute? Пробовал я делать и так, прочитав [3]. В результате при закрытии главной формы приложения получаю "Неверный дескриптор окна" - вызывается метод destroy уже разрушеного компонента frreport.
simpson (2004-09-14 19:12:00) [8]Кстати, если слова про "код работающий с COM-портом - мягко говоря, некорректный" не вдохновляют, в качестве примера приведу цитату из самого правильного сборника статей по программированию для Windows - MSDN:
TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
If the target thread owns a critical section, the critical section will not be released.
If the target thread is allocating memory from the heap, the heap lock will not be released.
If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
simpson (2004-09-14 19:08:00) [9]Например, использовать класс TThread - у него есть метод Synchronize, с помощью которого можно производить такие действия. Еще вариант - посылать сообщения окну через PostMessage.
guest_Dmitry (2004-09-14 19:06:00) [10]Каким образом тогда обращаться к визуальным компонентам, если это все-таки необходимо?
simpson (2004-09-14 18:57:00) [11]Уважаемый, цитирую Вас: "Вот полностью работающий код".
Отвечаю: ложь. Он не работающий. В нем море ошибок. Я не просто обращаю внимание на вызов ShowMessage: SetMark так же вызывается из дополнительного потока. В нем тоже есть вызовы ShowMessage. И вызов Form1.frReport1.PrepareReport.
Та вот, эти вызовы потоконебезопасны. Прочитайте про это понятие в справке - и решите проблему. Примите за аксиому: нельзя из дополнительного потока просто так обращаться к визуальным компонентам VCL.
Кроме того, код работающий с COM-портом - мягко говоря, некорректный.
guest_Dmitry (2004-09-14 18:49:00) [12]ShowMessage то я уберу, проблема то от этого не решится....
simpson (2004-09-14 18:44:00) [13]Тут сегодня уже объясняли одному товарищу, почему нельзя вызывать ShowMessage из другого потока просто так.
Сходи сюда:
http://www.delphimaster.ru/cgi-bin/forum.pl?id=1095161831&n=0
simpson (2004-09-14 18:41:00) [14]ага... особенно вот это:
procedure KillComm;
begin
TerminateThread(CommThread,0);
CloseHandle(CommHandle);
end;
это:
WaitCommEvent(CommHandle,TransMask,nil);
и это:
ShowMessage('Â êîäå äîëæåí ñîäåðæàòüñÿ ID äîêóìåíòà');
Уж как минимум, эти "ляпы" делают этот код не нормальным...
guest_Dmitry (2004-09-14 18:37:00) [15]>simpson © (14.09.04 18:33) [9]
я же говорю "за основу".
почитал еще статьи, подправил немного - работает вроде без глюков.
хотелось бы по сабжу...
simpson (2004-09-14 18:33:00) [16]> guest_Dmitry (14.09.04 18:26) [8]
> За основу был взят код из статьи с этого сайта "Работа с COM
> портами под Windows"
Не читай ее. Это - малограмотный бред сивой кобылы.
guest_Dmitry (2004-09-14 18:26:00) [17]Вот полностью работающий код. За основу был взят код из статьи с этого сайта "Работа с COM портами под Windows"
unit PortUnit;
interface
uses windows, sysutils, dialogs, forms, Messages, classes;
var
CommHandle : integer;
DCB : TDCB;
Ovr : TOverlapped;
Stat : TComStat;
CommThread : THandle;
hEvent : THandle;
Flag,StopResive : boolean;
KolByte,Kols,Mask,TransMask,Errs : DWord;
doc_id: integer;
s: string;
procedure PortInit;
procedure ReadComm;
procedure KillComm;
procedure SetMark;
procedure mybeep(Tone: Word; Delay: Integer);
implementation
uses
Main, StdCtrls, uDM;
procedure KillComm;
begin
TerminateThread(CommThread,0);
CloseHandle(CommHandle);
end;
procedure ReadComm;
var thread: TSimpleThread;
begin
while true do
begin
TransMask:=0;
WaitCommEvent(CommHandle,TransMask,nil);
if (TransMask and EV_RXFLAG)=EV_RXFLAG then
begin
s := '';
ClearCommError(CommHandle,Errs,@Stat);
Kols := Stat.cbInQue;
SetLength(s, kols);
ReadFile(CommHandle,s[1],Kols,Kols,@ovr);
PurgeComm(CommHandle, PURGE_RXCLEAR);
s := string(s);
s := trim(s);
try
doc_id := StrToInt(s);
SetMark;
except
ShowMessage('Â êîäå äîëæåí ñîäåðæàòüñÿ ID äîêóìåíòà');
end;
end;
end;
end;
procedure PortInit;
var
ThreadID:dword;
begin
doc_id := 0;
CommHandle := CreateFile(pchar(Form1.Edit2.Text),GENERIC_READ or GENERIC_WRITE,0,nil,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,0);
SetCommMask(CommHandle,EV_RXFLAG);
GetCommState(CommHandle,DCB);
DCB.BaudRate:=CBR_9600;
DCB.Parity:=NOPARITY;
DCB.ByteSize:=8;
DCB.StopBits:=OneStopBit;
DCB.EvtChar:=chr(13);
SetCommState(CommHandle,DCB);
CommThread := CreateThread(nil,0,@ReadComm,nil,0,ThreadID);
end;
procedure SetMark;
begin
Form1.pFIBQuery1.Close;
Form1.pFIBQuery1.SQL.Text := 'select id from documents where rowcount > 0 and id ='+IntToStr(doc_id);
Form1.pFIBQuery1.ExecQuery;
if Form1.pFIBQuery1.FieldByName['id'].AsInteger doc_id
then begin
ShowMessage('Äàííîãî äîêóìåíòà íåò â áàçå äàííûõ');
doc_id := 0;
Form1.pFIBQuery1.Close;
exit;
end;
Form1.pFIBQuery1.Close;
Form1.pFIBQuery1.SQL.Text := 'select z(mark0)+z(mark3) as marks from documents where id ='+IntToStr(doc_id);
Form1.pFIBQuery1.ExecQuery;
if Form1.pFIBQuery1.FieldByName['marks'].AsInteger 1
then begin
if Form1.pFIBQuery1.FieldByName['marks'].AsInteger = 0 then
ShowMessage('Íåò ïåðâîé îòìåòêè íà äîêóìåíòå');
if Form1.pFIBQuery1.FieldByName['marks'].AsInteger = 2 then
ShowMessage('Îòìåòêà íà äîêóìåíò óæå ïîñòàâëåíà');
doc_id := 0;
Form1.pFIBQuery1.Close;
exit;
end;
Form1.pFIBQuery1.Close;
Form1.pFIBQuery1.SQL.Text := 'update v_docmarks set mark3 = 1 where id ='+IntToStr(doc_id);
Form1.pFIBQuery1.ExecQuery;
Form1.pFIBTransaction1.CommitRetaining;
Form1.pFIBQuery1.Close;
doc_id := 0;
end;
end.
Только в процедуру SetMark добавляешь
Form1.frReport1.LoadFromFile(Form1.Edit3.Text+Form1.pFIBQuery1.FieldByName['frf'].AsString);
Form1.frReport1.PrepareReport;
начинаются проблемы.
guest_Dmitry (2004-09-14 17:14:00) [18]гм... в треде идет ожидание данных из порта. в это время форма прекрасно реагирует на вин-сообщения (я так понимаю на то тред и нужен). после получения данных выполняется ряд запросов к базе данных - все отрабатывает без проблем. возвращаюсь к ожиданию, все вин-сообщения ловятся. только начинаю работать с репортом - начинаются проблемы.
Digitman (2004-09-14 16:55:00) [19]
> Неверный дескриптор окна получаю когда при закрытии формы
> уничтожаются компоненты на ней, к этому времени frReport
> уже оказывается разрушенным
о боже ... каша какая-то ... формы, дескрипторы, рипорты какие-то ...
ты пойми, что для каждого трэда есть kernel-time и есть user-time
реакция на вин-сообщения требует kernel-time, и если некий тред в некий момент времени находится в user-time, то он (трэд) все это время никак не в состоянии реагировать на GUI-события/сообщения !
guest_Dmitry (2004-09-14 16:27:00) [20]Может у кого-то все-таки есть соображения по этому вопросу? Неверный дескриптор окна получаю когда при закрытии формы уничтожаются компоненты на ней, к этому времени frReport уже оказывается разрушенным...