2016-05-25 11 views
4

UPDATE Frage: So konnte ich den Prozess erstellen und die Programme kompilieren. Ich stoße jedoch auf ein neues Problem. Wenn ich versuche, das Source-Programm in das Filter-Programm zu leiten. Es scheint keine Eingabe für das Senkenprogramm zu liefern. Es gibt keine Fehlermeldung. Ich habe auch mein ganzes Programm mit dem Pipe-Operator in Windows 'cmd getestet.Prozess und anonyme Leitung erstellen

Ich versuche dieses kleine Projekt zu tun, um über anonyme Pipe zu lernen und Prozess zu erstellen. Ich habe 3 kleine Standalone-Programme namens Source, Filter und Sink erstellt. Diese 3 sind bereits kompiliert und laufen gut. Hier sind die Beschreibungen für die 3 Standalone-Programme.

Quelle: Ermittelt den Dateinamen einer Quelltextdatei von der Befehlszeile, öffnet die Datei und liest und kopiert den Inhalt der Datei ein Zeichen nach dem anderen direkt in die Standardausgabe (stdout). Wenn die Datei kopiert wurde, wird Source beendet (alle geöffneten Dateihandles werden geschlossen).

Das Filterprogramm verwendet keine Dateinamen-Befehlszeilenparameter. Stattdessen liest Filter eine Textdatei von der Standardeingabe (stdin) und schreibt eine Standardausgabe (stdout) einer Kopie der Eingabe, wobei alle Großbuchstaben in Kleinbuchstaben konvertiert werden. Der Filter muss speziell dafür ausgelegt sein, ein Zeichen zu lesen, es zu konvertieren, auszugeben und dann zu wiederholen, bis die eingehenden Daten beendet sind.

Sink-Programm ruft einen Zieltextdateidateinamen von seiner Befehlszeile ab, öffnet die Datei zum Schreiben und liest dann nacheinander Zeichen aus der Standardeingabedatei (stdin) und schreibt jedes eingehende Zeichen direkt in die Zielsenkdatei .

Als nächstes fahre ich separat ein Haupttreiberprogramm, das 2 Pipes erstellt und 3 unabhängige Childs mit Ein- und Ausgängen spawnt, die so konfiguriert sind, dass sie die angegebene gleichzeitige Ausführung und den gleichen Datenfluss ausführen. Etwas wie folgt aus:

  • srcfile -> Quelle -> PIPE1 -> Filter -> PIPE2 -> Sink -> destfile

Der Fahrer Programm erfordert zwei Kommandozeilenparameter:

  • C:\> Driver.exe srcfile destfile

wo srcfile ist eine bestehende Daten Text-Datei, und Zieldatei ist der Dateiname einer neuen Zieldatei, die von der Sink-Anwendung erstellt werden soll.

Hier ist mein Code für das Treiberprogramm. Es ist noch nicht fertig. Aber ich habe einen Schluckauf beim Versuch, einen Prozess für das Source-Programm zu erstellen.

AKTUALISIERT Code:

#include <windows.h> 
#include <WinBase.h> 
#include <stdio.h> 


#define DELAY_A_WHILE() {volatile long j; for(j = 1; j< 10000; j++) ; } 

int main(int argc, char *argv[]) 
{ 
    HANDLE hPipeRead, hPipeWrite, hPipeRead2, hPipeWrite2; 
    STARTUPINFO StartupInfoSource; 
    STARTUPINFO StartupInfoFilter; 
    STARTUPINFO StartupInfoSink; 
    PROCESS_INFORMATION ProcInfoSource; 
    PROCESS_INFORMATION ProcInfoFilter; 
    PROCESS_INFORMATION ProcInfoSink; 
    SECURITY_ATTRIBUTES PipeAttributes; 
    SECURITY_ATTRIBUTES PipeAttributes2; 
    char cmdline[200]; 

    PipeAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); 
    PipeAttributes.lpSecurityDescriptor = NULL;  //ignore 
    PipeAttributes.bInheritHandle = TRUE;   //child can inherit 

    //Create first pipe 
    if (!CreatePipe(&hPipeRead, &hPipeWrite, &PipeAttributes, 0)) { 
     fprintf(stderr, "Error creating pipe: %d\n", GetLastError()); 
     exit(1); 
    } 

    sprintf_s(cmdline, 200, "Source.exe %s", argv[1]); 
    printf("Create process: %s\n", cmdline); 

    GetStartupInfo(&StartupInfoSource); 
    StartupInfoSource.dwFlags = StartupInfoSource.dwFlags | STARTF_USESTDHANDLES; 


    //Mapping 
    StartupInfoSource.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 
    StartupInfoSource.hStdOutput = hPipeWrite; 
    StartupInfoSource.hStdError = GetStdHandle(STD_ERROR_HANDLE); 

    if (!CreateProcess(
     NULL, cmdline, NULL, NULL, 
     TRUE, 
     CREATE_NEW_CONSOLE, NULL, NULL, 
     &StartupInfoSource, 
     &ProcInfoSource)) 
    { 
     fprintf(stderr, "Error creating child process: %d",GetLastError()); 
     exit(1); 
    } 

    CloseHandle(hPipeWrite); 
    CloseHandle(ProcInfoSource.hProcess); 
    CloseHandle(ProcInfoSource.hThread); 

    PipeAttributes2.nLength = sizeof(SECURITY_ATTRIBUTES); 
    PipeAttributes2.lpSecurityDescriptor = NULL;  //ignore 
    PipeAttributes2.bInheritHandle = TRUE;   //child can inherit 
    //Create Second Pipe 
    if (!CreatePipe(&hPipeRead2, &hPipeWrite2, &PipeAttributes2, 0)) { 
     fprintf(stderr, "Error creating pipe: %d\n", GetLastError()); 
     exit(1); 
    } 

    GetStartupInfo(&StartupInfoFilter); 
    StartupInfoFilter.dwFlags = StartupInfoFilter.dwFlags | STARTF_USESTDHANDLES; 

    //Mapping 
    StartupInfoFilter.hStdInput = hPipeRead; 
    StartupInfoFilter.hStdOutput = hPipeWrite2; 
    StartupInfoFilter.hStdError = GetStdHandle(STD_ERROR_HANDLE); 

    sprintf_s(cmdline, 200, "Filter.exe"); 
    printf("Create process: %s\n", cmdline); 

    //Filter 
    GetStartupInfo(&StartupInfoFilter); 
    if (!CreateProcess(
     NULL, cmdline, NULL, NULL, 
     TRUE, 
     CREATE_NEW_CONSOLE, NULL, NULL, 
     &StartupInfoFilter, 
     &ProcInfoFilter)) 
    { 
     fprintf(stderr, "Error creating child process: %d", GetLastError()); 
     exit(1); 
    } 
