2009-03-15 1 views
4

Ich habe eine Win32-Anwendung, die ich mache, und es sendet eine Zeichenfolge von einem Prozess zu einem anderen über eine Named Pipe. Der Prozess, der ReadFile für die Pipe aufruft, ruft jedoch die Zeichenfolge mit einigen verstümmelten Daten darin ab. Es gibt die Anzahl der korrekt geschriebenen Bytes zurück, aber die letzten 8 Zeichen des Strings sind verstümmelt.Wie kann man verstümmelten Text mit WriteFile auf einer Pipe reparieren?

Hier ist der Code für das Rohr zu schaffen und zu schreiben, um es:

myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL); 
TCHAR title[128]; 
GetWindowText(foundHwnd, title, 128); 
wstring windowTitle(title); 
vector<wstring> splitVec; 
boost::split(splitVec, windowTitle, boost::algorithm::is_any_of(wstring(L"|"))); 
WriteFile(myPipe, splitVec[0].c_str(), splitVec[0].size(), &wrote, NULL); 

Und hier ist der Code, der es liest:

if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) { 
    MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK); 
    return false; 
} 

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL, 
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
if (myPipe == INVALID_HANDLE_VALUE) { 
    MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK); 
    return false; 
} 
    // Other code here... 
    TCHAR buf[512]; 
    DWORD read; 
    success = ReadFile(myPipe, buf, 512, &read, NULL); 
    if (read > 0) 
     MessageBox(NULL, buf, L"Got Data", MB_OK); 

Wenn MessageBox das Ende der gezeigt wird, String ist verstümmelt und ich habe keine Ahnung warum. Irgendwelche Ideen?

Danke!

Antwort

2

Ich denke, der Schlüssel hier ist, um sicherzustellen, dass Ihre Strings null abgeschlossen sind und Sie auch das Abschlusszeichen senden. Sie sollten nicht den gesamten Puffer senden müssen, wenn die Kommunikation synchron ist oder wenn Sie es in PIPE_READMODE_MESSAGE einrichten. ReadFile wird zurückgegeben, wenn entweder die angegebene Anzahl von Bytes gelesen wurde oder eine Schreiboperation am anderen Ende der Pipe abgeschlossen wurde. Ich glaube, dass der "verstümmelte" Text wirklich Müll im Lesepuffer auf der Client-Seite der Pipe ist und weil Sie das String-Beendigungszeichen nicht übertragen, wird es in den Text eingeschlossen, der an das Nachrichtenfeld gesendet wird. Entweder lösche ich den Lesepuffer vor dem Senden oder sende das Zeichenkettenbeendigungszeichen mit der Nachricht, und ich denke, es funktioniert ohne den Aufwand, einen vollen Puffer zu senden.

Hier ist sample client von MSDN.Beachten Sie, wie der Client genau die Anzahl der Zeichen in der Nachricht + 1 (einschließlich des Abschlusszeichens) sendet und in einem festen Puffer der Größe 512 empfängt. Wenn Sie einen server example betrachten, sehen Sie das gleiche Muster.

+0

Danke! Ich hatte jetzt ein Problem mit der Hälfte der gesendeten Zeichenfolge. Ich brauchte die (lstrlen (..) + 1) * sizeof (TCHAR), wie im Beispiel gezeigt. – staackuser2

+0

Ah, ja. Multibyte-Zeichen. Daran habe ich nicht einmal gedacht. – tvanfosson

+0

good catch, ich habe meine Antwort aktualisiert und sie mit * sizeof (TCHAR) –

2

Einige Beobachtungen über den Code, den Sie geschrieben:

  • Sie müssen entweder 1) explizit die Null beendet Byte oder 2) anhängen ein an die Daten, die Sie lesen senden.
  • Da Sie 512 Bytes lesen, sollten Sie auch genau 512 Bytes senden.
  • Sie können stattdessen Strings variabler Länge senden, indem Sie zuerst die Größe der Zeichenfolge senden und dann so viele Bytes senden. Auf diese Weise wissen Sie beim Lesen der Daten, wie viele Bytes für die tatsächliche Zeichenfolge zu lesen sind.
  • Das Problem mit dem, was Sie getan haben, wird zu sehen sein, sobald Sie 2 Dinge über die Leitung senden, und Sie lesen vorbei, was Sie wirklich in der ersten Lesung wollen.
  • Wenn Sie nur eine Sache über die Pipe senden, können Sie Ihren Code behalten, aber senden Sie Größe() + 1, wenn Sie in die Pipe schreiben.
  • ReadFile/WriteFile sollte Binärdaten senden, nicht unbedingt Zeichenfolgen. So können Sie eine Funktion namens ReadString und WriteString machen, die meinen Vorschlag zum Lesen/Schreiben zuerst der Größe und dann der eigentlichen Zeichenfolge implementiert.

