{"id":110629,"date":"2024-12-11T07:00:00","date_gmt":"2024-12-11T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=110629"},"modified":"2024-12-11T09:23:02","modified_gmt":"2024-12-11T17:23:02","slug":"20241211-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20241211-00\/?p=110629","title":{"rendered":"What is the <CODE>CONTINUE_IF_FAILED<\/CODE> equivalent of <CODE>RETURN_IF_FAILED<\/CODE>?"},"content":{"rendered":"<p>A customer who used the <a href=\"https:\/\/github.com\/microsoft\/wil\"> Windows Implementation Library<\/a> couldn&#8217;t find a <code>CONTINUE_IF_FAILED<\/code> macro, the counterpart to the existing <code>RETURN_IF_FAILED<\/code> macro, so they wrote their own:<\/p>\n<pre>#define CONTINUE_IF_FAILED(hr) \\\r\n    if (FAILED(hr)) { LOG_HR(hr); continue; }\r\n<\/pre>\n<p>This version has a serious problem: It evaluates its argument twice.<\/p>\n<p>Their sample usage went something like this:<\/p>\n<pre>for (auto&amp;&amp; item : items)\r\n{\r\n    wil::com_ptr&lt;IAttachment&gt; attachment;\r\n    CONTINUE_IF_FAILED(item-&gt;GetAttachment(&amp;attachment));\r\n\r\n    wil::unique_cotaskmem_ptr name;\r\n    CONTINUE_IF_FAILED(attachment-&gt;GetName(&amp;name));\r\n\r\n    if (wcscmp(name.get(), L\"Special\") == 0) {\r\n        HandleSpecial(item);\r\n    }\r\n}\r\n<\/pre>\n<p>After expanding the macro one level, we have<\/p>\n<pre>for (auto&amp;&amp; item : items)\r\n{\r\n    wil::com_ptr&lt;IAttachment&gt; attachment;\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">if (FAILED(item-&gt;GetAttachment(&amp;attachment))) {<\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    LOG_HR(item-&gt;GetAttachment(&amp;attachment));  <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    continue;                                  <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">}                                              <\/span>\r\n\r\n    wil::unique_cotaskmem_ptr name;\r\n    <span style=\"border: solid 1px currentcolor; border-bottom: none;\">if (FAILED(attachment-&gt;GetName(&amp;name))) {<\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    LOG_HR(attachment-&gt;GetName(&amp;name));  <\/span>\r\n    <span style=\"border: 1px currentcolor; border-style: none solid;\">    continue;                            <\/span>\r\n    <span style=\"border: solid 1px currentcolor; border-top: none;\">}                                        <\/span>\r\n\r\n    if (wcscmp(name.get(), L\"Special\") == 0) {\r\n        HandleSpecial(item);\r\n    }\r\n}\r\n<\/pre>\n<p>Notice that in both cases, we attempt the operation, and if it fails, we attempt it again (!) and log the result of the second attempt.<\/p>\n<p>Fortunately in this case, the <code>Get<\/code> methods have no side effects, so calling them twice is mostly harmless. You can imagine cases where this could be a problem, say, if the method was something like <code>Toggle\u00adState<\/code>.<\/p>\n<p>Furthermore, the second call might not fail for the same reason as the first call. Maybe the first call failed due to a transient error (server not responding, low memory), and the second call succeeds. Your code logs a success code, and you&#8217;ll be scratching your head when you study your logs trying to figure out why the code gave up on a successful call.<\/p>\n<p>You should build your solution out of the existing <code>RETURN_<wbr \/>IF_<wbr \/>FAILED<\/code> macro. <a href=\"https:\/\/github.com\/microsoft\/wil\/wiki\/Error-handling-helpers#using-error-handling-macros-to-stop-processing-without-exiting-the-function\"> The wil wiki even explains how<\/a>: Use a lambda to wrap the block you want to early-exit from without exiting the entire function.<\/p>\n<pre>for (auto&amp;&amp; item : items)\r\n{\r\n    [&amp;] {\r\n        wil::com_ptr&lt;IAttachment&gt; attachment;\r\n        RETURN_IF_FAILED(item-&gt;GetAttachment(&amp;attachment));\r\n\r\n        wil::unique_cotaskmem_ptr name;\r\n        RETURN_IF_FAILED(attachment-&gt;GetName(&amp;name));\r\n\r\n        if (wcscmp(name.get(), L\"Special\") == 0) {\r\n            HandleSpecial(item);\r\n        }\r\n\r\n        return S_OK;\r\n    }();\r\n}\r\n<\/pre>\n<p>You have all of the <code>RETURN_<wbr \/>IF_<\/code> macros at your disposal inside the lambda. You can use <code>RETURN_<wbr \/>IF_<wbr \/>FAILED<\/code>, <code>RETURN_<wbr \/>HR_<wbr \/>IF<\/code>, <code>RETURN_<wbr \/>IF_<wbr \/>FAILED_<wbr \/>EXPECTED<\/code>, and so on, so no need to create <code>CONTINUE_<wbr \/>IF_<\/code> variants of everything. And all of the error logging and reporting settings related to <code>RETURN_<wbr \/>IF_<\/code> will still work.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Be careful how you write it, or better: Don&#8217;t write it at all.<\/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":[25],"class_list":["post-110629","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Be careful how you write it, or better: Don&#8217;t write it at all.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110629","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=110629"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/110629\/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=110629"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=110629"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=110629"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}