2008-08-11 6 views
5

Ich wickle vorhandenen C++ - Code aus einem BSD-Projekt in unserem eigenen benutzerdefinierten Wrapper und ich möchte es mit so wenig Änderungen wie möglich in unseren Code integrieren. Dieser Code verwendet fprintf, um stderr zu drucken, um Fehler zu protokollieren/zu melden.Windows C++: Wie kann ich stderr für Aufrufe von fprintf umleiten?

Ich möchte dies an einen alternativen Ort innerhalb des gleichen Prozesses umleiten. Auf Unix Ich habe mit einer socket und ein Gewinde dies getan: ein Ende der Buchse ist, wo I Stderr (über einen Aufruf an dup2) und das andere Ende wird überwacht, in einem Thread zu senden, wo ich die Ausgabe dann verarbeiten kann.

funktioniert das nicht auf Windows aber, weil eine Steckdose nicht das gleiche wie eine Datei-Handle ist.

Alle Dokumente, die ich auf der Web-Show gefunden zu haben, wie die Ausgabe von einem untergeordneten Prozess umzuleiten, die nicht das, was ich will. Wie kann ich stderr innerhalb des gleichen Prozesses umleiten, der einen Rückruf irgendeiner Art erhält, wenn Ausgabe geschrieben wird? (Und bevor Sie es sagen, habe ich SetStdHandle versucht, aber kann keine Möglichkeit finden, dies zu tun)

Antwort

6

Sie können eine ähnliche Technik unter Windows verwenden, müssen Sie nur verschiedene Wörter für die gleichen Konzepte verwenden. :) Dieser Artikel: http://msdn.microsoft.com/en-us/library/ms682499.aspx verwendet eine Win32-Pipe, um I/O von einem anderen Prozess zu behandeln, müssen Sie nur das gleiche mit Threads innerhalb des gleichen Prozesses tun. In Ihrem Fall wird natürlich die Ausgabe an stderr von überall im Prozess zu Ihrem Kunden weitergeleitet.

Eigentlich sind andere Teile des Puzzles, die Sie benötigen, _fdopen und _open_osfhandle. In der Tat, hier ist ein verwandtes Beispiel von einigen code mir vor Jahren veröffentlicht:

DWORD CALLBACK DoDebugThread(void *) 
{ 
    AllocConsole(); 
    SetConsoleTitle("Copilot Debugger"); 
    // The following is a really disgusting hack to make stdin and stdout attach 
    // to the newly created console using the MSVC++ libraries. I hope other 
    // operating systems don't need this kind of kludge.. :) 
    stdout->_file = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); 
    stdin->_file = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT); 
    debug(); 
    stdout->_file = -1; 
    stdin->_file = -1; 
    FreeConsole(); 
    CPU_run(); 
    return 0; 
} 

In diesem Fall war der Hauptprozess ein GUI-Prozess, der mit stdio nicht startet überhaupt behandelt. Es öffnet eine Konsole und verschiebt dann die rechten Handles in stdout und stdin, sodass die debug() - Funktion (die als interaktive stdio-Funktion entworfen wurde) mit der neu erstellten Konsole interagieren kann. Sie sollten in der Lage sein, einige Pipes zu öffnen und das Gleiche zu tun, um stderr umzuleiten.

3

Man muss bedenken, dass das, was MSVCRT nennt „OS behandelt“ werden nicht Win32 behandelt, aber eine andere Schicht der Griffe hinzugefügt Sie nur zu verwirren. MSVCRT versucht, die Unix-Handle-Nummern zu emulieren, wobei stdin = 0, stdout = 1, stderr = 2 und so weiter. Win32-Handles sind unterschiedlich nummeriert und ihre Werte sind immer ein Vielfaches von 4. Das Öffnen der Pipe und die korrekte Konfiguration aller Handles erfordern es, sich die Hände schmutzig zu machen. Die Verwendung des MSVCRT-Quellcodes und eines Debuggers ist wahrscheinlich eine Voraussetzung.

1

Sie erwähnen, dass Sie eine Named Pipe nicht für den internen Gebrauch verwenden möchten; Es lohnt sich, darauf aufmerksam zu machen, dass die Dokumentation für CreatePipe(), , lautet: "Anonyme Pipes werden mithilfe einer Named Pipes mit einem eindeutigen Namen implementiert. Daher können Sie häufig ein Handle an eine anonyme Pipe an eine Funktion übergeben, die ein Handle für eine Named Pipe erfordert . " Also, ich schlage vor, dass Sie nur eine Funktion schreiben, die eine ähnliche Leitung mit den richtigen Einstellungen für asynchrone Lesevorgänge erstellt. Ich neige dazu, eine GUID als Zeichenfolge (generiert mit CoCreateGUID() und StringFromIID()) zu verwenden, um mir einen eindeutigen Namen zu geben und dann die Server- und Client-Enden der Named Pipe mit den richtigen Einstellungen für überlappende I/O zu erstellen (mehr dazu und Code, hier: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html).

Sobald ich habe, dass ich einige Code verdrahten, dass ich eine Datei mit überlappenden I/O mit einem I/O Completion Port lesen muss, und nun, ich bekomme nur async Benachrichtigungen der Daten, wie es ankommt .. Aber ich habe eine ganze Menge gut getesteten Bibliothekscode drin, der alles möglich macht ...

Es ist wahrscheinlich möglich, die Named Pipe einzurichten und dann einen überlappenden Lesevorgang mit einem Event in Ihrem zu machen OVERLAPPED Struktur und überprüfen Sie das Ereignis, um zu sehen, ob Daten verfügbar waren ... Ich habe keinen verfügbaren Code, der das tut.

Verwandte Themen