// int exitStatus; 
    // GetExitCodeProcess(ProcInfoFilter.hProcess, &exitStatus); 
    CloseHandle(hPipeRead); 
    CloseHandle(hPipeWrite2); 
    CloseHandle(ProcInfoFilter.hProcess); 
    CloseHandle(ProcInfoFilter.hThread); 


    GetStartupInfo(&StartupInfoSink); 
    StartupInfoSink.dwFlags = StartupInfoSink.dwFlags | STARTF_USESTDHANDLES; 



    //Mapping 
    StartupInfoSink.hStdInput = hPipeRead2; 
    StartupInfoSink.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 
    StartupInfoSink.hStdError = GetStdHandle(STD_ERROR_HANDLE); 

    sprintf_s(cmdline, 200, "Sink.exe %s", argv[2]); 
    printf("Create process: %s\n", cmdline); 

    GetStartupInfo(&StartupInfoSink); 
    if (!CreateProcess(
     NULL, cmdline, NULL, NULL, 
     TRUE, 
     CREATE_NEW_CONSOLE, NULL, NULL, 
     &StartupInfoSink, 
     &ProcInfoSink)) 
    { 
     fprintf(stderr, "Error creating child process: %d", GetLastError()); 
     exit(1); 
    } 

    CloseHandle(hPipeRead2); 
    CloseHandle(ProcInfoSink.hProcess); 
    CloseHandle(ProcInfoSink.hThread); 


    return 0; 
} 

Das Programm stellt in Ordnung. Wenn es jedoch versucht, den Prozess zu erstellen, schlägt er immer fehl und wird beendet. Der Wert cmdline beim Parsen ist "Source.exe test.txt", was genau das ist, was ich benutzt habe, um mein eigenständiges Source-Programm auszuführen. Kann jemand erklären, warum meine CreateProcess scheitern? Liegt es daran, dass ich den falschen Parameter parse?

+0

Sie sagen also, CreateProcess' scheitert? Dann sollten Sie sich den Fehlercode ansehen, der von 'GetLastError' zurückgegeben wird. Übrigens, ist es richtig, dass Sie den 'STARTUPINFO' des aufrufenden Prozesses übergeben? Soll das die Griffe zu stdin und stdout übergeben? –

+0

Wenn ich versuche, zu debuggen, führt das Programm immer das Stück Code innerhalb der If (! CreateProcess()) aus, die den Fehler drucken soll, wenn es das Programm nicht schafft und verläßt. –

Antwort

2

Das einzige Problem, das ich hier sehen kann, ist die Möglichkeit, dass die Source.exe-App nicht in dem Verzeichnis liegt, in dem sich Driver.exe befindet. Ich habe Ihren Code ausprobiert und es war der einzige Fall, als CreateProcess fehlgeschlagen ist.

+0

Meine source.exe befindet sich im selben Ordner wie die Driver.c-Datei. Ist es der richtige Ort dafür? –

+0

Nein. Ihre Binärdatei wird normalerweise im Release- oder Debug-Ordner abgelegt (abhängig davon, welche Build-Konfiguration Sie verwenden). Wenn Sie Ihr Projekt mit der Option "Verzeichnis für die Lösung erstellen" aktiviert haben, sehen Sie zwei verschiedene Release- und zwei verschiedene Debug-Ordner. Sie benötigen den, der sich in den oberen Schichten Ihrer Verzeichnisstruktur befindet. Wie auch immer, versuchen Sie einfach, den genauen Speicherort der Datei "driver.exe" zu finden und geben Sie "source.exe" in diesen Ordner ein. –

+0

habe ich schon getan. Und es macht immer noch dasselbe. –

-1

Ich habe herausgefunden, warum.Die Eigenschaft meines Projekts verwendete den Unicode-Zeichensatz. Wenn ich zu Multi-Byte-Zeichensatz umschalte, funktioniert es gut.

+0

Das ist nachweislich nicht ermüdet. Der Code in der Frage hätte nicht kompiliert. Das passiert, wenn Sie gefälschten Code verloren haben. Schäm dich. Das Umschalten auf Multibyte ist der falsche Weg. Es ist 2016. Verwenden Sie Unicode bereits! –

+0

Mein Code in der Frage kompiliert. Ich habe hier einige andere Fragen zu stackoverflow nachgeschlagen, die besagen, dass der Unicode-Zeichensatz in der Win32-Konsole schlecht unterstützt wird und nicht richtig angezeigt werden kann. Daher ist es am besten zu vermeiden. Hast du einen Vorschlag, es im Unicode-Zeichensatz zu tun? –

+0

Wenn dieser Code kompiliert wird, ist Unicode nicht definiert. Unicode wird von der Windows-Konsole unterstützt. –