versuchen, etwas wie folgt aus:

Hier ist der Code für das Rohr zu schaffen und zu schreiben, um es:

myPipe = CreateNamedPipe(L"\\\\.\\pipe\\testpipe", PIPE_ACCESS_OUTBOUND, PIPE_NOWAIT, 10, 512, 512, 10, NULL); 
TCHAR title[128]; 
GetWindowText(foundHwnd, title, 128); 
WriteFile(myPipe, title, 128*sizeof(TCHAR), &wrote, NULL);//<---In this case we are sending a null terminated string buffer. 

Und hier ist der Code, der es liest:

if (WaitNamedPipe(L"\\\\.\\pipe\\testpipe", 5000) == 0) { 
    MessageBox(NULL, L"Unable to wait for pipe", L"Error", MB_OK); 
    return false; 
} 

myPipe = CreateFile(L"\\\\.\\pipe\\testpipe", GENERIC_READ, FILE_SHARE_READ, NULL, 
    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 
if (myPipe == INVALID_HANDLE_VALUE) { 
    MessageBox(NULL, L"Unable to open pipe", L"Error", MB_OK); 
    return false; 
} 
    // Other code here... 
    TCHAR buf[128]; 
    DWORD read; 
    success = ReadFile(myPipe, buf, 128*sizeof(TCHAR), &read, NULL); 
    if (read > 0) 
     MessageBox(NULL, buf, L"Got Data", MB_OK); 
+0

Danke, ich wusste nicht, Rohre benötigt die Länge um genau zu sein. Ich dachte, sie würden es für mich tun. Es funktioniert jetzt! – staackuser2

0

Ich stieß auf dieses Problem mit "Müll in der Pipe" beim Schreiben einer generischen Funktion zum Lesen von stdout von jedem Prozess an der Eingabeaufforderung ausgeführt. Daher konnte ich nicht ändern, was auf die Pipe geschrieben wurde (wie es allgemein vorgeschlagen wird), ich konnte nur die Leseseite ändern. Also habe ich "geschummelt".

Wenn die Pipe-Daten nicht in einem Null-Terminator enden, habe ich das letzte Zeichen durch eins ersetzt! Es schien für mich zu funktionieren. Ich sah diese Arbeit perfekt dort, wo Nullen waren und wo es nicht am Ende meiner Datenblöcke war.

Ich habe mir Sorgen gemacht, dass ich einen kritischen letzten Char verlieren könnte (und es ist möglich, dass Sie könnten!), Aber für meine unmittelbaren Zwecke, das ist nicht geschehen. Sie könnten eine Null hinzugefügt, anstatt zu ersetzen, das Ende unter Umständen betrachten ...

Hier Code snippit:

const unsigned int MAX_PIPE_PEEKS = 100; 
DWORD bytesInPipe = 0; 
unsigned int pipePeeks=0; 
while((bytesInPipe==0) && (pipePeeks < MAX_PIPE_PEEKS)) 
{ 
    bSuccess = PeekNamedPipe(g_hChildStd_OUT_Rd, NULL, 0, NULL, 
           &bytesInPipe, NULL); 
    if(!bSuccess) return bSuccess; // Bail on critical failure     
    ++pipePeeks; 
} 
if(bytesInPipe > 0) 
{ 
    // Read the data written to the pipe (and implicitly clear it) 
    DWORD dwRead; 
    CHAR *pipeContents = new CHAR[ bytesInPipe ];  
    bSuccess = ReadFile(g_hChildStd_OUT_Rd, pipeContents, 
         bytesInPipe, &dwRead, NULL); 
    if(!bSuccess || dwRead == 0 ) return FALSE; // Bail on critical failure    

    // "Cheat" - eliminate garbage at the end of the pipe 
    if(pipeContents[ bytesInPipe ] != '\0') 
     pipeContents[ bytesInPipe ] = '\0'; 
} 

UPDATE:

Nach weiteren Tests fand ich, dass dies nicht ganz zuverlässig ist (schockierend, nicht wahr?) Ich denke jedoch, dass ich auf dem richtigen Weg bin für eine relativ einfache Lösung. Irgendwelche Ideen, um diesen schnellen Patch zum Laufen zu bringen?

Verwandte Themen