{"id":10803,"date":"2011-04-29T07:00:00","date_gmt":"2011-04-29T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2011\/04\/29\/why-is-there-a-restorelasterror-function-that-does-the-same-thing-as-setlasterror\/"},"modified":"2011-04-29T07:00:00","modified_gmt":"2011-04-29T07:00:00","slug":"why-is-there-a-restorelasterror-function-that-does-the-same-thing-as-setlasterror","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20110429-00\/?p=10803","title":{"rendered":"Why is there a RestoreLastError function that does the same thing as SetLastError?"},"content":{"rendered":"<p>\nMatt Pietrek noticed that\n<a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/magazine\/cc300448.aspx\">\n<code>Set&shy;Last&shy;Error<\/code> and\n<code>Restore&shy;Last&shy;Error<\/code> do exactly the same thing\nand wondered why there&#8217;s a separate function for it<\/a>.\n<\/p>\n<p>\nIt&#8217;s to assist in debugging and diagnostics.\n<\/p>\n<p>\nSay you&#8217;re debugging a problem and\nwhen you call <code>Get&shy;Last&shy;Error<\/code> you get\n<code>ERROR_ACCESS_DENIED<\/code>.\nIt would really help a lot if you could figure out\nwho set the error code to <code>ERROR_ACCESS_DENIED<\/code>.\nIf you set a breakpoint on <code>Set&shy;Last&shy;Error<\/code>,\nyou find that people call\n<code>Set&shy;Last&shy;Error<\/code> for two different\nreasons:\n<\/p>\n<ol>\n<li>To report an error.\n<\/li>\n<li>To restore the error code to what it was before they did something\n    that might change the last error code.\n<\/li>\n<\/ol>\n<p>\nThat second one needs a little explanation.\nYou might have a logging function that goes like this:\n<\/p>\n<pre>\n<i>\/\/ Remember, code in italics is wrong\nvoid LogSomething(blah blah)\n{\n DWORD dwError = GetLastError();\n ... do logging stuff ...\n SetLastError(dwError);\n}\n\/\/ or if you prefer RAII\nclass PreserveLastError\n{\npublic:\n    PreserveLastError() : m_dwLastError(GetLastError()) {}\n    ~PreserveLastError() { SetLastError(m_dwLastError); }\nprivate:\n    DWORD m_dwLastError;\n};<\/i>\nvoid LogSomething(blah blah)\n{\n PreserveLastError preserve;\n ... do logging stuff ...\n}\n<\/pre>\n<p>\nIt&#8217;s important that functions which perform logging,\nassertion checking, and other diagnostic operations\nare nonintrusive.\nYou don&#8217;t want a bug to go away when you turn on logging\nbecause the logging code somehow perturbed the system.\nTherefore, your logging function saves the value of\n<code>Get&shy;Last&shy;Error()<\/code> and sets that back as the error\ncode when it&#8217;s done, so that any errors that took place\nduring logging do not escape and inadvertently\naffect the rest of the program.\n<\/p>\n<p>\nNow let&#8217;s go back to the code that&#8217;s trying to figure out\nwho set the error code to <code>ERROR_ACCESS_DENIED<\/code>.\nYou set up your debugging diagnostic tool and tell it to\nrecord everybody who calls\n<code>Set&shy;Last&shy;Error()<\/code>\nand pay particular attention to everybody who sets\nthe error to <code>ERROR_ACCESS_DENIED<\/code>.\nYou then run your scenario,\nyour program encounters the failure you&#8217;re trying to debug,\nand you ask the diagnostic tool,\n&#8220;Tell me who set the error code to\n<code>ERROR_ACCESS_DENIED<\/code>.&#8221;\nThe diagnostic tool says,\n&#8220;Ah, I have that in my history.\nThe function that set the error code to\n<code>ERROR_ACCESS_DENIED<\/code> is&#8230;\n<code>Log&shy;Something<\/code>!&#8221;\n<\/p>\n<p>\nOf course, <code>Log&shy;Something<\/code> wasn&#8217;t really the originator of the\n<code>ERROR_ACCESS_DENIED<\/code>;\nit was just restoring things to how it found them.\nThe real <code>ERROR_ACCESS_DENIED<\/code> came from somebody else,\nand the log function was just being careful not to disturb it.\n<\/p>\n<pre>\n...\n  if (!FunctionX()) {\n    LogSomething(\"Function X failed\");\n  } else {\n    LogSomething(\"Function X succeeded\");\n   FunctionY(); \/\/ also does some logging\n  }\n  FunctionZ(); \/\/ also does some logging\n  Assert(EverythingOkay()); \/\/ assertion fires\n  \/\/ GetLastError() returns ERROR_ACCESS_DENIED\n...\n<\/pre>\n<p>\nAll those calls to logging functions in between\ncalled <code>Get&shy;Last&shy;Error()<\/code> and got\n<code>ERROR_ACCESS_DENIED<\/code>\nback,\nthen when the logging was complete, they called\n<code>Set&shy;Last&shy;Error(ERROR_ACCESS_DENIED)<\/code>\nto put things back.\nYour diagnostic error-tracing tool gleefully points the finger\nat your logging function:\n&#8220;Look! Look! This guy set the error code to\n<code>ERROR_ACCESS_DENIED<\/code>!&#8221;\n<\/p>\n<p>\nEnter <code>Restore&shy;Last&shy;Error<\/code>.\nThis function does the same thing as <code>Set&shy;Last&shy;Error<\/code>,\nbut its use is a message to diagnostic tools that\n&#8220;Sure, you may see me set an error code,\nbut <i>it wasn&#8217;t my idea<\/i>.\nI&#8217;m just trying to put things back the way I found them.\n<i>Keep looking backwards in your history<\/i>.&#8221;\n<\/p>\n<p>\n(The message also works forward in time:\nIf you want to catch <code>ERROR_ACCESS_DENIED<\/code> in the act,\nyou might set a breakpoint on <code>Set&shy;Last&shy;Error<\/code>,\nand then get frustrated that the breakpoint keeps getting hit by\nyour logging function.\nSwitching the logging function to <code>Restore&shy;Last&shy;Error<\/code>\nkeeps the breakpoint on\n<code>Set&shy;Last&shy;Error<\/code> from firing spuriously.)\n<\/p>\n<p>\nThe corrected version of the <code>Log&shy;Something<\/code>\nfunction is therefore something like this:\n<\/p>\n<pre>\nvoid LogSomething(blah blah)\n{\n DWORD dwError = GetLastError();\n ... do logging stuff ...\n <font COLOR=\"blue\">Restore<\/font>LastError(dwError);\n}\n\/\/ or if you prefer RAII\nclass PreserveLastError\n{\npublic:\n    PreserveLastError() : m_dwLastError(GetLastError()) {}\n    ~PreserveLastError() { <font COLOR=\"blue\">Restore<\/font>LastError(m_dwLastError); }\nprivate:\n    DWORD m_dwLastError;\n};\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Matt Pietrek noticed that Set&shy;Last&shy;Error and Restore&shy;Last&shy;Error do exactly the same thing and wondered why there&#8217;s a separate function for it. It&#8217;s to assist in debugging and diagnostics. Say you&#8217;re debugging a problem and when you call Get&shy;Last&shy;Error you get ERROR_ACCESS_DENIED. It would really help a lot if you could figure out who set the [&hellip;]<\/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-10803","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Matt Pietrek noticed that Set&shy;Last&shy;Error and Restore&shy;Last&shy;Error do exactly the same thing and wondered why there&#8217;s a separate function for it. It&#8217;s to assist in debugging and diagnostics. Say you&#8217;re debugging a problem and when you call Get&shy;Last&shy;Error you get ERROR_ACCESS_DENIED. It would really help a lot if you could figure out who set the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10803","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=10803"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/10803\/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=10803"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=10803"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=10803"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}