Wyjątki C++ nie mogą przekraczać granic modułu COM.C++ potencjalnie rzucający kod na granicy metody COM
Więc załóżmy jesteśmy w ciele metody COM, a niektóre C++ potencjalnie rzucających metoda/funkcja nazywa się (może to rzucić, ponieważ wykorzystywane są zajęcia np STL):
STDMETHODIMP CSomeComServer::DoSomething()
{
CppDoSomething(); // <--- This may throw C++ exceptions
return S_OK;
}
Q1. Czy powyższy kod jest wykonalną wersją? Na przykład, jeśli ten kod jest częścią rozszerzenia powłoki menu kontekstowego, jeśli funkcja C++ CppDoSomething()
zgłasza wyjątek C++, co robi Eksplorator? Czy przechwytuje wyjątek C++ i rozładowuje rozszerzenie powłoki? Czy to po prostu awarię Eksploratora (umożliwia analizę problemu za pomocą zrzutu awaryjnego) po fail-szybko podejście fail?
Q2. Czy taka implementacja byłaby lepsza?
Q3. A może byłoby nawet lepiej, gdyby został zgłoszony wyjątek C++, aby ustawić flagę wewnętrzną (np. Element danych bool m_invalid
), aby serwer COM był w stanie, który nie będzie już działał, a więc każde kolejne wywołanie do jego metoda zwraca kod błędu, np. E_FAIL
lub inny konkretny błąd?
Q4. Na koniec, zakładając, że Q2/Q3 są dobrymi wytycznymi implementacyjnymi, możliwe jest ukrycie pełnej osłony prekomputerowej try/catch
(która może być ponownie użyta w każdym korpusie metody COM), np.
#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
}
Stosując nowoczesne C++ 11/14, możliwe jest zastąpienie wspomnianych makr preprocesora z czegoś innego, wygodniejsze, bardziej elegancki, po prostu lepiej?
* Nigdy * nie rzucaj wyjątków C++ (lub prawie żadnego innego typu) przez granicę COM. Do tego właśnie służy HRESULT. Jeśli chcesz więcej informacji, weź pod uwagę paradygmat 'IErrorInfo' i' ISupportsErrorInfo'. Jeśli chodzi o makra zawarte w twoim ostatnim fragmencie, to decyzja o wyborze z Twojej strony, ale w ten czy inny sposób * nie wyrzucaj członka COM *. – WhozCraig
@WhozCraig: Jeśli wyjątek C++ (np. 'Std :: bad_alloc',' std :: invalid_argument', 'std :: runtime_error', ...) jest wyrzucany z "core" kodu C++ i jest przechwytywany w bloku 'try/catch' w ciele metody COM, czy umieściłbyś serwer COM w specjalnym _" stanie niepoprawnym "_ i sprawiłby, że następna metoda nie zadziała, czy po prostu zamapowałbyś wyjątek na błąd 'HRESULT' i kontynuowałeś obsługę swoich klientów? –
Nasilenie złapanego wyjątku można ocenić tylko w kontekście. Niezależnie od tego, czy serwer COM będzie stanowił nieodwracalny tryb awaryjny, czy nie, należy wybrać dla każdego wywołania. Podczas korzystania z wyjątków C++ często pomocne jest zastosowanie * silnej gwarancji *, tzn. Operacja albo kończy się, albo wycofuje wszystkie przejściowe modyfikacje stanu w przypadku niepowodzenia. – IInspectable