{"id":91781,"date":"2015-08-19T07:00:00","date_gmt":"2015-08-19T21:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/20150819-00\/?p=91781\/"},"modified":"2019-03-13T12:18:39","modified_gmt":"2019-03-13T19:18:39","slug":"20150819-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20150819-00\/?p=91781","title":{"rendered":"If you are going to call Marshal.GetLastWin32Error, the function whose error you&#8217;re retrieving had better be the one called most recently"},"content":{"rendered":"<p>Even if you <!-- backref: If you are going to call Marshal.GetLastWin32Error, the function whose error you're retrieving had better have SetLastError=true -->remember to set <code>Set&shy;Last&shy;Error=true<\/code> in your p\/invoke signature<\/a>, you still have to be careful with <code>Marshal.Get&shy;Last&shy;Win32&shy;Error<\/code> because there is only one last-error code, and it gets overwritten each time. <!--more--><\/p>\n<p>So let&#8217;s try this program: <\/p>\n<pre>\nusing System;\nusing System.Runtime.InteropServices;\n\nclass Program\n{\n  [DllImport(\"user32.dll\", SetLastError=true)]\n  public static extern bool OpenIcon(IntPtr hwnd);\n\n  public static void Main()\n  {\n    \/\/ Intentionally pass an invalid parameter.\n    var result = OpenIcon(IntPtr.Zero);\n    Console.WriteLine(\"result: {0}\", result);\n    Console.WriteLine(\"last error = {0}\",\n                      Marshal.GetLastWin32Error());\n  }\n}\n<\/pre>\n<p>The expectation is that the call to <code>Open&shy;Icon<\/code> will fail, and the error code will be some form of invalid parameter. <\/p>\n<p>But when you run the program, it prints this: <\/p>\n<pre>\nresult: False\nlast error = 0\n<\/pre>\n<p>Zero? <\/p>\n<p>Zero means &#8220;No error&#8221;. But the function failed. Where&#8217;s our error code? We printed the result immediately after calling <code>Open&shy;Icon<\/code>. We didn&#8217;t call any other p\/invoke functions. The last-error code should still be there. <\/p>\n<p>Oh wait, printing the result to the screen involves a function call. <\/p>\n<p>That function call might itself do a p\/invoke! <\/p>\n<p>We have to call <code>Marshal.Get&shy;Last&shy;Win32&shy;Error<\/code> immediately after calling <code>Open&shy;Icon<\/code>. Nothing else can sneak in between. <\/p>\n<pre>\nusing System;\nusing System.Runtime.InteropServices;\n\nclass Program\n{\n  [DllImport(\"user32.dll\", SetLastError=true)]\n  public static extern bool OpenIcon(IntPtr hwnd);\n\n  public static void Main()\n  {\n    \/\/ Intentionally pass an invalid parameter.\n    var result = OpenIcon(IntPtr.Zero);\n    <font COLOR=\"blue\">var lastError = Marshal.GetLastWin32Error();<\/font>\n    Console.WriteLine(\"result: {0}\", result);\n    Console.WriteLine(\"last error = {0}\",\n                      <font COLOR=\"blue\">lstError<\/font>);\n  }\n}\n<\/pre>\n<p>Okay, now the program reports the error code as 1400: &#8220;Invalid window handle.&#8221; <\/p>\n<p>This one was pretty straightforward, because the function call that modified the last-error code was right there in front of us. But there are other ways that code can run which are more subtle. <\/p>\n<ul>\n<li>If you retrieve a property,     the property retrieval may involve a p\/invoke. \n<li>If you access a class that has a static constructor,     the static constructor will secretly run     if this is the first time the class is used. <\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Watch out for functions called behind your back.<\/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-91781","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Watch out for functions called behind your back.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91781","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=91781"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/91781\/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=91781"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=91781"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=91781"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}