2013-08-13 4 views
5

C++ 예외는 COM 모듈 경계를 통과 할 수 없습니다.COM 메서드 경계에서 잠재적으로 throw하는 C++ 코드

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

:

그래서, 우리는 COM 방법 본체에 있고,라고 일부 C++ 잠재적으로 던지는 방법/기능 (예 : STL 클래스가 사용되기 때문에이 던질 수) 가정 Q1. 위의 코드는 실행 가능한 구현입니까? 예를 들어, 해당 코드가 컨텍스트 메뉴 셸 확장의 일부인 경우 C++ CppDoSomething() 함수가 C++ 예외를 throw하면 Explorer는 무엇을합니까? C++ 예외를 잡아서 셸 확장을 언로드합니까? 오류 빠른 접근 방식을 따르는 Explorer (크래시 덤프를 사용하여 문제를 분석하는 것이 가능함)가 작동하지 않습니까?

질문 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. 또는 C++ 예외가 발생하면 더 이상 작동하지 않을 수있는 상태로 COM 서버를 배치하기 위해 내부 플래그 (예 : bool m_invalid 데이터 멤버)를 설정하는 것이 더 좋을 것입니다. 따라서 모든 연속 호출은 해당 메서드는 E_FAIL 또는 다른 특정 오류 같은 일부 오류 코드를 반환합니까?

4. 마지막으로, Q2/Q3이 좋은 구현 가이드 라인이라고 가정하면 편리한 전 처리기 매크로 (모든 COM 메서드 본문에서 다시 사용할 수 있음)에서 자세한 정보 try/catch을 숨길 수 있습니다.

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

다른 뭔가 상기 전처리 매크로를 대체하는 현대 C++ 14분의 11, 그것은 수를 사용하여, 더 편리하고, 더 우아하고, 더 좋아?

+3

* COM 경계에서 C++ 예외 (또는 거의 다른 유형)를 throw하지 마십시오. HRESULT가 그 것이다. 더 많은 정보를 원한다면'IErrorInfo'와'ISupportsErrorInfo' 패러다임을 고려하십시오. 마지막 스 니펫의 매크로에 관해서는, 당신의 부분에 대한 디자인 결정이지만, 한 가지 또는 다른 것이 COM 멤버를 버리지는 않습니다 *. – WhozCraig

+0

@WhozCraig : C++ 예외 (예 :'std :: bad_alloc','std :: invalid_argument','std :: runtime_error', ...) "핵심"C + + 코드에서 던져 질 및 COM 메서드 본문에서'try/catch' 블록에 걸린 경우 COM 서버를 특별한 _ "잘못된 상태"_에 넣고 다음 메서드 호출을 실패하게 만들겠습니까? 아니면 예외를 오류'HRESULT'에 매핑하고 고객 서비스를 계속 하시겠습니까? –

+0

catch 된 예외의 심각도는 상황에 대해서만 평가할 수 있습니다. 이렇게하면 COM 서버를 복구 할 수없는 오류 모드로 만들지 여부를 각 호출에 대해 결정해야합니다. C++ 예외를 사용할 때 * 강력한 보증 *을 구현하는 것이 도움이됩니다. 즉, 작업이 완료 될 때 실행되거나 실패시 모든 일시적인 상태 수정을 롤백합니다. – IInspectable

답변

2

예외가 COM 경계를 넘어 전파되지 않도록하십시오. 그렇지 않으면 동작이 정의되지 않으며 호출되는 C++ 런타임 terminate(), 프로세스 진행 및 기타 좋은 보너스가 포함될 수 있습니다. 그냥하지 마. 일부 구성에서 "테스트 한"경우에도 여전히 정의되지 않은 동작이므로 사소한 환경이나 구현 변경이 발생하면 자동으로 중단됩니다.

당신은 잡아 HRESULT들에 모든 C++ 예외를 번역하고 선택적으로 세부 IErrorInfo을 설정해야합니다. 각 COM 서버 메서드 구현을 래핑하는 매크로를 사용하거나이 코드를 모든 곳에서 복사하여 붙여 넣을 수 있습니다. 어느 것이 더 유지 관리가 가능한지 추측 할 수 있습니다.

서버를 "유효하지 않은"상태로 만드는 아이디어는 일부 극단적 인 상황에서는 의미가있을 수 있지만 지금은 상상할 수 없습니다. 범용 솔루션이 아닌 것 같습니다. 일반적인 경우 예외 안전 코드가있는 경우이 코드는 전혀 필요하지 않습니다.

+0

흥미로운 내용은 다음과 같습니다. [** COM이 "유용하게"서버를 둘러싼 예외 처리기를 끄는 방법 **] (http://blogs.msdn.com/b/oldnewthing/archive/2011/01/) 20/10117963.aspx); _fail 빠른 접근처럼 보인다. –

+0

@ Mr.C64 : 아니요, 또 다른 문제입니다. C++ 예외가 아니라 구조화 된 예외에만 적용됩니다. 후자는 'terminate()'가 호출되도록합니다. – sharptooth

+0

당신이 옳은지 잘 모르겠습니다 ... 고려 : _ "반면에 '치명적이지 않은'예외는 C++ 예외 또는 CLR 예외와 비슷합니다. 처리되지 않은 C++ 또는 CLR 예외로 인해 서버가 중단되기를 원할 수도 있습니다 또한, 서버로 실행되지 않으면 프로그램을 중단시킬 수 있으므로 가능한 한 COMGLB_EXCEPTION_DONOT_HANDLE_ANY를 사용하는 것이 좋습니다. "_ –