0

Delphiアプリケーションがあり、呼び出しを介して名前付きパイプにテキストを送信します

SendMessageToNamedPipe(hPipe, CurMsg);

一部のメッセージでは正常に機能しますが、他のテキストを送信するとアプリケーションがクラッシュします。

私が知っている通常のメッセージと「クラッシュする」メッセージの唯一の違いは、クラッシュするメッセージに多くのキリル文字が含まれていることです。

前述の呼び出しを正しく実行するには、どのようにエンコードする必要がありますか?

アップデート1:これがの実装ですSendMessageToNamedPipe

procedure SendMessageToNamedPipe(hPipe:THandle; msg:string);
  const
    OUT_BUF_SIZE = 100;
  var
    dwWrite : DWORD;
    lpNumberOfBytesWritten : LongBool;
    utf8String : RawByteString;
    sendBuf: array[0..OUT_BUF_SIZE] of WideChar;
  begin
    utf8String := UTF8Encode(msg);

    sendBuf[0] := #0;
    lstrcatw(sendBuf, PChar(msg));

    lpNumberOfBytesWritten := WriteFile(hPipe, sendBuf, OUT_BUF_SIZE, dwWrite, NIL);

    if not lpNumberOfBytesWritten then
    begin
      OutputDebugString(PChar('Sending error: ' + SysErrorMessage(GetLastError)));
    end
    else
    begin
      OutputDebugString(PChar('Message sent, dwWrite: ' + IntToStr(dwWrite)));
    end;
  end;

アップデート2:機能しているように見える関数のバージョン。

procedure SendMessageToNamedPipe(hPipe:THandle; msg:string);
const
    OUT_BUF_SIZE = 200;
var
  dwWrite : DWORD;
  Success : LongBool;
  msgToSend : PChar;
  utf8String : RawByteString;
  sendBuf: array[0..OUT_BUF_SIZE-1] of WideChar;
  AnsiCharString : PAnsiChar;
begin
    OutputDebugString(PChar('SendMessageToNamedPipe.Length(msg): ' +     IntToStr(Length(msg))));
    OutputDebugString(PChar('Sending message: ' + msg));

    utf8String := UTF8Encode(msg);

    sendBuf[0] := #0;
    lstrcatw(sendBuf, PChar(msg));

    Success := WriteFile(hPipe, sendBuf, Length(sendbuf), dwWrite, NIL);

    if not Success then
    begin
      OutputDebugString(PChar('Sending error: ' + SysErrorMessage(GetLastError)));
    end
    else
    begin
      OutputDebugString(PChar('Message sent, dwWrite: ' + IntToStr(dwWrite)));
    end;
end;
4

1 に答える 1

6

Windowsパイプ関数は、パイプに書き込まれたデータをバイナリストリームとして認識するため、書き込まれるデータの種類によってクラッシュが発生する可能性はありません。

ただし、SendMessageToNamedPipeは、Delphiライブラリ関数でもWindowsAPI呼び出しでもありません。SendMessageToNamedPipeが何をしているのかを確認する必要があると思います。これは、ほぼ確実にバグがある場所だからです。次のような質問をしたいと思うかもしれません:CurMsgのデータ型は何ですか?SendMessageToNamedPipeは、パイプに書き込むバイト数をどのように計算しますか?

アップデート:

質問に追加したSendMessageToNamedPipeの実装を読んでください。

  1. sendBufは、OUT_BUF_SIZE+1ワイド文字です。おそらくそれをarray[0..OUT_BUF_SIZE-1]として定義するつもりでした。私はいつもこの間違いを目にします。(しかし、それはクラッシュの原因ではありません。)

  2. utf8Stringが割り当てられますが、使用されることはありません。

  3. クラッシュの原因はlstrcatw(sendBuf、PChar(msg))だと思います。渡された文字列の長さがOUT_BUF_SIZE+1文字より大きい場合、バッファsendBufがオーバーフローするため、クラッシュします。

  4. lpNumberOfBytesWrittenでない場合のテストは間違っています。さらに重要な点として、WriteFileからの戻り値は、書き込みが成功したかどうかを示すブール値であり、書き込まれたバイト数のカウントではありません。WriteFileは、終了時にdwWriteの値を変更して、書き込まれたバイト数のカウントを提供します。

  5. 別のものを見つけました。WriteFileはOUT_BUF_SIZEバイトを送信していますが、OUT_BUF_SIZEは、バイト数ではなく、sendBufの文字数のカウントです。Delphi 2009の文字は2バイト(utf-16)です。(ただし、優れたコードは、将来のDelphiバージョンで変更される可能性があり、過去に1回変更されているため、常に2ではなくSizeOf(Char)を使用します。)

Davidが書い​​たように、パイプに書き込む前に実際にmsgを別のバッファーにコピーする必要はありません。式PChar(msg)は、msg内のデータを構成するnullで終了するCharの配列の先頭へのポインターを返します。

あなたのコードを振り返って、パイプの反対側のプログラムがutf-16文字列またはutf-8文字列(またはそのことについてはANSI文字列)を受け取ることを期待しているかどうかを自分の心で明確にしているかどうかを尋ねます)。この質問を解決してから、それに応じてSendMessageToNamedPipeを変更する必要があります。(また、固定長のバッファーではなく、nullで終了する文字列が必要な場合は、OUT_BUF_SIZEバイトではなく、意図したバイト数だけを送信する必要があります。)

以下のコメントに返信してください。

  1. 上記のコードは、パイプにutf-8を書き込みません。utf-16を書き込みます。UTF8Encodeを呼び出しましたが、前述したように、結果を破棄しました。

  2. PRawByteString(utf8String)のようにキャストすることで、送信するバッファーとしてutf8Stringを直接WriteFileに渡すことができます。この式は、上で説明したPChar(msg)の場合と同様に、utf8Stringの最初の文字へのポインターを返します。

  3. WriteFileに書き込むには、OUT_BUF_SIZEではなく、正しいバイト数を渡す必要があります。これはutf-8文字列であるため、文字は1〜4バイトの範囲で使用できます。しかし、たまたま、DelphiのLength関数は、Utf8StringまたはRawByteStringに適用されたときにバイト数を返すため、Length(utf8String)+1と書くことができます。+1は、長さカウントに含まれない終了#0文字を含めることです。(utf-16文字列を渡す場合、Lengthは文字数を返すため、SizeOf(Char)を掛ける必要があります)。

それでも不明な場合は、DelphiとUnicodeを読むことで大きなメリットが得られるでしょう。

于 2012-11-01T14:34:54.560 に答える