विंडोज सी ++: fprintf पर कॉल के लिए मैं stderr को कैसे रीडायरेक्ट कर सकता हूं?

मैं मौजूदा सी ++ कोड को अपने स्वयं के कस्टम रैपर में बीएसडी प्रोजेक्ट से लपेट रहा हूं और मैं इसे जितना संभव हो उतना परिवर्तन के साथ हमारे कोड में एकीकृत करना चाहता हूं। त्रुटियों को लॉग/रिपोर्ट करने के लिए यह कोड stderr पर प्रिंट करने के लिए fprintf का उपयोग करता है।

मैं इसे एक ही प्रक्रिया में एक वैकल्पिक स्थान पर रीडायरेक्ट करना चाहता हूं। यूनिक्स पर मैंने इसे सॉकेटपेयर और thread के साथ किया है: सॉकेट का एक छोर है जहां मैं stderr (एक कॉल के माध्यम से dup2 ) और दूसरी छोर पर एक थ्रेड में निगरानी की जाती है, जहां मैं आउटपुट को संसाधित कर सकता हूं।

यह Windows पर काम नहीं करता है, हालांकि सॉकेट फ़ाइल संभाल के समान नहीं है।

वेब पर मिले सभी दस्तावेज दिखाते हैं कि बाल प्रक्रिया से आउटपुट को रीडायरेक्ट कैसे करें, जो मैं नहीं चाहता हूं। आउटपुट लिखे जाने पर मैं किसी प्रकार की कॉलबैक प्राप्त करने के समान प्रक्रिया में stderr को पुनर्निर्देशित कैसे कर सकता हूं? (और इससे पहले कि आप ऐसा कहें, मैंने SetStdHandle को आजमाया है लेकिन यह काम करने के लिए कोई रास्ता नहीं मिल रहा है) ...

0
ro fr bn

3 उत्तर

आप विंडोज पर एक समान तकनीक का उपयोग कर सकते हैं, आपको बस एक ही अवधारणाओं के लिए अलग-अलग शब्दों का उपयोग करने की आवश्यकता है। :) यह आलेख: http://msdn.microsoft.com/en-us/ लाइब्रेरी/ms682499.aspx किसी अन्य प्रक्रिया से I/O को संभालने के लिए Win32 पाइप का उपयोग करता है, आपको केवल उसी प्रक्रिया में थ्रेड के साथ एक ही चीज़ करना है। बेशक, आपके मामले में प्रक्रिया में कहीं से भी 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;
}   

इस मामले में, मुख्य प्रक्रिया एक जीयूआई प्रक्रिया थी जो स्टडीओ हैंडल से बिल्कुल शुरू नहीं होती है। यह एक कंसोल खोलता है, फिर दाहिने हैंडल को stdout और stdin में डालता है ताकि डीबग() फ़ंक्शन (जो एक स्टडीओ इंटरैक्टिव फ़ंक्शन के रूप में डिज़ाइन किया गया हो) नव निर्मित कंसोल के साथ बातचीत कर सकता है। आप कुछ पाइप खोलने और stderr को पुनर्निर्देशित करने के लिए एक ही तरह की चीज करने में सक्षम होना चाहिए।

0
जोड़ा

आपको याद रखना होगा कि एमएसवीसीआरटी क्या कहता है "ओएस हैंडल" Win32 हैंडल नहीं हैं, लेकिन हैंडल की एक और परत आपको उलझाने के लिए जोड़ती है। एमएसवीसीआरटी यूनिक्स हैंडल नंबरों का अनुकरण करने की कोशिश करता है जहां stdin = 0, stdout = 1, stderr = 2 और इसी तरह से। Win32 हैंडल को अलग-अलग गिना जाता है और उनके मान हमेशा 4 के बहु होते हैं। पाइप खोलना और सभी हैंडल को ठीक से कॉन्फ़िगर करना आपके हाथों को गन्दा करने की आवश्यकता होगी। एमएसवीसीआरटी स्रोत कोड और डीबगर का उपयोग करना शायद एक आवश्यकता है।

0
जोड़ा

आप उल्लेख करते हैं कि आप आंतरिक उपयोग के लिए नामित पाइप का उपयोग नहीं करना चाहते हैं; संभवत: यह जानने के लायक है कि CreatePipe() राज्यों, "अज्ञात पाइप को एक अद्वितीय नाम के साथ एक नामित पाइप का उपयोग करके कार्यान्वित किया जाता है। इसलिए, आप किसी फ़ंक्शन को एक अज्ञात पाइप पर एक हैंडल पास कर सकते हैं जिसके लिए किसी नामित पाइप को हैंडल की आवश्यकता होती है।" तो, मेरा सुझाव है कि आप केवल एक ऐसा फ़ंक्शन लिखें जो एसिंक पढ़ने के लिए सही सेटिंग्स के साथ एक समान पाइप बनाता है। मुझे एक अद्वितीय नाम देने के लिए एक GUID का उपयोग करना होता है (मुझे CoCreateGUID() और StringFromIID() का उपयोग करके जेनरेट किया जाता है) और उसके बाद सर्वर और क्लाइंट सिरों को बनाते हैं ओवरलैप I/O के लिए सही सेटिंग्स के साथ नामित पाइप (इस पर अधिक जानकारी, और कोड, यहां: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html )।

एक बार मेरे पास यह है कि मैं कुछ कोड तार करता हूं कि मुझे एक I/O प्राप्ति पोर्ट के साथ ओवरलैप्ड I/O का उपयोग करके फ़ाइल पढ़नी है और, ठीक है, तो मुझे डेटा की एसिंक सूचनाएं मिलती हैं जैसे कि यह आता है ... हालांकि, मैं वहां एक अच्छी तरह से अच्छी तरह से परीक्षण पुस्तकालय कोड मिला है जो इसे सब कुछ करता है ...

नामित पाइप सेट करना शायद संभव है और फिर अपने ओवरलैप्ड संरचना में किसी ईवेंट के साथ ओवरलैप्ड रीड करें और यह देखने के लिए ईवेंट जांचें कि डेटा उपलब्ध था या नहीं ... मेरे पास कोई कोड नहीं है उपलब्ध है कि हालांकि यह करता है।

0
जोड़ा