2008-08-11 18 views
5

Pakuję istniejący kod C++ z projektu BSD w naszym własnym niestandardowym opakowaniu i chcę go zintegrować z naszym kodem przy jak najmniejszej ilości zmian. Ten kod używa fprintf do drukowania na stderr w celu rejestrowania/zgłaszania błędów.Windows C++: Jak mogę przekierować stderr dla połączeń z fprintf?

Chcę przekierować to do alternatywnego miejsca w ramach tego samego procesu. Na Unixie zrobiłem to z parą gniazd i wątkiem: jeden koniec gniazda to miejsce, w którym wysyłam stderr (przez połączenie z dup2), a drugi koniec jest monitorowany w wątku, gdzie mogę następnie przetwarzać dane wyjściowe.

To nie działa w oknach, ponieważ gniazdo nie jest tym samym, co uchwyt pliku.

Wszystkie dokumenty znalezione w Internecie pokazują, jak przekierować dane wyjściowe z procesu potomnego, co nie jest tym, czego chcę. Jak mogę przekierować stderr w ramach tego samego procesu uzyskiwania wywołania zwrotnego pewnego rodzaju, gdy dane wyjściowe są zapisywane? (i zanim to powiesz, próbowałem SetStdHandle, ale nie mogę znaleźć żadnego sposobu, aby to zrobić) ...

Odpowiedz

6

Możesz użyć podobnej techniki w systemie Windows, po prostu trzeba użyć różnych słów dla tych samych pojęć. :) Ten artykuł: http://msdn.microsoft.com/en-us/library/ms682499.aspx używa rury win32 do obsługi operacji wejścia/wyjścia z innego procesu, po prostu musisz zrobić to samo z wątkami w ramach tego samego procesu. Oczywiście w twoim przypadku wszystkie wyjścia do stderr z dowolnego miejsca procesu zostaną przekierowane do twojego klienta.

W rzeczywistości, inne elementy układanki, które mogą być potrzebne, to: _fdopen i _open_osfhandle. W rzeczywistości, oto przykład powiązany z jakimś code wydałem lat temu:

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

W tym przypadku głównym procesem był proces GUI, który nie zaczyna się stdio uchwyty w ogóle. Otwiera konsolę, a następnie przesuwa prawe uchwyty na standardowe wyjście i stdin, dzięki czemu funkcja debug (która została zaprojektowana jako interaktywna funkcja stdio) może wchodzić w interakcje z nowo utworzoną konsolą. Powinieneś być w stanie otworzyć kilka potoków i zrobić to samo, aby przekierować stderr.

3

Należy pamiętać, że to, co MSVCRT nazywa "obsługą systemu operacyjnego", nie jest uchwytami Win32, ale kolejna warstwa uchwytów dodana tylko po to, by wprowadzić użytkownika w błąd. MSVCRT próbuje emulować numery uchwytów Uniksa, gdzie stdin = 0, stdout = 1, stderr = 2 i tak dalej. Uchwyty Win32 są ponumerowane w różny sposób, a ich wartości zawsze są wielokrotnością 4. Otwarcie rury i prawidłowe skonfigurowanie uchwytów będzie wymagało zabrudzenia rąk. Korzystanie z kodu źródłowego MSVCRT i debuggera jest prawdopodobnie wymogiem.

1

Podkreślasz, że nie chcesz używać nazwanego potoku do użytku wewnętrznego; prawdopodobnie warto poinstruować, że dokumentacja dla CreatePipe() stwierdza, "Anonimowe rury są implementowane za pomocą nazwanego potoku o unikalnej nazwie, dlatego często można przekazać uchwyt anonimowej potoku do funkcji wymagającej uchwytu do nazwanego potoku . " Proponuję więc napisać funkcję, która tworzy podobną rurę z poprawnymi ustawieniami asynchronicznego czytania. Zwykle używam identyfikatora GUID jako ciągu znaków (generowanego przy użyciu CoCreateGUID() i StringFromIID()), aby nadać mi unikalną nazwę, a następnie utworzyć końce serwera i klienta nazwanego potoku z poprawnymi ustawieniami dla nakładających się we/wy (więcej szczegółów na ten temat i kod, tutaj: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html).

Kiedy już to mam, podłączam kod, że muszę odczytać plik za pomocą nakładających się wejść/wyjść z portem I/O Completion Port i, no cóż, po prostu dostaję asynchroniczne powiadomienia o danych po ich nadejściu. Jednak mam tu sporo dobrze przetestowanego kodu biblioteki, który sprawia, że ​​wszystko się stało ...

Prawdopodobnie można ustawić nazwaną potokę, a następnie po prostu zrobić nałożony tekst na wydarzenie OVERLAPPED struktury i sprawdź zdarzenie, aby zobaczyć, czy dane były dostępne ... Nie mam jednak żadnego dostępnego kodu, który to robi.

Powiązane problemy