Domanda

Ho un'applicazione Win32 che sto creando e invia una stringa da un processo a un altro tramite una pipe denominata. Tuttavia, il processo che chiama ReadFile sulla pipe ottiene la stringa con alcuni dati confusi al suo interno. Restituisce il numero di byte scritti correttamente, ma gli ultimi 8 caratteri circa della stringa sono confusi.

Ecco il codice per creare la pipe e scriverla:

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

Ed ecco il codice che lo legge:

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

Quando viene mostrato MessageBox, la fine della stringa è confusa e non ho idea del perché. Qualche idea?

Grazie!

È stato utile?

Soluzione

Penso che la chiave qui sia assicurarsi che le stringhe siano nulle e che invii anche il carattere di terminazione. Non è necessario inviare l'intero buffer se le comunicazioni sono sincrone o se impostato in PIPE_READMODE_MESSAGE . ReadFile verrà restituito quando il numero specificato di byte è stato letto o è stata completata un'operazione di scrittura sull'altra estremità della pipe. Credo che il "quotato confuso" text è davvero spazzatura nel buffer di lettura sul lato client della pipe e poiché non si sta trasmettendo il carattere di terminazione della stringa, lo sta includendo nel testo inviato alla finestra di messaggio. Cancella il buffer di lettura prima di inviare o invia il carattere di terminazione della stringa con il messaggio e penso che funzionerà senza il sovraccarico di inviare un buffer completo.

Ecco client di esempio da MSDN . Nota come il client invia esattamente il numero di caratteri nel messaggio + 1 (incluso il carattere di terminazione) e riceve in un buffer fisso di dimensioni 512. Se si osserva un esempio di server , vedrai lo stesso schema.

Altri suggerimenti

Alcune osservazioni sul codice che hai pubblicato:

  • È necessario 1) inviare esplicitamente il byte con terminazione null oppure 2) aggiungere uno ai dati letti.
  • Dato che stai leggendo 512 byte, dovresti anche inviare esattamente 512 byte.
  • Puoi invece inviare stringhe di lunghezza variabile inviando prima la dimensione della stringa e quindi inviando così tanti byte. In questo modo quando leggi i dati saprai quanti byte leggere per la stringa effettiva.
  • Il problema con quello che hai fatto verrà visto non appena invierai 2 cose sulla pipe e leggi ciò che vuoi veramente nella prima lettura.
  • Se stai inviando solo 1 cosa sulla pipe, puoi conservare il tuo codice, ma invia size () + 1 quando scrivi sulla pipe.
  • ReadFile / WriteFile avevano lo scopo di inviare dati binari, non necessariamente stringhe. Quindi puoi creare una funzione chiamata ReadString e WriteString che implementa il mio suggerimento di leggere / scrivere prima la dimensione e poi la stringa effettiva.

Prova qualcosa del genere:

Ecco il codice per creare la pipe e scriverla:

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.

Ed ecco il codice che lo legge:

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

Ho riscontrato questo problema con "immondizia nel tubo" quando si scrive una funzione generica per leggere stdout da qualsiasi processo eseguito al prompt dei comandi. Pertanto, non potevo alterare ciò che veniva scritto sulla pipe (come è comunemente suggerito), potevo solo modificare il lato di lettura. Quindi, ho "imbrogliato".

Se i dati della pipe non finivano in un terminatore null, ho sostituito l'ultimo carattere con uno! Sembrava funzionare per me. Ho visto questo lavoro perfettamente dove c'erano null e dove non c'erano alla fine dei miei blocchi di dati.

Temevo di perdere un ultimo carattere critico (ed è possibile che tu potessi!), ma per i miei scopi immediati, ciò non è accaduto. Potresti prendere in considerazione l'aggiunta di un valore null anziché sostituire la fine in alcune circostanze ...

Ecco lo snippit di codice:

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:

Dopo ulteriori test, ho scoperto che questo non è abbastanza affidabile (scioccante, eh?). Penso di essere sulla buona strada per una soluzione relativamente semplice. Qualche idea per far funzionare questa patch veloce?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top