문제

저는 IRC 클라이언트에서 작업하고 있습니다. 나는 전공을 때렸다. 아래 코드를 보여 드리겠습니다. 내가 문제가있는 것은 idirc의 이벤트 핸들러 내에 MDI 어린이 창을 만드는 것입니다.

예를 들어, 새 채널 양식 (FRMCHANNEL)을 만들려면 '/join'명령을 잡을 때 프로 시저를 호출하여 쉽게이를 수행 할 수 있습니다.

그러나 올바른 방법으로하고 싶고 실제로 채널에 가입 할 때까지 기다렸다가 서버에서 확인을받을 때까지 (Onjoin 이벤트 핸들러에서 처리함으로써) 내 양식 작성 절차에 대한 내 호출이 발생합니다. 교수형 응용 프로그램.

상태 Windows도 마찬가지입니다. 예를 들어, 상태 윈도우 제작 절차를 TBUTTON의 ONCLICK 이벤트에서 호출하면 괜찮습니다. 어린이 형태가 생성되었습니다. 그러나 실제로 개인 메시지를받을 때 동일한 것을 시도하면 이벤트 핸들러를 확인하여 ... 응용 프로그램이 예외는없고 MDI 자식이 없습니다.

관련 코드는 다음과 같습니다 (이를 해결하기 위해 쿼리 창만 처리하겠습니다).

첫째, 실제 MDI 아동 창조는 다음과 같습니다. 이 클래스 형식의 목록을 관리하기 위해 여기에 tcomponentlist가 있습니다 (궁금한 경우). 여기에는 양식을 추적하는 다른 것들이 있지만, 그것들을 언급하는 것은 교수형을 방해하지 않습니다 (나는 시도했습니다).

procedure TFrmMain.NewQuery(const Server, MsgFrom: String);
var
Child: TFrmMessage;
TN: TTreeNode;
begin

///
/// Create form, set some data so we can reference it later.
///
///

  Child := TFrmMessage.Create(Application);
//  QueryManager.Add(Child); //TComponent List -- Used to find the Form Later On

  with Child do
  begin
   MyServer := Server; {What server this PM window is on}
   QueryWith := MsgFrom; {nickaname of the other person}
   Caption := MsgFrom; {Asthetic}
  end;

  Child.Echo('*** Conversation with ' + MsgFrom); //Herro World

  ///
  ///  The following code is working.
  ///  I'm pretty sure it's not causing the hangs.
  ///

  TN := GetNodeByText(ChanServTree, Server, True); {Find our parent node}

  with ChanServTree.Items.AddChild(TN, MsgFrom) do
  begin
   Selected := True;
   Tag := 2; {TYPE OF QUERY}
   Data := Pointer(Integer(Child)); //Pointer to Form we created
  end;

end;

내 IRC 구성 요소의 이벤트 핸들러는 다음과 같습니다.

procedure TFrmMain.IRCPrivateMessage(ASender: TIdContext; const ANicknameFrom,
  AHost, ANicknameTo, AMessage: string);
  var
  CheckVr: String;
  aThread: TNQThread;
begin
  //DEBUG:
