По поводу ситуации №2.Снег Север писал(а):Мой хрустальный шар говорит, что самая вероятная причина - драйвер видеокарты на клиентском компе.
Тут видимо не одна, а несколько наслоившихся проблем.
И с видеокартой в том числе. Но проблема стала проявляться на компах с Win7, Win8, и не в виртуальном или терминальном режимае, на обычной ОС установленной на железо.
проявляется через продолжительное время работы, минут через 30-50.
olegy123 писал(а):Такие фокусы могут быть когда окно(любое приложения, написанное на любом языке) не обрабатывает сообщения о перерисовке окна, или не успевает обработать все сообщения. простой бесконечный цикл, или наоборот блокировка главного потока может приводить к таким фокусам с перерисовкой.
Есть подозрение на обработку сообщения от АТС по TCP
Эта программа (далее ПР) получает сообщение от службы которая считывает события с АТС и рассылает по экземплярам ПР на разных рабочих местах сообщение по TCP
Для этого используются компоненты Indy10
Вот код.
Я не знал как "отвязать" однопоточную IdTCPServer от основного интерфейса ПР
поэтому сделал через посылку сообщения программой самой себе.
- Код: Выделить всё
//Обработка сигнала по TCP от службы ATEx
procedure TFormCallCntr.IdTCPServerATExExecute(AContext: TIdContext);
var strMsg, Callid, pn, cmd:string; p:integer;
begin
//Принимаем от клиента строку
cmd:=''; Sleep(10);
strMsg := AContext.Connection.Socket.ReadLn;
//Обработка
p:=pos('|',strMsg);
if p<>0 then
begin
//разделение полученной строки на ID звонка и номер телефона
cmd:=LowerCase(copy(strMsg,1,p-1)); //CallID:=copy(strMsg,1,p-1);
strMsg:=copy(strMsg,p+1,length(strMsg)-p);
p:=pos('|',strMsg);
if p<>0 then
begin
CallID:=copy(strMsg,1,p-1);
pn:=copy(strMsg,p+1,length(strMsg)-p); if pn<>'???' then PhoneNum:=pn;
end
else PhoneNum:=strMsg;
PhoneNum:=formatNumPhone( PhoneNum );
Sleep(10);
if cmd='callin_start' then PostMessage(Handle, Msg_PhoneVisible, 0, 0);
if cmd='callin_connect' then PostMessage(Handle, Msg_PhoneVisible, 1, 0);
if cmd='callin_stop' then PostMessage(Handle, Msg_PhoneVisible, 2, 0);
if cmd='callout_start' then PostMessage(Handle, Msg_PhoneVisible, 3, 0);
if cmd='callout_connect' then PostMessage(Handle, Msg_PhoneVisible, 4, 0);
if cmd='callout_stop' then PostMessage(Handle, Msg_PhoneVisible, 5, 0);
Sleep(10);
end;
end;
Тут объявление процедуры, есть и другие процедуры обработки сообщений, но они практически не используются.
- Код: Выделить всё
const
MessExePrm1=WM_USER;
MessExePrm2=WM_USER+1;
Msg_PhoneVisible=WM_USER+3;
....
private
{ private declarations }
procedure PhoneVisibleExec(var Msg: TMessage); message Msg_PhoneVisible;
procedure RangeDateChange(Sender: TObject);
procedure WMACT(var mes:TWMACTIVATE); message WM_ACTIVATE;
public
{ public declarations }
procedure ReadMessExePrm1(var MessExePrm1:TMessage); message MessExePrm1;
procedure ReadMessExePrm2(var MessExePrm2:TMessage); message MessExePrm2;
end;
Обработка сообщения от IdTCPServer во всех случаях просто меняет видимость индикаторов на панели программы.
В одном случае запускает обработку номера телефона полученного от АТС - запись номера в фильтр и перевыборку цепочки Select-ов с DBGridEh на формах.
- Код: Выделить всё
//Переключение индикатора звонка телефона
procedure TFormCallCntr.PhoneVisibleExec(var Msg: TMessage);
var prm:integer;
begin
prm:=Msg.Wparam;
if prm=0 then //Включить индикатор телефона / Начало звонка DIAL_STATUS='callin_start'
begin
PanelPhone.Visible:=true;
ImagePhone.Visible:=false; ImageBtnInsertPhone.Visible:=true; ImageBtnOutPhone.Visible:=false;
LabelPhoneExternal.Font.Color:=clMaroon;
LabelPhoneExternal.Caption:='Вам звонят - '+PhoneNum;
TimerPhone.Interval:=100; TimerPhone.Enabled:=fl_flashing_phone_indicator;
end;
if (prm=1) or (prm=4) then //Включить индикатор телефона / Начало разговора DIAL_STATUS='connect'
begin
PanelPhone.Visible:=true;
ImagePhone.Visible:=true; ImageBtnInsertPhone.Visible:=false; ImageBtnOutPhone.Visible:=false;
LabelPhoneExternal.Font.Color:=clGreen;
if (prm=1) then LabelPhoneExternal.Caption:='Вы говорите с '+PhoneNum;
if (prm=4) then LabelPhoneExternal.Caption:='Вы дозвонились - '+PhoneNum;
TimerPhone.Interval:=0; TimerPhone.Enabled:=false;
FormCallCntr.FindPatWithPhoneExecute(FormCallCntr);
end;
if (prm=2) or (prm=5) then //Выключить индикатор телефона / Звонок полностью окончен DIAL_STATUS:='stop'
begin
PanelPhone.Visible:=false;
TimerPhone.Interval:=0; TimerPhone.Enabled:=false;
SBtnCallout_start.Visible:=true;
end;
if prm=3 then //Включить индикатор телефона / Начало звонка DIAL_STATUS='callout_make'
begin
PanelPhone.Visible:=true;
ImagePhone.Visible:=false; ImageBtnInsertPhone.Visible:=false; ImageBtnOutPhone.Visible:=true;
LabelPhoneExternal.Font.Color:=clMaroon;
LabelPhoneExternal.Caption:='Вы звоните на номер '+LEditPhone.text;
TimerPhone.Interval:=100; FormCallCntr.TimerPhone.Enabled:=fl_flashing_phone_indicator;
end;
end;
По идее, т.к. в один экземпляр ПР прилетают сообщения касающиеся только событий происходящих в одним внутренним номером телефонной сети, то они должны быть более мнее последовательными, и очень редко может возникать ситуация когда, предыдущее еще не отработано-не отрисовано, и уже пришло очередное. Но возможно такое случается, при высокой плотности звонков и большом количестве людей-операторов работающих одновременно.
Например может быть такая череда сообщений.
callin_start|1231|9119116789
callin_stop|1239|9119116789
callin_start|1245|9519512345
callin_stop|1266|9519512345
callin_start|3346|9019019874
callin_connect|3377|9019019874
callin_stop|3489|9019019874
....
Sleep(10) - не было, добавил по рекомендации (хотя советовали IndySleep но похоже в IndyLaz его нет)
Так же в книге "Indy in depth" вычитал рекомендацию
В Indy имеется специальный компонент, который решает проблему замораживания
пользовательского интерфейса. Просто добавьте один компонент TIdAntiFreeze куда ни будь в
своем приложении, и вы сможете выполнять блокирующие вызовы без замораживания
пользовательского интерфейса. Использование TIdAntiFreeze позволяет получить все преимущества блокирующих сокетов, без
видимых недостатков.
Тестирование того повлияло ли прерывание Sleep и IdAntiFreeze еще предстоит.
Основной вопрос. Правильно ли вообще так делать, так обрабатывать внешние сообщения для индикации событий?
Если нет то как лучше делать?