2009-03-15 5 views
4

J'ai une application Win32 que je crée et elle envoie une chaîne d'un processus à un autre via un tube nommé. Toutefois, le processus qui appelle ReadFile sur le canal obtient la chaîne avec des données brouillées. Il renvoie le nombre d'octets écrits correctement, mais les 8 derniers caractères de la chaîne sont tronqués.Comment réparer un texte brouillé en utilisant WriteFile sur un tuyau?

Voici le code pour créer le tuyau, et écrit à ce:

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); 

Et voici le code qui le lit:

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); 

Lorsque MessageBox est affichée, la fin de la la chaîne est brouillée et je ne sais pas pourquoi. Des idées?

Merci!

Répondre

2

Je pense que la clé ici est de s'assurer que vos chaînes sont terminées par zéro et que vous envoyez également le caractère de terminaison. Vous ne devriez pas avoir à envoyer le tampon entier si les communications sont synchrones ou si vous l'avez configuré en PIPE_READMODE_MESSAGE. ReadFile retournera lorsque le nombre spécifié d'octets a été lu ou qu'une opération d'écriture se termine à l'autre extrémité du canal. Je crois que le texte "brouillé" est vraiment garbage dans le tampon de lecture sur le côté client du tuyau et parce que vous ne transmettez pas le caractère de fin de chaîne, il inclut ceci dans le texte envoyé à la boîte de message. Effacez votre tampon de lecture avant d'envoyer ou envoyez le caractère de fin de chaîne avec le message et je pense que cela fonctionnera sans la surcharge de l'envoi d'un tampon complet.

Voici sample client à partir de MSDN.Notez comment le client envoie exactement le nombre de caractères dans le message + 1 (y compris le caractère de fin) et reçoit dans un tampon fixe de taille 512. Si vous regardez un server example, vous verrez le même modèle.

+0

Merci! J'avais maintenant un problème avec la moitié de la chaîne étant envoyée. J'avais besoin du (lstrlen (..) + 1) * sizeof (TCHAR), comme montré dans l'exemple. – staackuser2

+0

Ah, oui. Caractères multi-octets. Je n'ai même pas pensé à ça. – tvanfosson

+0

bonne prise, j'ai mis à jour ma réponse en le fixant avec * sizeof (TCHAR) –

2

Quelques observations sur le code affiché:

  • Vous devez soit 1) envoyer explicitement l'octet nul terminé, ou 2) un append aux données que vous lisez.
  • Puisque vous lisez 512 octets, vous devriez également envoyer exactement 512 octets.
  • Vous pouvez envoyer des chaînes de longueur variable à la place en envoyant d'abord la taille de la chaîne, puis en envoyant autant d'octets. De cette façon, lorsque vous lisez les données, vous connaîtrez le nombre d'octets à lire pour la chaîne actuelle.
  • Le problème avec ce que vous avez fait sera vu dès que vous envoyez 2 choses sur le tuyau, et vous lisez passé ce que vous voulez vraiment dans la première lecture.
  • Si vous n'envoyez qu'une chose par-dessus le canal, vous pouvez conserver votre code, mais envoyez size() + 1 lorsque vous écrivez dans le canal. ReadFile/WriteFile étaient destinés à envoyer des données binaires, pas nécessairement des chaînes. Vous pouvez donc créer une fonction appelée ReadString et WriteString qui implémente ma suggestion sur la lecture/écriture d'abord la taille puis la chaîne réelle.

Essayez quelque chose comme ceci:

Voici le code pour créer le tuyau, et écrit à ce:

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. 

Et voici le code qui le lit:

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

Merci, je n'avais pas réalisé que les tuyaux avaient besoin de la longueur pour être exact. Je pensais qu'ils feraient ça pour moi. Il fonctionne maintenant! – staackuser2

0

J'ai rencontré ce problème avec "garbage in the pipe" lors de l'écriture d'une fonction générique pour lire stdout à partir de tout processus exécuté à l'invite de commande. Par conséquent, je ne pouvais pas modifier ce qui était écrit sur le tuyau (comme cela est souvent suggéré), je ne pouvais que modifier le côté lecture. Donc, j'ai "triché".

Si les données de tuyau ne se terminaient pas dans un terminateur nul, j'ai remplacé le dernier caractère par un! Cela a semblé fonctionner pour moi. J'ai vu ce travail parfaitement là où il y avait des zéros et où il n'y en avait pas à la fin de mes morceaux de données. Je m'inquiétais de perdre un dernier personnage critique (et c'est possible!), Mais pour mes besoins immédiats, cela ne s'est pas produit. Vous pouvez envisager d'ajouter une valeur nulle au lieu de remplacer la fin dans certaines circonstances ...

est ici 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'; 
} 

MISE À JOUR:

Après d'autres tests, je trouve que ce n'est pas tout à fait fiable (choquant, hein?). Je pense que je suis sur la bonne voie pour une solution relativement simple. Des idées pour faire fonctionner ce patch rapide?

Questions connexes