(StatusManager[0] as TFrmStatus).Echo('From: ' + ANickNameFrom + 'AMESSAGE: ' + '''' +AMessage + '''');

///
/// Handle Drone Version Requests!
///  This is REQUIRED on servers like irc.blessed.net - or they won't let you join
///  channels! - It's part of the Registration proccess
///

{The Drones on some server's don't follow specifications, so we need to search
hard for their presence}

CheckVr := AMessage;

StringReplace(CheckVr,' ','',[rfReplaceAll, rfIgnoreCase]);
StringReplace(CheckVr,#1,'',[rfReplaceAll, rfIgnoreCase]);
(StatusManager[0] as TFrmStatus).Echo('Message was: ' + '''' + CheckVr + '''');

if Trim(CheckVr) = 'VERSION' then
begin
 IRC.CTCPReply(ANickNameFrom,'VERSION','mIRC v6.01 Khaled Mardam-Bey');
 (StatusManager[0] as TFrmStatus).Echo('*** Sent Version Reply to ' + ANickNameFrom);

 exit; {Because if we don't, this could mess things up}
end;

  ///
  /// The Following code sends the PM to the appropriate window.
  ///  If that window does not exist, we will create one first.
  ///


  if Pos('#',Amessage) = 1 then
   begin
    //Handled Elsewhere
   end else {is PM}
   begin

     if FindQueryFrm(ANickNameTo,IRC.Host) = nil then
    begin

    NewQuery(IRC.Host, ANickNameFrom);
      exit;
     end;

   end;

//  FindChannelFrm(ANickNameTo,IRC.Host).ChannelMessage(ANicknameFrom, AMessage);

end;

교수형의 원인을 추적하기 위해 코드의 여러 부분을 언급하려고 시도했습니다. 교수형은 아이에 의해 발생합니다. = tfrmmessage.create (응용 프로그램); 구체적으로 전화하십시오. 무엇을 제공합니까?

문제가 될 수 있는지 확인하기 위해 스레드를 구현하려고 시도했습니다. 그것이 당신이 문제라고 생각하는 것이라면, 코드가 컴파일되고 있지만 나사산 버전이 매달려 있기 때문에 여전히 잘못이라고 부릅니다.

미리 감사드립니다.

도움이 되었습니까?

해결책

내가 당신에게 말했듯이 alt.comp.lang.borland-delphi 오늘 일찍, 문제는 Indy가 이벤트 처리기를 차단 소켓 호출과 동일한 스레드에서 실행한다는 것입니다. 이는 GUI와 동일한 스레드가 아닙니다. 모든 GUI 작업은 동일한 스레드에서 수행해야하지만 소켓 스레드에서 새 창이 생성됩니다.

이를 해결하기 위해 이벤트 핸들러는 메인 스레드에 알림을 게시해야합니다. 메인 스레드는 다음 메시지를 확인할 때마다 비동기식으로 처리합니다.

최근 델파이 버전이 있다면 TThread.Queue 매우 작동하는 방법 Synchronize, 호출 스레드를 제외하고는 주 스레드가 주어진 메소드를 실행할 때까지 차단하지 않습니다. 그러나 그들은 모두 방법 매개 변수와 관련하여 동일한 제한을 가지고 있습니다. 그들은 제로 파라미터 방법 만 받아들입니다. 따라서 방법이 결국 호출 될 때 사용하기 위해 추가 정보를 전송하는 것이 번거 롭습니다. 특히 나쁘다 대기 방법 메인 스레드가 실행하는 데 걸리는 한 손상되지 않아야합니다. 호출 스레드는 대기열 메소드가 호출되기 전에 추가 데이터를 덮어 쓰지 않도록해야합니다.

더 나은 계획은 아마도 메인 스레드의 일부 지정된 창에 메시지를 게시하는 것입니다. Application.MainForm 유혹적인 대상이지만 Delphi Form은 통지없이 재창조 할 책임이 있으므로 다른 스레드를 처리하는 모든 스레드가 메시지를 게시하려고 할 때 유효하지 않을 수 있습니다. 그리고 읽기 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;

나는 당신의 코드를 몇 가지 변경했습니다. 하나는 내가 자식 양식의 생성자가 제대로 만들어야하는 두 가지 정보를 받아들이게했다는 것입니다. 양식이 캡션이 별명이되기를 원한다면, 별명을 말하고 양식이 해당 정보와 관련하여 필요한 모든 것을 수행하도록하십시오.

다른 팁

내가 델파이에서 프로그래밍하고 비슷한 문제를 겪은 지 오래되었습니다 ...

Java에서는 소켓 정보 알림이 GUI를 유지하는 것과는 매우 다른 스레드에서 발생하며 GUI 스레드 외부에서 GUI를 변경하는 것이 실제로 금지되어 있습니다 (그러나 GUI 스레드를 법적으로 요청하는 메커니즘이 주어집니다. 모드를 만들려면). 델파이에서는 모든 이벤트가 동일한 이벤트 루프에서 나오지만 여전히 ... 소켓 이벤트를 기반으로 한 창을 열고 주요 GUI 업데이트를 요구하는 Queasy 느낌을 얻을 수 있습니다.

내가 시도하는 것은 Comm 이벤트가 대기열에 알림을 남기고 GUI 스레드가 onIdle 핸들러 또는 그런 것.

그래도 이것은 어둠 속에서 찌르는 것입니다. 많은 소금으로 추천하십시오!

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top