1

私の Delphi プロジェクトでは、スレッド クラス TMyThread を派生させ、フォーラムからのアドバイスに従って、AllocateHWnd を使用してウィンドウ ハンドルを作成します。TMyThread オブジェクトでは、SendMessage を呼び出してメッセージをウィンドウ ハンドルに送信します。

送信されるメッセージが少量の場合、アプリケーションはうまく機能します。ただし、メッセージが大量になると、アプリケーションはデッドロックし、応答が失われます。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;
4

1 に答える 1

6

割り当てられた文字列を 2 回破棄しています。せいぜい、 が終了した後にワーカー スレッドで例外を取得し、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;

を使用する場合、文字列を動的に割り当てる必要はありません。これSendMessage()は、メッセージが処理されるまで呼び出しスレッドをブロックし、文字列が有効なままであることを保証するためです。代わりにを使用していた場合は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;
于 2013-10-19T20:22:40.147 に答える