2013-08-13 6 views
5

सी ++ अपवाद COM मॉड्यूल सीमाओं को पार नहीं कर सकते हैं।सी ++ संभावित रूप से फेंकने वाले कोड COM विधि सीमाओं

तो, मान हम एक COM विधि शरीर में हैं, और कुछ सी ++ संभावित-फेंकने विधि/समारोह कहा जाता है (इस वजह से जैसे एसटीएल कक्षाएं उपयोग किया जाता है फेंक कर सकते हैं):

STDMETHODIMP CSomeComServer::DoSomething() 
{ 
    CppDoSomething(); // <--- This may throw C++ exceptions 
    return S_OK; 
} 

Q1। क्या उपरोक्त कोड एक व्यवहार्य कार्यान्वयन है? उदाहरण के लिए, यदि वह कोड संदर्भ मेनू खोल एक्सटेंशन का हिस्सा है, यदि C++ CppDoSomething() फ़ंक्शन एक C++ अपवाद फेंकता है, तो एक्सप्लोरर क्या करता है? क्या यह सी ++ अपवाद को पकड़ता है और खोल एक्सटेंशन को अनलोड करता है? क्या यह सिर्फ विफल-तेज दृष्टिकोण के बाद एक्सप्लोरर (क्रैश डंप का उपयोग करके समस्या का विश्लेषण करना संभव बनाता है)?

प्रश्न 2। क्या इस तरह का कार्यान्वयन बेहतर होगा?

STDMETHODIMP CSomeComServer::DoSomething() 
{ 
    // 
    // Wrap the potentially-throwing C++ code call in a safe try/catch block. 
    // C++ exceptions are caught and transformed to HRESULTs. 
    // 
    try 
    { 
     CppDoSomething(); // <--- This may throw C++ exceptions 
     return S_OK; 
    } 
    // 
    // Map C++ std::bad_alloc exception to E_OUTOFMEMORY HRESULT. 
    // 
    catch(const std::bad_alloc& ex) 
    { 
     // ... Log the exception what() message somewhere, 
     // e.g. using OutputDebugString(). 
     .... 
     return E_OUTOFMEMORY; 
    } 
    // 
    // Map C++ std::exception exception to generic E_FAIL. 
    // 
    catch(const std::exception& ex) 
    { 
     // ... Log the exception what() message somewhere, 
     // e.g. using OutputDebugString(). 
     .... 
     return E_FAIL; 
    } 
} 

क्यू 3। या यदि यह एक सर्वर में COM सर्वर डालने के लिए एक आंतरिक ध्वज (उदाहरण के लिए bool m_invalid डेटा सदस्य) सेट करने के लिए सी ++ अपवाद फेंक दिया गया है, तो यह बेहतर होगा, ताकि यह अब काम नहीं कर सके, इसलिए प्रत्येक लगातार कॉल इसकी विधि कुछ त्रुटि कोड देता है, जैसे E_FAIL या कुछ अन्य विशिष्ट त्रुटि?

क्यू 4। अंत में, यह मानते हुए कि Q2/Q3 अच्छे कार्यान्वयन दिशानिर्देश हैं, कुछ सुविधाजनक प्रीप्रोसेसर मैक्रोज़ में वर्बोज़ try/catch गार्ड को छिपाना संभव है (जिसे प्रत्येक COM विधि निकाय में पुन: उपयोग किया जा सकता है), उदा।

#define COM_EXCEPTION_GUARD_BEGIN try \ 
            { 

#define COM_EXCEPTION_GUARD_END return S_OK; \ 
            } \ 
            catch(const std::bad_alloc& ex) \ 
            { \ 
             .... \ 
             return E_OUTOFMEMORY; \ 
            } \ 
            catch(const std::exception& ex) \ 
            { \ 
             .... \ 
             return E_FAIL; \ 
            } 

// 
// May also add other mappings, like std::invalid_argument --> E_INVALIDARG ... 
// 

STDMETHODIMP CSomeComServer::DoSomething() 
{ 
    COM_EXCEPTION_GUARD_BEGIN 

    CppDoSomething(); // <--- This may throw C++ exceptions 

    COM_EXCEPTION_GUARD_END 
} 

STDMETHODIMP CSomeComServer::DoSomethingElse() 
{ 
    COM_EXCEPTION_GUARD_BEGIN 

    CppDoSomethingElse(); // <--- This may throw C++ exceptions 

    COM_EXCEPTION_GUARD_END 
} 

कुछ और के साथ ऊपर उल्लिखित पूर्वप्रक्रमक मैक्रो को बदलने के लिए आधुनिक सी ++ 11/14, यह संभव है का उपयोग करना, और अधिक सुविधाजनक है, और अधिक सुंदर, पहले से बेहतर हो?

+3

