Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Почему умирает иконка в трее?


Страницы:   1 2

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 уже оказывается разрушенным...


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо