{"id":10831,"date":"2006-04-25T12:17:57","date_gmt":"2006-04-25T12:17:57","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2006\/04\/25\/pinvoke-or-accessing-win32-apis\/"},"modified":"2019-02-18T13:25:04","modified_gmt":"2019-02-18T20:25:04","slug":"pinvoke-or-accessing-win32-apis","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/pinvoke-or-accessing-win32-apis\/","title":{"rendered":"PINVOKE or accessing WIN32 APIs"},"content":{"rendered":"<p>In the very early days of Monad, we&nbsp;focused on&nbsp;a world where everyone would publish Cmdlets and providers.&nbsp; Cmdlets and providers&nbsp;were designed around providing the best user experience.&nbsp; They provide the right, high-level, task-oriented abstractions that users want while also providing the semantic benefits that the Monad engine provides (-WHATIF, -CONFIRM, -VERBOSE, -ERRORACTION, -ERRORVARIABLE, etc etc).&nbsp; The trick then is &#8211; how do we get full coverage with Cmdlets?<\/p>\n<p>To address this issue &#8211; we took an economic approach: require a tiny amount of code, provide a huge amount of function and good things will occur.&nbsp; Anyone that has written a Cmdlet gets this in focus very quickly.&nbsp; We provide value-add functions in a variety of ways.&nbsp; First,&nbsp;Cmdlets are&nbsp;subclassed&nbsp;from our base class and then hosted by the&nbsp;Monad engine.&nbsp; The base class and the engine provide a ton of functionality for free when you use the right APIs.&nbsp; For instance,&nbsp;all you have to do is call ShouldProcess() and the engine will implement -WHATIF -CONFIRM and -VERBOSE for you.&nbsp; Good deal.&nbsp; <\/p>\n<p>We also provide a ton of functions to manipulate&nbsp;&nbsp;the objects that your cmdlets emit.&nbsp; We have object utilities (sort, where, group, select, compare, etc), we have formating and outputing commands (format-table\/list\/wide\/custom, out-host\/file\/printer\/string etc, export\/import-clixml\/csv), we allow 3rd parties and end-users to extend your objects (*format.mshxml, *types.mshxml), we provide an interactive shell and a programming language with an awesome dynamic range which is usable by beginner scripters&nbsp;to very sophisticated programmers.&nbsp; All and all, I think you&#8217;d be hard-pressed to get more functions per line of code than a Cmdlet provides (providers give even more functionality but they are not as tiny as Cmdlets).&nbsp;<\/p>\n<p>While we think we&#8217;ve produced a compelling economic,&nbsp; it didn&#8217;t take very long for us to do the analysis and realize that would quite a while before customers had full coverage for all the functions that they needed.&nbsp; It would take a while before vendors had an opportunity to update their products, it would take a while before customers adopted the new versions of those products, and in the end &#8211; there might be some vendors that won&#8217;t write Cmdlets no matter what (for technical, strategic, geo-political, or religious reasons or&nbsp;maybe because the vendor went out of business).&nbsp; At this point, we expanded the scope of the project to embrace existing forms of instrumentation.&nbsp; <\/p>\n<p>Today we support Text Processing, COM automation, access to .NET classes but currently there is no native support for Win32 APIs.&nbsp;&nbsp; That said, .NET provides some great support for calling Win32 APIs.&nbsp; Here is a pointer to a good article on the details of .NET&#8217;s support for PINVOKE (Platform Invoke)&nbsp;: <\/p>\n<p><a href=\"http:\/\/msdn.microsoft.com\/library\/default.asp?url=\/library\/en-us\/csref\/html\/vcwlkplatforminvoketutorial.asp\">http:\/\/msdn.microsoft.com\/library\/default.asp?url=\/library\/en-us\/csref\/html\/vcwlkplatforminvoketutorial.asp<\/a><\/p>\n<p>Below is a code sample for how you can write an MSH Script with embedded C# code to invoke a Win32API.<\/p>\n<p><font face=\"Courier New\" size=\"1\">#######################################################################<br \/>#&nbsp; This is a general purpose routine that I put into a file called<br \/>#&nbsp;&nbsp; LibraryCodeGen.msh and then dot-source when I need it.<br \/>#######################################################################<br \/>function Compile-Csharp ([string] $code, $FrameworkVersion=&#8221;v2.0.50727&#8243;, <br \/>[Array]$References)<br \/>{<br \/>&nbsp;&nbsp;&nbsp; #<br \/>&nbsp;&nbsp;&nbsp; # Get an instance of the CSharp code provider<br \/>&nbsp;&nbsp;&nbsp; #<br \/>&nbsp;&nbsp;&nbsp; $cp = new-object Microsoft.CSharp.CSharpCodeProvider<\/p>\n<p>&nbsp;&nbsp;&nbsp; #<br \/>&nbsp;&nbsp;&nbsp; # Build up a compiler params object&#8230;<br \/>&nbsp;&nbsp;&nbsp; $framework = Combine-Path $env:windir &#8220;Microsoft.NET\\Framework\\$FrameWorkVersion&#8221;<br \/>&nbsp;&nbsp;&nbsp; $refs = new Collections.ArrayList<br \/>&nbsp;&nbsp;&nbsp; $refs.AddRange( @(&#8220;${framework}\\System.dll&#8221;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;${mshhome}\\System.Management.Automation.dll&#8221;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;${mshhome}\\System.Management.Automation.ConsoleHost.dll&#8221;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;${framework}\\system.windows.forms.dll&#8221;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;${framework}\\System.data.dll&#8221;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;${framework}\\System.Drawing.dll&#8221;,<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &#8220;${framework}\\System.Xml.dll&#8221;))<br \/>&nbsp;&nbsp;&nbsp; if ($references.Count -ge 1)<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $refs.AddRange($References)<br \/>&nbsp;&nbsp;&nbsp; }<\/p>\n<p>&nbsp;&nbsp;&nbsp; $cpar = New-Object System.CodeDom.Compiler.CompilerParameters<br \/>&nbsp;&nbsp;&nbsp; $cpar.GenerateInMemory = $true<br \/>&nbsp;&nbsp;&nbsp; $cpar.GenerateExecutable = $false<br \/>&nbsp;&nbsp;&nbsp; $cpar.OutputAssembly = &#8220;custom&#8221;<br \/>&nbsp;&nbsp;&nbsp; $cpar.ReferencedAssemblies.AddRange($refs)<br \/>&nbsp;&nbsp;&nbsp; $cr = $cp.CompileAssemblyFromSource($cpar, $code)<\/p>\n<p>&nbsp;&nbsp;&nbsp; if ( $cr.Errors.Count)<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $codeLines = $code.Split(&#8220;`n&#8221;);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; foreach ($ce in $cr.Errors)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; write-host &#8220;Error: $($codeLines[$($ce.Line &#8211; 1)])&#8221;<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $ce |out-default<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Throw &#8220;INVALID DATA: Errors encountered while compiling code&#8221;<br \/>&nbsp;&nbsp;&nbsp; }<br \/>}<\/p>\n<p>###########################################################################<br \/>#&nbsp; Here I leverage one of my favorite features (here-strings) to define<br \/># the C# code I want to run.&nbsp; Remember &#8211; if you use single quotes &#8211; the<br \/># string is taken literally but if you use double-quotes, we&#8217;ll do variable<br \/># expansion.&nbsp; This can be VERY useful.<br \/>###########################################################################<br \/>$code = @&#8217;<br \/>using System;<br \/>using System.Runtime.InteropServices;<\/p>\n<p>namespace test<br \/>{<br \/>&nbsp;&nbsp;&nbsp; public class Testclass<br \/>&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport(&#8220;msvcrt.dll&#8221;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static extern int puts(string c);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [DllImport(&#8220;msvcrt.dll&#8221;)]<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; internal static extern int _flushall();<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static void Run(string message)<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; puts(message);<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _flushall();<br \/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br \/>&nbsp;&nbsp;&nbsp; }<br \/>}<br \/>&#8216;@<\/p>\n<p>##################################################################<br \/># So now we compile the code and use .NET object access to run it.<br \/>##################################################################<br \/>compile-CSharp $code<br \/>[Test.TestClass]::Run(&#8220;Monad ROCKS!&#8221;)<br \/><\/font><font face=\"Courier New\" size=\"1\"><\/font><\/p>\n<p>Enjoy<\/p>\n<p><font face=\"Courier New\" size=\"1\"><font face=\"Times New Roman\" size=\"3\">Jeffrey P. Snover [MSFT]<\/font><\/p>\n<p><\/font><\/p>\n<p>[<i>Edit: Monad has now been renamed to Windows PowerShell.  This script or discussion may require slight adjustments before it applies directly to newer builds.<\/i>]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the very early days of Monad, we&nbsp;focused on&nbsp;a world where everyone would publish Cmdlets and providers.&nbsp; Cmdlets and providers&nbsp;were designed around providing the best user experience.&nbsp; They provide the right, high-level, task-oriented abstractions that users want while also providing the semantic benefits that the Monad engine provides (-WHATIF, -CONFIRM, -VERBOSE, -ERRORACTION, -ERRORVARIABLE, etc etc).&nbsp; [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-10831","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell"],"acf":[],"blog_post_summary":"<p>In the very early days of Monad, we&nbsp;focused on&nbsp;a world where everyone would publish Cmdlets and providers.&nbsp; Cmdlets and providers&nbsp;were designed around providing the best user experience.&nbsp; They provide the right, high-level, task-oriented abstractions that users want while also providing the semantic benefits that the Monad engine provides (-WHATIF, -CONFIRM, -VERBOSE, -ERRORACTION, -ERRORVARIABLE, etc etc).&nbsp; [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/10831","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=10831"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/10831\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=10831"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=10831"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=10831"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}