{"id":109271,"date":"2024-01-15T07:00:00","date_gmt":"2024-01-15T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=109271"},"modified":"2024-01-14T20:00:55","modified_gmt":"2024-01-15T04:00:55","slug":"20240115-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20240115-00\/?p=109271","title":{"rendered":"C++\/WinRT gotcha: Not all exceptions derive from <CODE>hresult_error<\/CODE>"},"content":{"rendered":"<p>I often see code that tries to catch all C++\/WinRT exceptions by doing a<\/p>\n<pre>try {\r\n    ... C++\/WinRT code ...\r\n} catch (winrt::hresult_error const&amp; ex) {\r\n    ... caught all C++\/WinRT exceptions (right?) ...\r\n}\r\n<\/pre>\n<p>Unfortunately, this doesn&#8217;t catch all C++\/WinRT exceptions.<\/p>\n<p>The code in C++\/WinRT that converts <code>HRESULT<\/code>s to exceptions can be found <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/blob\/0958cf3a4d572b54d14a06e9d506a1ddd09fae2e\/strings\/base_error.h#L447\"> in <code>throw_hresult<\/code><\/a>. From the code, you can see that every failure <code>HRESULT<\/code> turns into a thrown <code>winrt::hresult_error<\/code>, except for <code>error_<wbr \/>bad_<wbr \/>alloc<\/code>, which is <a href=\"https:\/\/github.com\/microsoft\/cppwinrt\/blob\/0958cf3a4d572b54d14a06e9d506a1ddd09fae2e\/strings\/base_types.h#L246\"> the C++\/WinRT internal name for <code>E_<wbr \/>OUT\u00adOF\u00adMEMORY<\/code><\/a>.<\/p>\n<p>Furthermore, your <code>try<\/code> block probably encompasses some C++ library code that could throw things like <code>std::<wbr \/>out_<wbr \/>of_<wbr \/>range<\/code>, <code>std::<wbr \/>invalid_<wbr \/>argument<\/code>, or a plain old <code>std::<wbr \/>exception<\/code>.<\/p>\n<p>And of course if your code interacts with other libraries, you will want to catch the exceptions thrown by those other libraries, like the <a href=\"https:\/\/github.com\/microsoft\/wil\"> Windows Implementation Library<\/a>.<\/p>\n<p>If you want to catch all exceptions, then catch all exceptions. You can ask <code>winrt::<wbr \/>to_hresult()<\/code> to convert the current exception to an <code>HRESULT<\/code>.<\/p>\n<pre>try {\r\n    ... C++\/WinRT code ...\r\n} catch (<span style=\"border: solid 1px currentcolor;\">...<\/span>) {\r\n    LogFailure(<span style=\"border: solid 1px currentcolor;\">winrt::to_hresult()<\/span>);\r\n}\r\n<\/pre>\n<p>In practice, catching <code>std::<wbr \/>bad_<wbr \/>alloc<\/code> doesn&#8217;t usually help much. Your exception-handling code is probably going to allocate some memory, so you&#8217;re back where you started.<\/p>\n<p><b>Bonus chatter<\/b>: One of the design principles of the Windows Runtime is that exceptions are intended to be used for unrecoverable errors. If there is a recoverable error, then it should be reported in a non-exceptional way. Some of the older Windows Runtime classes don&#8217;t follow this principle, but for the important ones, Windows has been slowly adding non-exceptional alternatives. For example, <code>HttpClient.<wbr \/>GetAsync<\/code> now has a non-exceptional alternative <code>HttpClient.<wbr \/>TryGetAsync<\/code>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are also C++ standard exceptions, particularly <CODE>std::bad_alloc<\/CODE>.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-109271","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing"],"acf":[],"blog_post_summary":"<p>There are also C++ standard exceptions, particularly <CODE>std::bad_alloc<\/CODE>.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=109271"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/109271\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=109271"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=109271"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=109271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}