Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.10.03;
Скачать: [xml.tar.bz2];

Вниз

Почему умирает иконка в трее?   Найти похожие ветки 

 
guest_Dmitry   (2004-09-08 19:21) [0]

Программа читает данные из COM порта. После считывания выполняет ряд запросов к базе данных и возвращается в ожидание. В результате иконка в трее перестает реагировать на попытки открыть меню. В чем может быть причина этого? Использую RxTrayIcon.


 
DiamondShark ©   (2004-09-08 21:32) [1]

Потому что сообщения от иконки обрабатывает окно программы. А программа однопоточная.


 
guest_Dmitry   (2004-09-09 05:54) [2]

Расскажите в двух словах как поправить это. Такая же программа, только выполняющая после чтения немного другие функции работает на ура.


 
sniknik ©   (2004-09-09 09:04) [3]

> Расскажите в двух словах как поправить это.
сделать 2 потока. (извини в 2-а слова не вложился, но почти...)

или прерывать твой бесконечный цикл (гдето есть такой) время от времени обработчиком событий (Application.ProcessMessages куда нужно вставить)


 
guest_Dmitry   (2004-09-10 11:52) [4]

Попробовал вставить Application.ProcessMessages - не помогает.

В процедуре  после чтения штрих кода у меня печатается несколько печатных форм FastReport. Убираешь печать - все работает нормально. Попробовал создать второй поток, который после выполнения процедуры убивался. Эффект умирания иконки ушел, но при попытке закрытия приложения получаю - "неверный дескриптор окна".


 
guest_Dmitry   (2004-09-14 16:27) [5]

Может у кого-то все-таки есть соображения по этому вопросу? Неверный дескриптор окна получаю когда при закрытии формы уничтожаются компоненты на ней, к этому времени frReport уже оказывается разрушенным...


 
Digitman ©   (2004-09-14 16:55) [6]


> Неверный дескриптор окна получаю когда при закрытии формы
> уничтожаются компоненты на ней, к этому времени frReport
> уже оказывается разрушенным


о боже ... каша какая-то ... формы, дескрипторы, рипорты какие-то ...

ты пойми, что для каждого трэда есть kernel-time и есть user-time

реакция на вин-сообщения требует kernel-time, и если некий тред в некий момент времени находится в user-time, то он (трэд) все это время никак не в состоянии реагировать на GUI-события/сообщения !


 
guest_Dmitry   (2004-09-14 17:14) [7]

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


 
guest_Dmitry   (2004-09-14 18:26) [8]

Вот полностью работающий код. За основу был взят код из статьи с этого сайта "Работа с 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("&#196;&#224;&#237;&#237;&#238;&#227;&#238; &#228;&#238;&#234;&#243;&#236;&#229;&#237;&#242;&#224; &#237;&#229;&#242; &#226; &#225;&#224;&#231;&#229; &#228;&#224;&#237;&#237;&#251;&#245;");
       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("&#205;&#229;&#242; &#239;&#229;&#240;&#226;&#238;&#233; &#238;&#242;&#236;&#229;&#242;&#234;&#232; &#237;&#224; &#228;&#238;&#234;&#243;&#236;&#229;&#237;&#242;&#229;");
      if Form1.pFIBQuery1.FieldByName["marks"].AsInteger = 2 then
       ShowMessage("&#206;&#242;&#236;&#229;&#242;&#234;&#224; &#237;&#224; &#228;&#238;&#234;&#243;&#236;&#229;&#237;&#242; &#243;&#230;&#229; &#239;&#238;&#241;&#242;&#224;&#226;&#235;&#229;&#237;&#224;");
       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;

начинаются проблемы.


 
simpson ©   (2004-09-14 18:33) [9]

> guest_Dmitry   (14.09.04 18:26) [8]
> За основу был взят код из статьи с этого сайта "Работа с COM
> портами под Windows"

Не читай ее. Это - малограмотный бред сивой кобылы.


 
guest_Dmitry   (2004-09-14 18:37) [10]

>simpson ©   (14.09.04 18:33) [9]

я же говорю "за основу".
почитал еще статьи, подправил немного - работает вроде без глюков.

хотелось бы по сабжу...


 
simpson ©   (2004-09-14 18:41) [11]

ага... особенно вот это:


procedure KillComm;
begin
TerminateThread(CommThread,0);
CloseHandle(CommHandle);
end;


это:

WaitCommEvent(CommHandle,TransMask,nil);

и это:


