Ngoại lệ C++ không thể vượt qua ranh giới mô-đun COM.C++ mã có khả năng ném tại ranh giới phương thức COM
Vì vậy, giả sử chúng ta đang ở trong một cơ thể phương pháp COM, và một số C++ có khả năng ném phương pháp/hàm được gọi (điều này có thể ném vì các lớp học như STL được sử dụng):
STDMETHODIMP CSomeComServer::DoSomething()
{
CppDoSomething(); // <--- This may throw C++ exceptions
return S_OK;
}
Q1. Đoạn mã trên có thực hiện khả thi không? Ví dụ: nếu mã đó là một phần của tiện ích mở rộng trình đơn ngữ cảnh, nếu hàm C++ CppDoSomething()
ném ngoại lệ C++, Explorer sẽ làm gì? Nó có bắt được ngoại lệ C++ và dỡ bỏ phần mở rộng của shell không? Có phải nó chỉ gặp sự cố Explorer (làm cho nó có thể phân tích vấn đề bằng cách sử dụng một bãi chứa sự cố) theo cách tiếp cận không không nhanh chóng?
Q2. Việc triển khai như thế có tốt hơn không?
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;
}
}
Q3. Hoặc sẽ tốt hơn, nếu ngoại lệ C++ được ném, chỉ cần đặt cờ nội bộ (ví dụ: thành viên dữ liệu bool m_invalid
) để đặt máy chủ COM ở trạng thái sao cho không thể hoạt động nữa, vì vậy mọi cuộc gọi liên tiếp đến phương thức của nó trả về một số mã lỗi, chẳng hạn như E_FAIL
hoặc một số lỗi cụ thể khác?
Q4. Cuối cùng, giả sử Q2/Q3 là hướng dẫn triển khai tốt, có thể ẩn bảo vệ chi tiết try/catch
trong một số macro tiền xử lý thuận tiện (có thể được sử dụng lại trong mọi phương thức COM), ví dụ:
#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
}
Sử dụng C++ 11/14 hiện đại, có thể thay thế macro tiền xử lý nói trên bằng một thứ khác, thuận tiện hơn, thanh lịch hơn, tốt hơn không?
* Không bao giờ * ném ngoại lệ C++ (hoặc gần bất kỳ loại nào khác) qua ranh giới COM. Đó là những gì mà HRESULT dành cho. Nếu bạn muốn biết thêm thông tin, hãy xem xét mô hình 'IErrorInfo' và' ISupportsErrorInfo'. Về các macro trong đoạn trích cuối cùng của bạn, đó là quyết định thiết kế về phía bạn, nhưng theo cách này hay cách khác, * không được ném ra khỏi thành viên COM *. – WhozCraig
@WhozCraig: Nếu ngoại lệ C++ (ví dụ: 'std :: bad_alloc',' std :: invalid_argument', 'std :: runtime_error', ...) được ném từ mã "C++" cốt lõi và được bắt trong khối 'try/catch' trong thân phương thức COM, bạn sẽ đặt máy chủ COM trong một _" trạng thái không hợp lệ "_ đặc biệt và thực hiện các cuộc gọi phương thức tiếp theo không thành công, hoặc bạn sẽ chỉ vẽ bản đồ ngoại lệ cho một thất bại 'HRESULT' và tiếp tục phục vụ khách hàng của bạn? –
Mức độ nghiêm trọng của ngoại lệ bị bắt chỉ có thể được đánh giá theo ngữ cảnh. Cho dù điều này đặt máy chủ COM vào một chế độ thất bại không thể phục hồi hoặc không phải được quyết định cho mỗi lời gọi. Khi sử dụng ngoại lệ C++, thường hữu ích khi triển khai * bảo đảm mạnh mẽ *, tức là một thao tác chạy hoặc hoàn thành hoặc cuộn lại tất cả các sửa đổi trạng thái tạm thời về lỗi. – IInspectable