{"id":4603,"date":"2008-03-14T12:56:17","date_gmt":"2008-03-14T12:56:17","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2008\/03\/14\/making-pinvoke-easy\/"},"modified":"2024-07-05T14:32:34","modified_gmt":"2024-07-05T21:32:34","slug":"making-pinvoke-easy","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/making-pinvoke-easy\/","title":{"rendered":"Making PInvoke Easy"},"content":{"rendered":"<p>Jared here again.&nbsp; <\/p>\n<p>I very excited to announce we recently released a tool I&#8217;ve been working on to MSDN that will greatly help with using PInvoke in managed code.&nbsp; The tool is called the &#8220;PInvoke Interop Assistant&#8221; and is included as part of a MSDN article on marshalling data for PInvoke and Reverse PInvoke scenarios.&nbsp; <\/p>\n<p>Here is a link to the article and tool<\/p>\n<ul>\n<li>Article: <a title=\"http:\/\/msdn2.microsoft.com\/en-us\/magazine\/cc164193.aspx\" href=\"http:\/\/msdn2.microsoft.com\/en-us\/magazine\/cc164193.aspx\">http:\/\/msdn2.microsoft.com\/en-us\/magazine\/cc164193.aspx<\/a>  \n<li>Tool: <a title=\"CLRInsideOut2008_01.exe\" href=\"http:\/\/download.microsoft.com\/download\/f\/2\/7\/f279e71e-efb0-4155-873d-5554a0608523\/CLRInsideOut2008_01.exe\">CLRInsideOut2008_01.exe<\/a><\/li>\n<\/ul>\n<p>The motivation behind this tool is writing PInvoke is a hard and often tedious task. There are many rules you must obey and many exceptions that must be taken into account.&nbsp; Anything beyond simple data structures gets very involved and subtle semantics of C can greatly change the needed signature.&nbsp; Incorrect translations often result in obscure exceptions or crashes.<\/p>\n<p>In short, it&#8217;s not any fun. <\/p>\n<p>The tool works in several different ways to make PInvoke generation an easier process.&nbsp; The goal is to make generating managed code for structs, unions, enums, constants, functions, typedefs , etc &#8230; as easy as possible. The resulting code can be generated in both VB and C#. <\/p>\n<p>The GUI version of the tool operates in 3 modes.&nbsp;&nbsp; <\/p>\n<ol>\n<li>SigImp Search: Search for a commonly used function and translate it into managed code.<\/li>\n<li>SigImp Translate Snippet: Directly translate C code into managed PInvoke signatures.<\/li>\n<li>SigExp: Convert managed binaries into C++ Reverse PInvoke scenarios<\/li>\n<\/ol>\n<p>The first two are the parts I worked on and represent the PInvoke scenarios.&nbsp; The third part was written by Ladi Prosek and will be covered in a different article. We chose the names SigImp and SigExp to mirror the tblimp\/tlbexp tool base since they have similar functions.<\/p>\n<h3>Directly translating C code into PInvoke Signatures<\/h3>\n<p>Most adventures in PInvoke start with a developer having a small set of C code they would like to use from a managed binary.&nbsp; Typically it&#8217;s one or two functions with several supporting C structs.&nbsp; Before, all of this would be hand translated into managed code from scratch.&nbsp; With this tool all you must do is paste the code into the tool and it will generate the interop signature for you.&nbsp; <\/p>\n<p>For instance assume you wanted to translate the following C code into VB.&nbsp; <\/p>\n<pre class=\"code\"><span>struct<\/span> S1\n{\n  <span>int<\/span> a;\n  <span>char<\/span>[10] b;\n};\n<span>float<\/span> CalculateData(S1* p);<\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<p>Start up the tool and switch to the &#8220;SigImp Translate Snippet&#8221; tab.&nbsp; Then paste the code in and then hit the Generate button.&nbsp; <\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/7\/2019\/02\/PInvoke1_4.png\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" style=\"border-right: 0px;border-top: 0px;border-left: 0px;border-bottom: 0px\" height=\"157\" alt=\"PInvoke1\" src=\"https:\/\/devblogs.microsoft.com\/vbteam\/wp-content\/uploads\/sites\/7\/2008\/03\/PInvoke1_thumb_1.png\" width=\"244\" border=\"0\"><\/a>&nbsp;<\/p>\n<p>You can also set click the &#8220;Auto Generate&#8221; box and watch the code update as you type.&nbsp; <\/p>\n<p>This translation is not limited to built-in C types.&nbsp; It will also resolve most commonly used windows types such as HANDLE, DWORD all the way up to complex structs such as <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa365740(VS.85).aspx\">WIN32_FIND_DATA<\/a><\/p>\n<h3>Searching for a commonly used function<\/h3>\n<p>Often developers want to use C functions familiar to them in managed code.&nbsp; This can be a tedious task as well because if the signature is not already available you are back to coding from scratch.&nbsp; Even adding a constant value can be tricky if you don&#8217;t know which header file to look in.&nbsp; <\/p>\n<p>The tool also provides a database of many commonly used functions, structs, constants, etc &#8230; It is essentially anything that is included from windows.h.&nbsp; Switch to the SigImp search tab, type the name of what you are looking for and hit generate.&nbsp; For example if I want to see the value for WM_PAINT just type it in.&nbsp; <\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/7\/2019\/02\/Pinvoke2_2.png\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" style=\"border-top-width: 0px;border-left-width: 0px;border-bottom-width: 0px;border-right-width: 0px\" height=\"157\" alt=\"Pinvoke2\" src=\"https:\/\/devblogs.microsoft.com\/vbteam\/wp-content\/uploads\/sites\/7\/2008\/03\/Pinvoke2_thumb.png\" width=\"244\" border=\"0\"><\/a> <\/p>\n<p>In addition this part of the tool will also do dependency calculation.&nbsp; For instance if choose a method which has a parameter that is a C structure it will automatically generate the structure with the function.&nbsp; For instance if you choose the function <a href=\"http:\/\/msdn2.microsoft.com\/en-us\/library\/aa364418.aspx\">FindFirstFile<\/a> it will determine that the function depends on the WIN32_FIND_DATA structure.&nbsp; Furthermore it will notice that WIN32_FIND_DATA depends on FILETIME and generate both in addition to the method.<\/p>\n<pre class=\"code\">&lt;System.Runtime.InteropServices.StructLayoutAttribute( _\n    System.Runtime.InteropServices.LayoutKind.Sequential, _\n    CharSet:=System.Runtime.InteropServices.CharSet.[Unicode])&gt; _\n<span>Public<\/span> <span>Structure<\/span> WIN32_FIND_DATAW\n    <span>'''DWORD-&gt;unsigned int\n<\/span>    <span>Public<\/span> dwFileAttributes <span>As<\/span> <span>UInteger\n<\/span>    <span>'''FILETIME-&gt;_FILETIME\n<\/span>    <span>Public<\/span> ftCreationTime <span>As<\/span> FILETIME\n    <span>'''FILETIME-&gt;_FILETIME\n<\/span>    <span>Public<\/span> ftLastAccessTime <span>As<\/span> FILETIME\n    <span>'''FILETIME-&gt;_FILETIME\n<\/span>    <span>Public<\/span> ftLastWriteTime <span>As<\/span> FILETIME\n    <span>'''DWORD-&gt;unsigned int\n<\/span>    <span>Public<\/span> nFileSizeHigh <span>As<\/span> <span>UInteger\n<\/span>    <span>'''DWORD-&gt;unsigned int\n<\/span>    <span>Public<\/span> nFileSizeLow <span>As<\/span> <span>UInteger\n<\/span>    <span>'''DWORD-&gt;unsigned int\n<\/span>    <span>Public<\/span> dwReserved0 <span>As<\/span> <span>UInteger\n<\/span>    <span>'''DWORD-&gt;unsigned int\n<\/span>    <span>Public<\/span> dwReserved1 <span>As<\/span> <span>UInteger\n<\/span>    <span>'''WCHAR[260]\n<\/span>    &lt;System.Runtime.InteropServices.MarshalAsAttribute( _\n        System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=260)&gt; _\n    <span>Public<\/span> cFileName <span>As<\/span> <span>String\n<\/span>    <span>'''WCHAR[14]\n<\/span>    &lt;System.Runtime.InteropServices.MarshalAsAttribute( _\n        System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst:=14)&gt; _\n    <span>Public<\/span> cAlternateFileName <span>As<\/span> <span>String\nEnd<\/span> <span>Structure\n<\/span>&lt;System.Runtime.InteropServices.StructLayoutAttribute( _\n    System.Runtime.InteropServices.LayoutKind.Sequential)&gt; _\n<span>Public<\/span> <span>Structure<\/span> FILETIME\n    <span>'''DWORD-&gt;unsigned int\n<\/span>    <span>Public<\/span> dwLowDateTime <span>As<\/span> <span>UInteger\n<\/span>    <span>'''DWORD-&gt;unsigned int\n<\/span>    <span>Public<\/span> dwHighDateTime <span>As<\/span> <span>UInteger\nEnd<\/span> <span>Structure\nPartial<\/span> <span>Public<\/span> <span>Class<\/span> NativeMethods\n    <span>'''Return Type: HANDLE-&gt;void*\n<\/span>    <span>'''lpFileName: LPCWSTR-&gt;WCHAR*\n<\/span>    <span>'''lpFindFileData: LPWIN32_FIND_DATAW-&gt;_WIN32_FIND_DATAW*\n<\/span>    &lt;System.Runtime.InteropServices.DllImportAttribute(<span>\"kernel32.dll\"<\/span>, EntryPoint:=<span>\"FindFirstFileW\"<\/span>)&gt; _\n    <span>Public<\/span> <span>Shared<\/span> <span>Function<\/span> FindFirstFileW( _\n        &lt;System.Runtime.InteropServices.InAttribute(), _\n            System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)&gt; _\n            <span>ByVal<\/span> lpFileName <span>As<\/span> <span>String<\/span>, _\n        &lt;System.Runtime.InteropServices.OutAttribute()&gt; _\n        <span>ByRef<\/span> lpFindFileData <span>As<\/span> WIN32_FIND_DATAW) <span>As<\/span> System.IntPtr\n    <span>End<\/span> <span>Function\nEnd<\/span> <span>Class<\/span><\/pre>\n<p><a href=\"http:\/\/11011.net\/software\/vspaste\"><\/a><\/p>\n<h3>Translating Large Code bases<\/h3>\n<p>The snippet translator works well for small snippets of code.&nbsp; If you are trying to translate a much larger code base, say several interdependent header files the small snippet dialog won&#8217;t work well.&nbsp; To work with larger code bases you should use the command line version of the tool;&nbsp; sigimp.exe.&nbsp; It is designed to process several header files and produce a mass output.&nbsp; <\/p>\n<h3>Wrapping Up<\/h3>\n<p>This tool started out as a pet project of mine some time ago.&nbsp; I&#8217;m extremely excited that customers are now going to be able to take advantage of it and I greatly look forward to any feedback you have.&nbsp; I will post a couple more articles in the future detailing how this tool works under the hood.&nbsp; <\/p>\n<p>Jared Parsons<\/p>\n<p><a href=\"http:\/\/blogs.msdn.com\/jaredpar\">http:\/\/blogs.msdn.com\/jaredpar<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Jared here again.&nbsp; I very excited to announce we recently released a tool I&#8217;ve been working on to MSDN that will greatly help with using PInvoke in managed code.&nbsp; The tool is called the &#8220;PInvoke Interop Assistant&#8221; and is included as part of a MSDN article on marshalling data for PInvoke and Reverse PInvoke scenarios.&nbsp; [&hellip;]<\/p>\n","protected":false},"author":260,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[21,195],"tags":[57,78,127,170],"class_list":["post-4603","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-im-a-vb","category-visual-basic","tag-did-you-know","tag-jared-parsons","tag-pinvoke","tag-vb6_migrationinterop"],"acf":[],"blog_post_summary":"<p>Jared here again.&nbsp; I very excited to announce we recently released a tool I&#8217;ve been working on to MSDN that will greatly help with using PInvoke in managed code.&nbsp; The tool is called the &#8220;PInvoke Interop Assistant&#8221; and is included as part of a MSDN article on marshalling data for PInvoke and Reverse PInvoke scenarios.&nbsp; [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4603","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/260"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=4603"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4603\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=4603"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=4603"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=4603"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}