ShowMessage("&#194; &#234;&#238;&#228;&#229; &#228;&#238;&#235;&#230;&#229;&#237; &#241;&#238;&#228;&#229;&#240;&#230;&#224;&#242;&#252;&#241;&#255; ID &#228;&#238;&#234;&#243;&#236;&#229;&#237;&#242;&#224;");


Уж как минимум, эти "ляпы" делают этот код не нормальным...


 
simpson ©   (2004-09-14 18:44) [12]

Тут сегодня уже объясняли одному товарищу, почему нельзя вызывать ShowMessage из другого потока просто так.

Сходи сюда:
http://delphimaster.net/view/1-1095161831/


 
guest_Dmitry   (2004-09-14 18:49) [13]

ShowMessage то я уберу, проблема то от этого не решится....


 
simpson ©   (2004-09-14 18:57) [14]

Уважаемый, цитирую Вас: "Вот полностью работающий код".
Отвечаю: ложь. Он не работающий. В нем море ошибок. Я не просто обращаю внимание на вызов ShowMessage: SetMark так же вызывается из дополнительного потока. В нем тоже есть вызовы ShowMessage. И вызов Form1.frReport1.PrepareReport.

Та вот, эти вызовы потоконебезопасны. Прочитайте про это понятие в справке - и решите проблему. Примите за аксиому: нельзя из дополнительного потока просто так обращаться к визуальным компонентам VCL.

Кроме того, код работающий с COM-портом - мягко говоря, некорректный.


 
guest_Dmitry   (2004-09-14 19:06) [15]

Каким образом тогда обращаться к визуальным компонентам, если это все-таки необходимо?


 
simpson ©   (2004-09-14 19:08) [16]

Например, использовать класс TThread - у него есть метод Synchronize, с помощью которого можно производить такие действия. Еще вариант - посылать сообщения окну через PostMessage.


 
simpson ©   (2004-09-14 19:12) [17]

Кстати, если слова про "код работающий с 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.



 
guest_Dmitry   (2004-09-14 19:18) [18]

Т.е. я так понял создавать еще однин поток и все действия производить в TMyThread.Execute? Пробовал я делать и так, прочитав [3]. В результате при закрытии главной формы приложения получаю "Неверный дескриптор окна" - вызывается метод destroy уже разрушеного компонента frreport.


 
simpson ©   (2004-09-14 19:22) [19]

> guest_Dmitry   (14.09.04 19:18) [18]
> Пробовал я делать и так, прочитав [3]

Э... т. е. добавил вызов "Application.ProcessMessages" в теле метода Execute? А нафига?

Не, срочно читаем Рихтера.


 
guest_Dmitry   (2004-09-14 19:29) [20]

Почему? В TMyThread.Execute поместил код из процедуры SetMark
и вместо ее вызова использовал

 thread := TMyThread.Create(false);


 
simpson ©   (2004-09-14 19:34) [21]

Хм...  сдается, что понимание смысла использования дополнительных поток отсутствует...

Общий алгоритм:

1. Создаещь потомка TThread (это обертка вокруг thread, с которым в твоем примере ты работешь с пом. API-функций).
2. В его Execute (это - собственно поток) ожидаешь данные из порта.
3. Как только данные пришли, вызываешь Synchronize, которому передаешь указатель на метод, в котором, в свою очередь, делаешь все, что тебе надо с визуальщиной.
Двух потоков не создавать не надо.


 
simpson ©   (2004-09-14 19:37) [22]

> simpson ©   (14.09.04 19:34) [21]
> использования дополнительных поток отсутствует

дополнительных потоков


 
guest_Dmitry   (2004-09-14 19:44) [23]

Вроде более-менее понятно... Буду пробовать.
Если статья на этом сайте по работе с com портами некорректна, что можно прочитать по данному вопросу? вот еще нашел статью, в ней вроде описанных ляпов не обнаружено -
http://z-oleg.com/delphi/hardw5.htm


 
guest_Dmitry   (2004-09-15 13:46) [24]

>simpson ©   (14.09.04 19:34) [21]

Спасибо! Разобрался, все заработало.



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

Форум: "Основная";
Текущий архив: 2004.10.03;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.54 MB
Время: 3.851 c
14-1095229918
Holy
2004-09-15 10:31
2004.10.03
Сколько мы спим?


14-1095312521
professor
2004-09-16 09:28
2004.10.03
Перебор паролей - это взлом?


1-1095222353
ККВ
2004-09-15 08:25
2004.10.03
Деньги


14-1095092172
}|{yk
2004-09-13 20:16
2004.10.03
Сабо обозвал Интернет "сборищем бомжей с Бессарабки"


1-1095244178
Ms.Dunkul
2004-09-15 14:29
2004.10.03
таскание формы 2





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский