Как я уже говорил вам в alt.comp.lang.borland-delphi ранее сегодня , проблема в том, что Indy запускает свои обработчики событий в том же потоке, что и блокирующий сокет звонки, которые не совпадают с вашим GUI. Все операции с графическим интерфейсом должны выполняться в одном потоке, но вы создаете новое окно в потоке сокета.
Чтобы решить эту проблему, ваш обработчик событий должен опубликовать уведомление в главном потоке, которое основной поток будет обрабатывать асинхронно всякий раз, когда это происходит при следующей проверке сообщений.
Если у вас есть достаточно свежая версия Delphi, вы можете попробовать метод TThread.Queue
, который работает так же, как Synchronize
, за исключением того, что вызывающий поток этого не делает блок ожидания основного потока для запуска данного метода. Они оба имеют одно и то же ограничение относительно параметров своих методов; они принимают только метод с нулевым параметром. Это усложняет передачу дополнительной информации для метода, который будет использоваться при его вызове. Это особенно плохо для методов , поставленных в очередь , поскольку любые дополнительные данные, которые вы предоставляете для них, должны оставаться нетронутыми в течение всего времени, необходимого для его запуска основным потоком; вызывающий поток должен удостовериться, что он не перезаписывает лишние данные до вызова метода из очереди.
Лучшим планом, вероятно, будет просто опубликовать сообщение в определенном окне основного потока. Application.MainForm
является заманчивой целью, но формы Delphi могут быть воссозданы без предварительного уведомления, поэтому любой дескриптор окна, используемый вашими другими потоками, может оказаться недействительным во время попытки опубликовать сообщение. И чтение свойства MainForm.Handle
по требованию также небезопасно, поскольку, если форма не имеет дескриптора в то время, она будет создана в контексте потока сокета, что позже вызовет всевозможные проблемы. Вместо этого попросите главный поток создать новое выделенное окно для получения сообщений потока с AllocateHWnd
.
Как только у вас есть цель для сообщений, к которым вы можете перейти, вы можете организовать темы для их публикации и получения. Определите значение сообщения и опубликуйте его с помощью PostMessage
.
const
am_NewQuery = wm_App + 1;
PostMessage(TargetHandle, am_NewQuery, ...);
Для отправки дополнительных данных получателю потребуется полностью обработать событие, сообщения имеют два параметра. Если вам нужны только две части информации, вы можете передать свои данные непосредственно в эти параметры. Если сообщения нуждаются в дополнительной информации, тогда вам нужно определить запись, чтобы хранить все это. Это может выглядеть примерно так:
type
PNewQuery = ^TNewQuery;
TNewQuery = record
Host: string;
FromNickname: string;
end;
Подготовьте и опубликуйте сообщение так:
procedure NewQuery(const Server, MsgFrom: string);
var
Data: PNewQuery;
begin
New(Data);
Data.Host := Server;
Data.FromNickname := MsgFrom;
PostMessage(TargetHandle, am_NewQuery, 0, LParam(Data));
end;
Обратите внимание, что вызывающая сторона выделяет новый указатель записи, но не освобождает его. Получатель освободит его.
class procedure TSomeObject.HandleThreadMessage(var Message: TMessage);
var
NewQueryData: PNewQuery;
begin
case Message.Msg of
am_NewQuery: begin
NewQueryData := PNewQuery(Message.LParam);
try
Child := TFrmMessage.Create(NewQueryData.Host, NewQueryData.FromNickname);
TN := GetNodeByText(ChanServTree, NewQueryData.Host, True); // Find parent node
with ChanServTree.Items.AddChild(TN, NewQueryData.FromNickname) do begin
Selected := True;
Tag := 2; // TYPE OF QUERY
Data := Child; // reference to form we created
end;
finally
Dispose(NewQueryData);
end;
end;
else
Message.Result := DefWindowProc(TargetHandle, Message.Msg, Message.WParam, Message.LParam);
end;
end;
Я сделал несколько других изменений в вашем коде. Во-первых, я заставил конструктор дочерней формы принять две части информации, которые необходимы ей для правильного создания. Если форма хочет, чтобы ее заголовок был псевдонимом, просто назовите его псевдонимом и дайте форме сделать с этой информацией все, что ей нужно.