* कभी भी * COM सीमा में सी ++ अपवाद (या निकट-किसी अन्य प्रकार) को फेंक दें। यही है HRESULT के लिए है। यदि आप अधिक जानकारी चाहते हैं तो 'IErrorInfo' और' ISupportsErrorInfo' प्रतिमान पर विचार करें। अपने आखिरी स्निपेट में मैक्रोज़ के बारे में, यह आपके हिस्से पर एक डिज़ाइन निर्णय है, लेकिन एक तरफ या दूसरा, * COM सदस्य * से बाहर नहीं निकलता है। – WhozCraig

+0

@WhozCraig: यदि कोई C++ अपवाद (उदा। 'Std :: bad_alloc',' std :: invalid_argument', 'std :: runtime_error', ...) को "कोर" सी ++ कोड से फेंक दिया जाता है और COM विधि निकाय में 'try/catch' ब्लॉक में पकड़ा जाता है, क्या आप COM सर्वर को एक विशेष _ "अमान्य स्थिति" _ में डाल देंगे और अगली विधि कॉल विफल हो जाएंगे, या आप बस 'HRESULT' विफलता के अपवाद को मानचित्रित करेंगे और अपने ग्राहकों की सेवा जारी रखेंगे? –

+0

पकड़े गए अपवाद की गंभीरता केवल संदर्भ में मूल्यांकन की जा सकती है। चाहे यह COM सर्वर को एक अप्राप्य विफलता मोड में रखता है या प्रत्येक आमंत्रण के लिए निर्णय नहीं लिया जाना चाहिए। सी ++ अपवादों का उपयोग करते समय यह * मजबूत गारंटी * को लागू करने में अक्सर मददगार होता है, यानी एक ऑपरेशन या तो विफलता पर सभी क्षणिक राज्य संशोधनों को पूरा करने या रोल करने के लिए चलाता है। – IInspectable

उत्तर

2

अपवादों को कभी भी COM सीमा में फैलाने दें, अन्यथा व्यवहार अपरिभाषित है और इसमें आपके सी ++ रनटाइम terminate() को शामिल किया जा सकता है, प्रक्रिया नट्स और अन्य अच्छे बोनस जा रही है। बस यह मत करो। यहां तक ​​कि अगर आपने कुछ विन्यास में इसे "परीक्षण" किया है - यह अभी भी अपरिभाषित व्यवहार है और चुपचाप तोड़ने के लिए मामूली वातावरण या कार्यान्वयन में परिवर्तन होना चाहिए।

आपको सभी सी ++ अपवादों को HRESULT एस में पकड़ना और अनुवाद करना चाहिए और वैकल्पिक रूप से विवरण के साथ IErrorInfo सेट करना चाहिए। आप प्रत्येक COM सर्वर विधि कार्यान्वयन को लपेटने वाले मैक्रोज़ या हर जगह इस कोड को कॉपी-पेस्ट करके ऐसा कर सकते हैं - अनुमान लगाएं कि अधिक रखरखाव योग्य है।

सर्वर को "अमान्य" स्थिति में चलाने के विचार को कुछ चरम स्थितियों में समझ में आ सकता है लेकिन मैं इस समय उनकी कल्पना नहीं कर सकता। मुझे लगता है कि यह एक सार्वभौमिक समाधान नहीं है। सामान्य मामलों में यदि आपके पास अपवाद सुरक्षित कोड है तो आपको इसकी आवश्यकता नहीं होनी चाहिए।

+0

यहां एक दिलचस्प पठन है: [** अपवाद हैंडलर को कैसे बंद करें कि COM "मददगार" आपके सर्वर के चारों ओर लपेटता है **] (http://blogs.msdn.com/b/oldnewthing/archive/2011/01/ 20/10117963.aspx); एक _fail fast_ दृष्टिकोण की तरह लगता है। –

+0

@ श्री सी 64: नहीं, यह एक और बात है, यह केवल संरचित अपवादों के लिए है, सी ++ अपवादों के लिए नहीं - बाद वाला केवल 'समाप्त()' कहलाएगा। – sharptooth

+0

मुझे यकीन नहीं है कि आप सही हैं ... पर विचार करें: _ "दूसरी ओर एक 'nonfatal' अपवाद सी ++ अपवाद या सीएलआर अपवाद की तरह कुछ है। शायद आप अपने सर्वर को क्रैश करने के लिए एक अनचाहे C++ या CLR अपवाद चाहते हैं , भी, यह आपके प्रोग्राम को क्रैश कर देगा यदि यह सर्वर के रूप में नहीं चल रहा था। इसलिए, जब भी संभव हो, तो मेरी व्यक्तिगत सिफारिश COMGLB_EXCEPTION_DONOT_HANDLE_ANY का उपयोग करना है। "_ –

संबंधित मुद्दे