{"id":17113,"date":"2009-08-13T10:00:00","date_gmt":"2009-08-13T10:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2009\/08\/13\/common-gotchas-when-writing-your-own-pinvoke\/"},"modified":"2009-08-13T10:00:00","modified_gmt":"2009-08-13T10:00:00","slug":"common-gotchas-when-writing-your-own-pinvoke","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20090813-00\/?p=17113","title":{"rendered":"Common gotchas when writing your own p\/invoke"},"content":{"rendered":"<p>\nIf you&#8217;re looking to get into some p\/invoke action,\nyou&#8217;d be well-served to check out the\n<a HREF=\"http:\/\/pinvoke.net\/\">pinvoke wiki<\/a>\nto see if somebody else has done it too.\nIf what you need isn&#8217;t there, you may end up forced to write your own,\nand here are some gotchas I&#8217;ve seen people run into:\n<\/p>\n<ul>\n<li>\n    C++ <code>bool<\/code> and Win32 <code>BOOLEAN<\/code>\n    are not the same as C# <code>bool<\/code>\n    (aka <code>System.Boolean<\/code>).\n    In Win32, <code>BOOL<\/code> is a 4-byte type,\n    and <code>BOOLEAN<\/code> is a 1-byte type.\n    [<i>See also\n    <a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2009\/08\/13\/9867383.aspx#9870333\">\n    MadQ&#8217;s remarks about <code>VARIANT_BOOL<\/code><\/a><\/i>.]\n    Meanwhile, C++ <code>bool<\/code> is not standardized by Win32,\n    so the size will vary based on your compiler, but most compilers\n    use a 1-byte value.\n    And then C# is even weirder:\n    The <code>bool<\/code> is a 1-byte type,\n    <a HREF=\"http:\/\/blogs.msdn.com\/jaredpar\/archive\/2008\/10\/14\/pinvoke-and-bool-or-should-i-say-bool.aspx\">\n    but it marshals as a 4-byte type by default<\/a>.<\/p>\n<li>Win32 <code>char<\/code> is not the same as C# <code>char<\/code>\n    (aka <code>System.Char<\/code>).\n    In C#, <code>char<\/code> is a Unicode character (two bytes), whereas in\n    C\/C++ under Win32 it is an ANSI character (one byte).<\/p>\n<li>Win32 <code>long<\/code> is not the same as C# <code>long<\/code>\n    (aka <code>System.Int64<\/code>).\n    In C#, <code>long<\/code> is 64-bit value, whereas in\n    C\/C++ under Win32 it is a 32-bit value.<\/p>\n<li>If memory is allocated and freed across the interop boundary,\n    make sure both sides are using the same allocator.\n    It is my understanding that\n    <a HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/f1cf4kkz.aspx\">\n    the CLR uses <code>CoTaskMemAlloc<\/code>\/<code>CoTaskMemFree<\/code>\n    by default<\/a>.\n    If your Win32 function doesn&#8217;t use <code>CoTaskMemAlloc<\/code>,\n    you&#8217;ll have to teach the CLR which allocator you really want.<\/p>\n<li>When laying out structures, you have to watch out for alignment.\n<\/ul>\n<p>\nThat last one is particularly gnarly on 64-bit systems,\nwhere alignment requirements are less forgiving than on x86.\nThe structure declarations on pinvoke.net tend to ignore 64-bit\nissues.\nFor example, the declaration of the <code>INPUT<\/code> structure\n(<a HREF=\"http:\/\/pinvoke.net\/default.aspx\/user32\/SendInput(2008-01-24-03-56-33.4726--69.14.194.68).html\">as of this writing<\/a>&mdash;it&#8217;s a wiki so it&#8217;s probably changed\nby the time you read this) reads as follows:\n<\/p>\n<blockquote CLASS=\"q\">\n<pre>\n[StructLayout(LayoutKind.Explicit)]struct INPUT {\n  [FieldOffset(0)] int type;\n  [FieldOffset(4)] MOUSEINPUT mi;\n  [FieldOffset(4)] KEYBDINPUT ki;\n  [FieldOffset(4)] HARDWAREINPUT hi;\n}\n<\/pre>\n<\/blockquote>\n<p>\nThis structure layout is correct for 32-bit Windows,\nbut it&#8217;s incorrect for 64-bit Windows.\n<\/p>\n<p>\nLet&#8217;s take a look at that <code>MOUSEINPUT<\/code> structure,\nfor starters.\n<\/p>\n<pre>\ntypedef struct tagMOUSEINPUT {\n    LONG    dx;\n    LONG    dy;\n    DWORD   mouseData;\n    DWORD   dwFlags;\n    DWORD   time;\n    ULONG_PTR dwExtraInfo;\n} MOUSEINPUT, *PMOUSEINPUT, FAR* LPMOUSEINPUT;\n<\/pre>\n<p>\nIn 64-bit Windows, the <code>LONG<\/code> and <code>DWORD<\/code>\nmembers are four bytes, but the <code>dwExtraInfo<\/code> is\na <code>ULONG_PTR<\/code>, which is eight bytes on a 64-bit machine.\nSince\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2009\/04\/22\/9560726.aspx\">\nWindows assumes \/Zp8 packing<\/a>,\nthe <code>dwExtraInfo<\/code> must be aligned on an 8-byte boundary,\nwhich forces four bytes of padding to be inserted after the\n<code>time<\/code> to get the <code>dwExtraInfo<\/code> to align\nproperly.\nAnd in order for all this to work, the <code>MOUSEINPUT<\/code>\nstructure itself must be 8-byte aligned.\n<\/p>\n<p>\nNow let&#8217;s look at that <code>INPUT<\/code> structure again.\nSince the <code>MOUSEINPUT<\/code> comes after the <code>type<\/code>,\nthere also needs to be padding between the <code>type<\/code>\nand the <code>MOUSEINPUT<\/code> to get the <code>MOUSEINPUT<\/code>\nback to an 8-byte boundary.\nIn other words, the offset of <code>mi<\/code> in the <code>INPUT<\/code>\nstructure is <u>8<\/u> on 64-bit Windows, not&nbsp;4.\n<\/p>\n<p>\nHere&#8217;s how I would&#8217;ve written it:\n<\/p>\n<pre>\n\/\/ This generates the anonymous union\n[StructLayout(LayoutKind.Explicit)] struct INPUT_UNION {\n  [FieldOffset(0)] MOUSEINPUT mi;\n  [FieldOffset(0)] KEYBDINPUT ki;\n  [FieldOffset(0)] HARDWAREINPUT hi;\n};\n<a HREF=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2009\/08\/13\/9867383.aspx#9869008\">[StructLayout(LayoutKind.Sequential)]<\/a> struct INPUT {\n  int type;\n  INPUT_UNION u;\n}\n<\/pre>\n<p>\nI introduce a helper structure to represent the anonymous union\nthat is the second half of the Win32 <code>INPUT<\/code> structure.\nBy doing it this way, I let somebody else worry about the\nalignment,\nand it&#8217;ll be correct for both 32-bit and 64-bit Windows.\n<\/p>\n<pre>\nstatic public void Main()\n{\n  Console.WriteLine(Marshal.OffsetOf(typeof(INPUT), \"u\"));\n}\n<\/pre>\n<p>\nOn a 32-bit system, this prints&nbsp;4,\nand on a 64-bit system, it prints&nbsp;8.\nThe downside is that you have to type an extra <code>u.<\/code>\nwhen you access the <code>mi<\/code>, <code>ki<\/code> or <code>hi<\/code>\nmembers.\n<\/p>\n<pre>\ninput i;\ni.<font COLOR=\"blue\">u.<\/font>mi.dx = 0;\n<\/pre>\n<p>\n(I haven&#8217;t checked what the\n<a HREF=\"http:\/\/www.codeplex.com\/Release\/ProjectReleases.aspx?ProjectName=clrinterop&amp;ReleaseId=14120\">\nPInvoke Interop Assistant<\/a>\ncomes up with for the <code>INPUT<\/code> structure.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;re looking to get into some p\/invoke action, you&#8217;d be well-served to check out the pinvoke wiki to see if somebody else has done it too. If what you need isn&#8217;t there, you may end up forced to write your own, and here are some gotchas I&#8217;ve seen people run into: C++ bool and [&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-17113","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>If you&#8217;re looking to get into some p\/invoke action, you&#8217;d be well-served to check out the pinvoke wiki to see if somebody else has done it too. If what you need isn&#8217;t there, you may end up forced to write your own, and here are some gotchas I&#8217;ve seen people run into: C++ bool and [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17113","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=17113"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/17113\/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=17113"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=17113"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=17113"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}