2013-10-19 8 views
1

Delphi 프로젝트에서 스레드 클래스 TMyThread를 파생시키고 포럼의 조언에 따라 AllocateHWnd를 사용하여 창 핸들을 만듭니다. TMyThread 객체에서 SendMessage를 호출하여 윈도우 핸들에 메시지를 보냅니다.SendMessage가 AllocateHWND에 의해 생성 된 윈도우로 인해 교착 상태가 발생합니다.

보낸 메시지가 작은 볼륨에 있으면 응용 프로그램이 잘 작동합니다. 그러나 메시지가 대량 인 경우 응용 프로그램은 교착 상태에 빠져 응답을 잃게됩니다. 나는 메시지 큐가 LogWndProc처럼 완전하다고 생각하지만, 메시지를 처리하는 코드 만 있지만 큐에서 메시지를 제거하는 코드가 없기 때문에 처리 된 모든 메시지가 큐에 남아 큐가 가득 차게 될 수도있다. . 그 맞습니까?

코드는 아래 첨부 :

var 
hLogWnd: HWND = 0; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
hLogWnd := AllocateHWnd(LogWndProc); 
end; 

procedure TForm1.FormDestroy(Sender: TObject); 
begin 
if hLogWnd <> 0 then 
DeallocateHWnd(hLogWnd); 
end; 

procedure TForm1.LogWndProc(var Message: TMessage); 
var 
S: PString; 
begin 
if Message.Msg = WM_UPDATEDATA then 
begin 
S := PString(msg.LParam); 
try 
List1.Items.Add(S^); 
finally 
Dispose(S); 
end; 
end else 
Message.Result := DefWindowProc(hLogWnd, Message.Msg, Message.WParam, 
Message.LParam); 
end; 

procedure TMyThread.SendLog(I: Integer); 
var 
Log: PString; 
begin 
New(Log); 
Log^ := 'Log: current stag is ' + IntToStr(I); 
SendMessage(hLogWnd, WM_UPDATEDATA, 0, LPARAM(Log)); 
Dispose(Log); 
end; 
+2

을 그건 그렇고, 당신이 대답을 받아들이는 방법을 배웠 시간이다. 이전 질문을 다시 살펴보십시오. –

답변

6

당신은 두 번 할당 된 문자열을 배치하고 있습니다. 기껏해야 SendMessage()이 종료 된 후 작업자 스레드에서 예외를 가져오고, 예외를 catch하지 않으면 스레드를 종료합니다. 더 나쁜 경우에는 예외가 발생하지 않을 수도 있지만 메모리를 휴지통으로 만들어 앱을 나쁜 상태로 만들면 모든 종류의 무작위적인 일이 발생할 수 있습니다. 할당 된 문자열은 한 번만 처리해야합니다.

SendMessage()은 메시지를 대기열에 넣지 않으므로 대기열에서 보낸 메시지를 제거 할 책임이 없습니다. 그러나 메시지에있는 것처럼 스레드 경계를 넘는 전송 된 메시지를 보내려면 큐에 새 메시지가없는 경우에도 수신 스레드가 새 메시지를 위해 큐를 펌프해야합니다. SendMessage()이 블로킹중인 경우 주 메시지 루프가 실행되지 않도록 차단 한 다른 코드가있는 경우와 같이 주 스레드가 표시하지 않은 코드에서 큐를 올바르게 펌핑하지 않습니다. 차단 호출 스레드 이후 메시지가 될 때까지 당신은 SendMessage()를 사용하는 경우 동적으로 문자열을 할당 할 필요가 없습니다

procedure TForm1.LogWndProc(var Message: TMessage); 
begin 
    if Message.Msg = WM_UPDATEDATA then 
    List1.Items.Add(PString(Message.LParam)^) 
    else 
    Message.Result := DefWindowProc(hLogWnd, Message.Msg, Message.WParam, Message.LParam); 
end; 

procedure TMyThread.SendLog(I: Integer); 
var 
    Log: String; 
begin 
    Log := 'Log: current stag is ' + IntToStr(I); 
    SendMessage(hLogWnd, WM_UPDATEDATA, 0, LPARAM(@Log)); 
end; 

: 당신은, 나는 다음과 같은 변화를 보여 제안 않은 코드로

처리되어 문자열이 유효한지 확인합니다. 대신 PostMessage()를 사용한다면, 당신은 동적으로 할당 (및 Dispose()의 당신의 잘못된 사용을 수정)해야합니다 :

procedure TForm1.LogWndProc(var Message: TMessage); 
var 
    S: PString; 
begin 
    if Message.Msg = WM_UPDATEDATA then 
    begin 
    S := PString(msg.LParam); 
    try 
     List1.Items.Add(S^); 
    finally 
     Dispose(S); 
    end; 
    end else 
    Message.Result := DefWindowProc(hLogWnd, Message.Msg, Message.WParam, Message.LParam); 
end; 

procedure TMyThread.SendLog(I: Integer); 
var 
    Log: PString; 
begin 
    New(Log); 
    Log^ := 'Log: current stag is ' + IntToStr(I); 
    if not PostMessage(hLogWnd, WM_UPDATEDATA, 0, LPARAM(Log)) then 
    Dispose(Log); 
end; 
+1

당신의 대답이 제 것보다 낫고, 제 것을 지우고 싶습니다. 하지만 네가 두 배의 쓰레기는 언급하지 않았다. 제발 그것에 대한 언급을 추가 할 수 있습니다. +1 –

+0

@DavidHeffernan : 완료. –