2012-11-01 27 views
0

我有一個Delphi應用程序,它通過電話發送文本塊的命名管道通過命名管道發送文本崩潰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; 
+2

爲什麼你UTF-8編碼,然後堅持在UTF-16緩衝區?爲什麼你甚至不打擾緩衝區。只需發送PAnsiChar(utf8string) –

+0

我試過'AnsiString:= PAnsiChar(utf8String); lpNumberOfBytesWritten:= WriteFile(hPipe,AnsiString,Length(AnsiString),dwWrite,NIL);'得到相同的結果。 –

+0

成功:= WriteFile(hPipe,PAnsiChar(utf8string),Length(utf8string)+1,dwBytesWritten,nil); –

回答

6

因爲Windows管職能看到寫入管道作爲二進制流是不是合理的,被寫入的數據的類型,可能導致崩潰的數據。

但SendMessageToNamedPipe既不是Delphi庫函數,也不是Windows API調用。我認爲你需要看看SendMessageToNamedPipe在做什麼,因爲這幾乎可以肯定是錯誤所在。您可能想提出如下問題:CurMsg的數據類型是什麼? SendMessageToNamedPipe如何計算要寫入管道的字節數?

更新:

通過SendMessageToNamedPipe的實施,您已經添加到您的問題閱讀:

  1. sendBuf是OUT_BUF_SIZE + 1寬字符。你可能打算把它定義爲數組[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中的Char是2個字節(utf-16)。 (然而,好的代碼總是使用SizeOf(Char)而不是2,因爲它可能會在未來的Delphi版本中更改,並且在過去已經更改過一次。)

正如David寫道的,在寫入管道之前,實際上並不需要將msg複製到其他緩衝區。表達式PChar(msg)返回一個指向由msg中的數據組成的以空字符結尾的Chars數組開頭的指針。

反思你的代碼,我會問你是否清楚自己的想法管道的另一端的程序是否期望收到一個utf-16字符串或utf-8字符串(甚至ANSI字符串)。您需要解決此問題,然後相應地修改SendMessageToNamedPipe。 (另外,如果需要一個空終止字符串,而不是一個固定長度的緩衝區,你應該只發送字節的預期數量,而不是OUT_BUF_SIZE字節)。

回覆如下的評論:

  1. 上面的代碼不會將utf-8寫入管道。它寫道utf-16。正如我上面提到的,雖然你調用了UTF8Encode,但你拋棄了結果。

  2. 您可以直接將utf8String傳遞給WriteFile作爲發送緩衝區,通過像這樣投射它:PRawByteString(utf8String)。該表達式返回一個指向utf8String中第一個字符的指針,就像我上面解釋的PChar(msg)一樣。

  3. 您需要傳遞寫入WriteFile的正確字節數,而不是OUT_BUF_SIZE。由於它是一個utf-8字符串,字符可以佔用1到4個字節的任何內容。但是,當它應用於Utf8String或RawByteString時,Delphi的長度函數返回字節的數量,因此您可以編寫Length(utf8String)+1。 +1將包含終止#0字符,該字符不包含在長度計數中。 (如果您傳遞的是utf-16字符串,則長度將返回字符數,因此需要乘以SizeOf(Char))。

如果您還不清楚,那麼您可能會從閱讀Delphi and Unicode獲益良多。

+1

由於標籤說delphi-2009,我猜它也與Unicode(SizeOf(Char)= 2)和ANSI有關。 –

+0

@Andreas:同意,尤其是因爲這在使用ANSI範圍之外的字符時似乎最常發生。 –

+0

我在更新1中添加了'SendMessageToNamedPipe'的實現。 –

相關問題