Windows C++: Bagaimana cara mengarahkan stderr untuk panggilan ke fprintf?

Saya membungkus kode C++ yang ada dari proyek BSD dalam pembungkus khusus kami sendiri dan saya ingin mengintegrasikannya ke kode kami dengan perubahan sesedikit mungkin. Kode ini menggunakan fprintf untuk mencetak ke stderr untuk mencatat/melaporkan kesalahan.

Saya ingin mengarahkan ini ke tempat alternatif dalam proses yang sama. Di Unix saya telah melakukan ini dengan socketpair dan thread: salah satu ujung soket adalah tempat saya mengirim stderr (melalui panggilan ke dup2) dan ujung lainnya dipantau di utas, tempat saya kemudian dapat memproses hasilnya.

Ini tidak berfungsi pada Windows karena soket tidak sama dengan pegangan file.

Semua dokumen yang saya temukan di web menunjukkan cara mengalihkan keluaran dari proses anak, yang bukan itu yang saya inginkan. Bagaimana saya bisa mengalihkan stderr dalam proses yang sama untuk mendapatkan semacam panggilan balik ketika keluaran ditulis? (dan sebelum Anda mengatakannya, saya sudah mencoba SetStdHandle tetapi tidak dapat menemukan cara untuk membuat ini berhasil)...


person jkp    schedule 11.08.2008    source sumber


Jawaban (3)


Anda dapat menggunakan teknik serupa di Windows, Anda hanya perlu menggunakan kata yang berbeda untuk konsep yang sama. :) Artikel ini: http://msdn.microsoft.com/en-us/library/ms682499.aspx menggunakan pipa win32 untuk menangani I/O dari proses lain, Anda hanya perlu melakukan hal yang sama dengan thread dalam proses yang sama. Tentu saja, dalam kasus Anda, semua keluaran ke stderr dari mana saja dalam proses akan dialihkan ke konsumen Anda.

Sebenarnya, potongan teka-teki lain yang mungkin Anda perlukan adalah _fdopen dan _open_osfhandle. Sebenarnya, inilah contoh terkait dari beberapa kode yang saya rilis beberapa tahun lalu:

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

Dalam hal ini, proses utama adalah proses GUI yang tidak dimulai dengan pegangan stdio sama sekali. Ini membuka konsol, lalu memasukkan pegangan kanan ke stdout dan stdin sehingga fungsi debug() (yang dirancang sebagai fungsi interaktif stdio) dapat berinteraksi dengan konsol yang baru dibuat. Anda seharusnya dapat membuka beberapa pipa dan melakukan hal yang sama untuk mengarahkan ulang stderr.

person Greg Hewgill    schedule 11.08.2008

Anda harus ingat bahwa apa yang disebut MSVCRT sebagai "pegangan OS" bukanlah pegangan Win32, tetapi lapisan pegangan lain yang ditambahkan hanya untuk membingungkan Anda. MSVCRT mencoba meniru nomor pegangan Unix di mana stdin = 0, stdout = 1, stderr = 2 dan seterusnya. Pegangan Win32 diberi nomor berbeda dan nilainya selalu kelipatan 4. Membuka pipa dan mengonfigurasi semua pegangan dengan benar akan membuat tangan Anda berantakan. Menggunakan kode sumber MSVCRT dan debugger mungkin merupakan suatu persyaratan.

person Greg Hewgill    schedule 11.08.2008

Anda menyebutkan bahwa Anda tidak ingin menggunakan pipa bernama untuk penggunaan internal; mungkin perlu diperhatikan bahwa dokumentasi untuk CreatePipe() menyatakan, "Pipa anonim diimplementasikan menggunakan pipa bernama dengan nama yang unik. Oleh karena itu, Anda sering kali dapat meneruskan pegangan ke pipa anonim ke fungsi yang memerlukan pegangan ke pipa bernama." Jadi, saya sarankan Anda menulis saja fungsi yang membuat pipa serupa dengan pengaturan yang benar untuk pembacaan async. Saya cenderung menggunakan GUID sebagai string (dihasilkan menggunakan CoCreateGUID() dan StringFromIID()) untuk memberi saya nama unik dan kemudian membuat ujung server dan klien dari pipa bernama dengan pengaturan yang benar untuk I/O yang tumpang tindih (detail lebih lanjut tentang ini, dan kode, di sini: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html).

Setelah saya memilikinya, saya memasang beberapa kode yang harus saya baca file menggunakan I/O yang tumpang tindih dengan Port Penyelesaian I/O dan, kemudian saya hanya mendapat pemberitahuan asinkron dari data yang tiba... Namun, saya Ada cukup banyak kode perpustakaan yang teruji dengan baik di sana yang membuat semuanya terjadi...

Mungkin saja untuk mengatur pipa bernama dan kemudian melakukan pembacaan yang tumpang tindih dengan suatu peristiwa di struktur OVERLAPPED Anda dan memeriksa peristiwa tersebut untuk melihat apakah data tersedia... Saya tidak memiliki kode apa pun yang tersedia untuk melakukan itu.

person Len Holgate    schedule 16.09.2008