{"id":103338,"date":"2020-01-17T07:00:00","date_gmt":"2020-01-17T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103338"},"modified":"2020-01-16T18:00:06","modified_gmt":"2020-01-17T02:00:06","slug":"20200117-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200117-00\/?p=103338","title":{"rendered":"How can I turn a structured exception into a C++ exception without having to use \/EHa, if I can constrain exactly where the structured exception is coming from?"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200116-00\/?p=103333\"> Last time<\/a>, we looked at how you can handle both structured exceptions and C++ exceptions coming out of a plug-in. But the <code>_set_se_translator<\/code> function <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/5z4bw5h5.aspx\"> requires that your code be compiled with the <code>\/EHa<\/code><\/a>. The customer was wondering if there was something that avoided the need for <code>\/EHa<\/code>.<\/p>\n<p>One possibility is compiling parts of the program with <code>\/EHa<\/code> and parts without. This is <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/1deeycx5.aspx\"> explicitly called out as not recommended<\/a>. The reason is that code compiled with <code>\/EHs<\/code> (the opposite of <code>\/EHa<\/code>) assumes that exceptions can be raised only by <code>throw<\/code> statements, and <code>_set_se_translator<\/code> violates that rule because it allows C++ exceptions to be thrown by any Win32 exception.<\/p>\n<p>But all is not lost. In this case, we need the asynchronous-to-synchronous conversion only for a specific block of code. If we can make sure no asynchronous exceptions escape into code compiled with <code>\/EHs<\/code>, we won&#8217;t violate the assumptions of <code>\/EHs<\/code>.<\/p>\n<pre>HRESULT InvokeWithCustomExceptionTranslation(\r\n    CALLBACK_FUNCTION fn, \/* other arguments *\/)\r\n{\r\n  __try {\r\n    return fn(\/* other arguments *\/);\r\n  } __except (GetExceptionCode() == MSVC_EXCEPTION ?\r\n              EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER) {\r\n    throw win32_exception(GetExceptionCode(),\r\n                          get_stack_trace(GetExceptionInformation()));\r\n  }\r\n}\r\n\r\n\/\/ InvokeCallback same as before\r\n<\/pre>\n<p>If an asynchronous exception occurs during execution of the lambda, we check if it was a C++ exception. If so, then we let it go through so that the runtime can deal with it. Otherwise, we convert it to a C++ exception on the spot.<\/p>\n<p>It is important that there not be anything with a destructor in the <code>__try<\/code> block, because the asynchronous exception will bypass all destructors. Fortunately, the compiler will <a href=\"https:\/\/docs.microsoft.com\/en-us\/cpp\/error-messages\/compiler-errors-2\/compiler-error-c2712\"> yell at you<\/a> if you make this mistake.<\/p>\n<p>It is also important that this function handle all asynchronous exceptions (aside from C++ exceptions themselves), so that no asynchronous exception escapes into <code>\/EHs<\/code> code.<\/p>\n<p>On the other hand, we hard-coded some secret knowledge of the compiler&#8217;s implementation, namely, that <code>MSVC_<code><\/code>EXCEPTION<\/code> is the exception code used for C++ exceptions. If you are running in an environment where the plug-in could be written in managed code, then you will turn managed exceptions into <code>win32_<code><\/code>exception<\/code>.<\/p>\n<p>Which brings us back to what we had before: Using the <code>_set_se_translator<\/code> function to switch from <code>\/EHs<\/code> mode to <code>\/EHa<\/code> mode temporarily.<\/p>\n<p>This is one of those cases where advice needs to come with a rationale: If you understand why a rule exists, you can understand when you are in a case where the rule doesn&#8217;t apply.<\/p>\n<p>And we are in one of those cases. The rason for the guidance against mixing <code>\/EHs<\/code> and <code>\/EHa<\/code> in the same program is that you don&#8217;t want asynchronous exceptions to be converted to synchronous exceptions when the calling code isn&#8217;t expecting it. By scoping the use of the <code>_set_se_translator<\/code> function to a single block of code, we can verify by inspection that asynchronous exceptions never escape into code that doesn&#8217;t expect it.<\/p>\n<p>This code needs to be carefully commented with a note that it needs to be compiled in a specific way, and giving an explanation not only why that is necessary, but also why it is safe.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trying to contain the damage.<\/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-103338","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Trying to contain the damage.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103338","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=103338"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103338\/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=103338"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103338"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}