::::::::: PowerShell :::::::::
Sunday, December 04, 2005
  Calling Win32 API functions through MSH
I have always been wondering if there is a native(in terms of MSH context) way to call Win32 API functions inside MSH. There isn't a built-in way to call Win32 API functions directly.

Oh, don't be disappointed, though. There is a work-around; Dynamic in-memory compilation of C#/VB.net code does the trick.

Well, another day and another day at UseNet newsgroup, I have found the answer.
Solutions were provided by /\/\o\/\/(with VB.net solution) and Jeffery Snover for in-memory compilation of C# code snippet.

My next project will be creating a utility MSH function to ease the pain of declaring and using Win32 API functions

e.g.) new-win32_function declaration [[-ns namespace] [-cn classname]]
new-win32_function "public static extern int puts(string c)" -ns TestNs -cl TestApp
Would let me use "puts" function like the following
MSH> [TestNs.TestApp]::puts("test")


/\/\o\/\/'s VB.NET solution
$provider = new-object Microsoft.VisualBasic.VBCodeProvider
$params = new-object System.CodeDom.Compiler.CompilerParameters
$params.GenerateInMemory = $True
$refs = "System.dll","Microsoft.VisualBasic.dll"
$params.ReferencedAssemblies.AddRange($refs)


# VB.NET EXAMPLE
$txtCode = @'
Class mow
Declare Auto Function MyMessageBox Lib “user32.dll” Alias _
“MessageBox” (ByVal hWnd as Integer, ByVal msg as String, _
ByVal Caption as String, ByVal Tpe as Integer) As Integer
Sub Main()
MyMessageBox(0, "Hello World !!!", "Project Title", 0)
End Sub
end class
'@


$results = $provider.CompileAssemblyFromSource($params, $txtCode)
$mAssembly = $results.CompiledAssembly
$i = $mAssembly.CreateInstance("mow")
$r = $i.main()




and here is the C# solution(Modified a bit to fix syntax error)
Jeffery's C# solution


##################################################### 
# This is a general purpose routine that I put into a file called
# LibraryCodeGen.msh and then dot-source when I need it.
#####################################################
function Compile-Csharp ([string] $code, $FrameworkVersion="v2.0.50727",
[Array]$References)
{
#
# Get an instance of the CSharp code provider
#
$cp = new-object Microsoft.CSharp.CSharpCodeProvider


#
# Build up a compiler params object...
#
"${framework}\System.Data.dll,${framework}\System.dll,${framework}\system.xm­l.dll"


$framework = Combine-Path $env:windir "Microsoft.NET\Framework\$FrameWorkVersion"
$refs = new-object Collections.ArrayList
$refs.AddRange( @("${framework}\System.dll",
"${mshhome}\System.Management.Automation.dll",
"${mshhome}\System.Management.Automation.ConsoleHost.dll",
"${framework}\system.windows.forms.dll",
"${framework}\System.data.dll",
"${framework}\System.Drawing.dll",
"${framework}\System.Xml.dll"))
if ($references.Count -ge 1)
{
$refs.AddRange($References)
}


$cpar = New-Object System.CodeDom.Compiler.CompilerParameters
$cpar.GenerateInMemory = $true
$cpar.GenerateExecutable = $false
$cpar.OutputAssembly = "custom"
$cpar.ReferencedAssemblies.AddRange($refs)
$cr = $cp.CompileAssemblyFromSource($cpar, $code)


if ( $cr.Errors.Count)
{
$codeLines = $code.Split("`n");
foreach ($ce in $cr.Errors)
{
write-host "Error: $($codeLines[$($ce.Line - 1)])"
$ce out-default
}
Throw "INVALID DATA: Errors encountered while compiling code"
}



}

#########################################################
# Here I leverage one of my favorite features (here-strings) to define
# the C# code I want to run. Remember - if you use single quotes - the
# string is taken literally but if you use double-quotes, we'll do variable
# expansion. This can be VERY useful.
#########################################################
$code = '
using System;
using System.Runtime.InteropServices;

namespace test
{
public class Testclass
{
[DllImport("msvcrt.dll")]
public static extern int puts(string c);
[DllImport("msvcrt.dll")]
internal static extern int _flushall();


public static void Run(string message)
{
puts(message);
_flushall();
}
}


}
'

########################################################
# So now we compile the code and use .NET object access to run it.
########################################################
compile-CSharp $code
[Test.TestClass]::Run("Monad ROCKS!")




Has anyone ever noticed that "Solution" sounds better than simply referring it as "answer"?
 
Comments:
>Has anyone ever noticed that "Solution" sounds better than simply referring it as "answer"?

imho, (I'm not native) IS "Solution" better as "Answer", as an answer could be just "No not Possible", but that makes it NOT a "Solution".

gr /\/\o\/\/
 
Post a Comment



<< Home
Let's get lazy with PowerShell!

Name:
Location: Flushing, NY, United States

Experimenting with a different format of blogs...

Links
ARCHIVES
10/01/2005 - 11/01/2005 / 11/01/2005 - 12/01/2005 / 12/01/2005 - 01/01/2006 / 01/01/2006 - 02/01/2006 / 02/01/2006 - 03/01/2006 / 03/01/2006 - 04/01/2006 / 04/01/2006 - 05/01/2006 / 05/01/2006 - 06/01/2006 / 06/01/2006 - 07/01/2006 / 07/01/2006 - 08/01/2006 / 08/01/2006 - 09/01/2006 / 10/01/2006 - 11/01/2006 / 11/01/2006 - 12/01/2006 /


Powered by Blogger