Windows C ++: ฉันจะเปลี่ยนเส้นทาง stderr เพื่อโทรไปที่ fprintf ได้อย่างไร

ฉันกำลังรวมโค้ด C++ ที่มีอยู่จากโปรเจ็กต์ BSD ใน Wrapper ที่เรากำหนดเอง และฉันต้องการรวมเข้ากับโค้ดของเราโดยมีการเปลี่ยนแปลงน้อยที่สุด รหัสนี้ใช้ fprintf เพื่อพิมพ์ไปที่ stderr เพื่อบันทึก / รายงานข้อผิดพลาด

ฉันต้องการเปลี่ยนเส้นทางนี้ไปยังสถานที่อื่นภายในกระบวนการเดียวกัน บน Unix ฉันทำสิ่งนี้ด้วย socketpair และ thread: ปลายด้านหนึ่งของซ็อกเก็ตคือที่ที่ฉันส่ง stderr (ผ่านการเรียกไปที่ dup2) และปลายอีกด้านหนึ่งได้รับการตรวจสอบ ในเธรด ซึ่งฉันสามารถประมวลผลเอาต์พุตได้

สิ่งนี้ใช้ไม่ได้กับ Windows เนื่องจากซ็อกเก็ตไม่เหมือนกับตัวจัดการไฟล์

เอกสารทั้งหมดที่ฉันพบบนเว็บแสดงวิธีเปลี่ยนเส้นทางเอาต์พุตจากกระบวนการย่อย ซึ่งไม่ใช่สิ่งที่ฉันต้องการ ฉันจะเปลี่ยนเส้นทาง stderr ภายในกระบวนการเดียวกันเพื่อรับการเรียกกลับบางประเภทเมื่อมีการเขียนเอาต์พุตได้อย่างไร (และก่อนที่คุณจะพูดอย่างนั้น ฉันได้ลอง SetStdHandle แล้ว แต่ไม่พบวิธีใดที่จะทำให้งานนี้สำเร็จได้)...


person jkp    schedule 11.08.2008    source แหล่งที่มา


คำตอบ (3)


คุณสามารถใช้เทคนิคที่คล้ายกันบน Windows คุณเพียงแค่ต้องใช้คำที่แตกต่างกันสำหรับแนวคิดเดียวกัน :) บทความนี้: http://msdn.microsoft.com/en-us/library/ms682499.aspx ใช้ไปป์ win32 เพื่อจัดการ I/O จากกระบวนการอื่น คุณเพียงแค่ต้องทำสิ่งเดียวกันกับเธรดที่อยู่ในกระบวนการเดียวกัน แน่นอนในกรณีของคุณเอาต์พุตทั้งหมดไปยัง stderr จากทุกที่ในกระบวนการจะถูกเปลี่ยนเส้นทางไปยังผู้บริโภคของคุณ

จริงๆ แล้ว ชิ้นส่วนอื่นๆ ของปริศนาที่คุณอาจต้องการคือ _fdopen และ _open_osfhandle อันที่จริง นี่คือตัวอย่างที่เกี่ยวข้องจาก โค้ด บางส่วนที่ฉันเผยแพร่เมื่อหลายปีก่อน:

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

ในกรณีนี้ กระบวนการหลักคือกระบวนการ GUI ซึ่งไม่ได้ขึ้นต้นด้วย stdio handle เลย โดยจะเปิดคอนโซล จากนั้นดันที่จับด้านขวาเข้าไปใน stdout และ stdin เพื่อให้ฟังก์ชัน debug() (ซึ่งได้รับการออกแบบให้เป็นฟังก์ชันโต้ตอบ stdio) สามารถโต้ตอบกับคอนโซลที่สร้างขึ้นใหม่ได้ คุณควรจะสามารถเปิดบางไพพ์และทำสิ่งเดียวกันเพื่อเปลี่ยนเส้นทาง stderr

person Greg Hewgill    schedule 11.08.2008

คุณต้องจำไว้ว่าสิ่งที่ MSVCRT เรียกว่า "ตัวจัดการ OS" ไม่ใช่ตัวจัดการ Win32 แต่มีตัวจัดการอีกชั้นหนึ่งที่เพิ่มเข้ามาเพื่อให้คุณสับสน MSVCRT พยายามจำลองหมายเลขอ้างอิง Unix โดยที่ stdin = 0, stdout = 1, stderr = 2 และอื่น ๆ หมายเลขอ้างอิง Win32 นั้นมีหมายเลขแตกต่างกันและค่าของมันมักจะเป็นทวีคูณของ 4 เสมอ การเปิดไปป์และการกำหนดค่าหมายเลขอ้างอิงทั้งหมดอย่างถูกต้องจะทำให้มือของคุณยุ่ง การใช้ซอร์สโค้ด MSVCRT และดีบักเกอร์อาจเป็นข้อกำหนด

person Greg Hewgill    schedule 11.08.2008

คุณพูดถึงว่าคุณไม่ต้องการใช้ไปป์ที่มีชื่อสำหรับใช้ภายใน มันอาจจะคุ้มค่าที่จะชี้ให้เห็นว่าเอกสารสำหรับ CreatePipe() ระบุว่า "ไปป์ที่ไม่ระบุชื่อถูกนำมาใช้โดยใช้ไปป์ที่มีชื่อซึ่งมีชื่อเฉพาะ ดังนั้น คุณมักจะสามารถส่งผ่านตัวจัดการไปยังไปป์ที่ไม่ระบุชื่อไปยังฟังก์ชันที่ต้องใช้ตัวจัดการไปยังไปป์ที่มีชื่อ" ดังนั้น ฉันขอแนะนำให้คุณเขียนฟังก์ชันที่สร้างไปป์ที่คล้ายกันโดยมีการตั้งค่าที่ถูกต้องสำหรับการอ่านแบบอะซิงก์ ฉันมักจะใช้ GUID เป็นสตริง (สร้างโดยใช้ CoCreateGUID() และ StringFromIID()) เพื่อให้ชื่อที่ไม่ซ้ำแก่ฉัน จากนั้นสร้างเซิร์ฟเวอร์และไคลเอนต์สิ้นสุดของไปป์ที่มีชื่อด้วยการตั้งค่าที่ถูกต้องสำหรับ I/O ที่ทับซ้อนกัน (รายละเอียดเพิ่มเติมเกี่ยวกับเรื่องนี้ และ รหัส ที่นี่: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html)

เมื่อฉันได้สิ่งนั้นแล้ว ฉันเชื่อมโยงโค้ดบางส่วนที่ฉันต้องอ่านไฟล์โดยใช้ I/O ที่ทับซ้อนกันกับพอร์ต I/O Completion จากนั้นฉันก็ได้รับการแจ้งเตือนแบบอะซิงก์ของข้อมูลเมื่อมาถึง... อย่างไรก็ตาม ฉัน มีโค้ดไลบรารีที่ได้รับการทดสอบอย่างดีจำนวนพอสมควรซึ่งทำให้ทุกอย่างเกิดขึ้น...

อาจเป็นไปได้ที่จะตั้งค่าไปป์ที่มีชื่อ จากนั้นเพียงอ่านทับซ้อนกับเหตุการณ์ในโครงสร้าง OVERLAPPED ของคุณ และตรวจสอบเหตุการณ์เพื่อดูว่ามีข้อมูลหรือไม่... ฉันไม่มีรหัสใด ๆ ที่สามารถทำเช่นนั้นได้

person Len Holgate    schedule 16.09.2008