Jump to content

Using .NET libary with AutoIt, possible?


Recommended Posts

Larsj, you did it again ! :graduated:

This is a Text Append Example :

Example_Text()

Func Example_Text()
  Local $oAppDomain = _CLR_GetDefaultDomain()

  ; Create an instance using a parameterized constructor
  Local $pHandle
  $oAppDomain.CreateInstance( "mscorlib", "System.Text.StringBuilder",  $pHandle )
  ConsoleWrite( @CRLF & "$pHandle = " & $pHandle & @CRLF )

  Local $oHandle = ObjCreateInterface( $pHandle, $sIID_IObjectHandle, $sTag_IObjectHandle )
  ConsoleWrite( @CRLF & "IsObj( $oHandle ) = " & IsObj( $oHandle ) & @CRLF )

  ; Unwrap the ArrayList instance inside the ObjectHandle
  Local $oArrayList
  $oHandle.Unwrap( $oArrayList )
  ConsoleWrite( @CRLF & "IsObj( $oArrayList ) = " & IsObj( $oArrayList ) & @CRLF )

    $vStr1 = "Hello"
    $vStr2 = " World"
    $vStr3 = "  - Larsj did it again !!!! :-) "

    $oArrayList.Append_3($vStr1)
    $oArrayList.Append_3($vStr2)
    $oArrayList.Append_3($vStr3)

  ; Print ArrayList Appended Text
  ConsoleWrite( @CRLF & "$oArrayList.Capacity() = " & $oArrayList.ToString() & @CRLF & @CRLF )
EndFunc

 

Not sure yet when to use the CreateInstance and when the CreateInstance_3 ... we will learn as we go along...

 

Edited by ptrex
Link to comment
Share on other sites

I guess this should be more the explanation that relates to the Appdomain.CreateInstance  ?

Since we are not using the full blown .NET framework but only the AppDomain late bound features ...

https://msdn.microsoft.com/en-us/library/system.appdomain.createinstance(v=vs.110).aspx

So now we need to put it all together to see which types / Methods / properties / ... we can access ?

But since there are different CreateInstances as mentioned in the link I posted here, we need to figure out which one to use in which case...

Yesterday I did a bit more testing and found out that we not just can use 1 syntax to call all .Net Assembly Types :mad:

 

 

Some more interesting references ...

// Activator is an object that contains the Activation (CreateInstance/New) // methods for late bound support.

http://referencesource.microsoft.com/#mscorlib/system/activator.cs,4c7b92371a93f246

AppDomain.CreateInstanceAndUnwrap Method is has C++ examples in there for those can understand it ?

https://msdn.microsoft.com/en-us/library/aa310422(v=vs.71).aspx

https://msdn.microsoft.com/en-us/library/aa310423(v=vs.71).aspx

https://msdn.microsoft.com/en-us/library/aa310424(v=vs.71).aspx

 

Link to comment
Share on other sites

As far as I can see there is nothing new in the code in posts 140 and 141. The code in post 140 could just as well have been implemented in this way, which may even appear to be easier:

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example()

Func Example()
  Local $oAssembly = _CLR_LoadLibrary( "mscorlib" )
  Local $oArrayList = _CRL_CreateObject( $oAssembly, "System.Collections.ArrayList", 128 )
  ConsoleWrite( "$oArrayList.Capacity() = " & $oArrayList.Capacity() & @CRLF )
EndFunc

 

We actually use the _AppDomain Interface. Note that this interface has no CreateInstanceAndUnwrap method.

Link to comment
Share on other sites

Sure so far nothing new...the confusing part is that if you read the internet you always find : AppDomain.CreateInstanceAndUnwrap

As you can see it also refers to Appdomain., correct ?

Is this an undocumented feature ?

So far the major part is built and working, thanks again for that.

But we still have to figure out how to properly access the .net classes using CLR.

Because I tried to access the System.IO.FileInfo 

https://msdn.microsoft.com/en-us/library/system.io.fileinfo(v=vs.110).aspx

And did not succeed ? Error was Null pointer returned :mad:

Link to comment
Share on other sites

@ptrex the numbers are just based on this logic https://msdn.microsoft.com/en-us/library/ms182197(v=vs.140).aspx and goes back to history on how c evolved to c++ and out of that C# with overloaded methods

and part of the calls you make to createinstance.... methods is based on preference. Many ways to reach the same result.

Many examples are on C# (managed) as opposed to C++ and even in C. 

The part on variant.au3 and createvector (Single array) is part of my learning and I think I understand now most based on reading autoitobject udf how thngs are handled in AutoIt by just "simulating" the union of the variant type. 

Unfortunately I miss a lot of details on the objcreateinterface internals to see how that one fits in the whole picture.

  1. objCreate for standard COM
  2. objCreateInterface for non exposed com objects (so not in the registry registered)
  3. .NET hosting what we discuss in this thread and certainly has big relation with point 2
Link to comment
Share on other sites

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example()

Func Example()
  Local $oAssembly = _CLR_LoadLibrary( "mscorlib" )
  Local $oFileInfo = _CRL_CreateObject( $oAssembly, "System.IO.FileInfo", "tst02.txt" )
  ConsoleWrite( "IsObj( $oFileInfo ) = " & IsObj( $oFileInfo ) & @CRLF )
  $oFileInfo.Create()
EndFunc

 

Link to comment
Share on other sites

This proves so far the one int parameter construct (with using createinstance_3) is working 

But when trying this with point which has 2 parameters its somehow not working (so could be the point class or the number of parameters)

So looking for another constructor with 2 double parameters to see if its in this case point not working or something with passing args

sidenote: win32 api allways had a long definition so double is confusing to me anyway;-)  typedef struct tagPOINT { LONG x; LONG y; } POINT, *PPOINT;

but the other system.drawing.point is the logic one (however that one is not used in system.windows for usage with elements of forms)

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example80()

Func Example80()
  Local $oAssembly = _CLR_LoadLibrary( "mscorlib" )
  Local $oArrayList = _CRL_CreateObject( $oAssembly, "System.Collections.ArrayList", 128 )
  ConsoleWrite( "$oArrayList.Capacity() = " & $oArrayList.Capacity() & @CRLF )

  Local $oAssembly2 = _CLR_LoadLibrary( "System.Windows.Forms" )
  ConsoleWrite("$oAssembly2: " & IsObj($oAssembly2) & @CRLF)

  local $oPoint=_CRL_CreateObject($oAssembly2,"System.Windows.Point",150,150)
  ConsoleWrite("!$oPoint: " & IsObj($oPoint) & @CRLF)

  Local $oAssembly3 = _CLR_LoadLibrary( "System.Drawing" )
  ConsoleWrite("$oAssembly3: " & IsObj($oAssembly3) & @CRLF)

  local $oSize=_CRL_CreateObject($oAssembly2,"System.Drawing.Size",150,150)
  ConsoleWrite("!$oSize: " & IsObj($oSize) & @CRLF)



EndFunc

Changing the type in createsafearray from $VT_I4 to $VT_I8 does not make a difference for the point construct.
just to try out when value is 150 changed this part in createsafearray

Case "Int32"
                consolewrite("hitting int32")
                if $aArgs[$i] = 150 Then
                    consolewrite("force double")

                    DllStructSetData(DllStructCreate("word", $pSafeArrayData), 1, $VT_R8)
                    DllStructSetData(DllStructCreate("double", $pSafeArrayData + 8), 1, $aArgs[$i])
                Else
                    DllStructSetData(DllStructCreate("word", $pSafeArrayData), 1, $VT_I4)
                    DllStructSetData(DllStructCreate("int", $pSafeArrayData + 8), 1, $aArgs[$i])
                endif

 

Link to comment
Share on other sites

I'm pretty sure that CreateSafeArray (newest version of CLR.au3 in post 140) generates a proper 1D safearray of variants that also works for multiple parameters. Here demonstrated with two parameters:

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example()

Func Example()
  Local $oDrawing = _CLR_LoadLibrary( "System.Drawing" )
  ConsoleWrite( "IsObj( $oDrawing ) = " & IsObj( $oDrawing ) & @CRLF )
  Local $oFont = _CRL_CreateObject( $oDrawing, "System.Drawing.Font", "Courier New", 20 )
  ConsoleWrite( "IsObj( $oFont ) = " & IsObj( $oFont ) & @CRLF )
EndFunc

So far only Bool, Double, Int32 and String data types (AutoIt data types) are implemented.

 

_CRL_CreateObject creates an object as an instance of a class. I'm also pretty sure that the function will not work if you just replace the class with a structure eg. System.Windows.Point or System.Drawing.Size. You need another function and other methods to handle structures.

Link to comment
Share on other sites

@LarsJ you are right just finished an example to see where the issue is. It must be in point and size beeing a struct and not a class

Func Example81()
  Local $oAssembly2 = _CLR_LoadLibrary("Windowsbase" )
  ConsoleWrite("$oAssembly2:dfgdsgfdg " & IsObj($oAssembly2) & @CRLF)

    Local $oAssemblyCSharp = _CLR_CompileCSharp(FileRead("CodeC#.cs"), "System.dll | System.Windows.Forms.dll")
    If IsObj($oAssemblyCSharp) Then
        ConsoleWrite("$oAssemblyCSharp: " & IsObj($oAssemblyCSharp) & @CRLF)
        Local $oFoo = _CRL_CreateObject($oAssemblyCSharp, "Foo")
        ConsoleWrite("$oFoo: " & IsObj($oFoo) & @CRLF)
        If IsObj($oFoo) Then
            $oFoo.Test()
            consolewrite($oFoo.Age & @CRLF)
            consolewrite($oFoo.aqNameString() & @CRLF)
            consolewrite($oFoo.aqNameInt32() & @CRLF)
            consolewrite($oFoo.aqNameBoolean() & @CRLF)
;~          consolewrite($oFoo.aqNamePoint() & @CRLF)
        endif

        Local $oFoo2 = _CRL_CreateObject($oAssemblyCSharp, "Foo", 1,2 )
        ConsoleWrite("$oFoo: " & IsObj($oFoo2) & @CRLF)
        If IsObj($oFoo2) Then
            $oFoo2.Test()
            consolewrite($oFoo2.Age)
        endif

        Local $oFoo3 = _CRL_CreateObject($oAssemblyCSharp, "Foo", 150,150)
        ConsoleWrite("$oFoo: " & IsObj($oFoo3) & @CRLF)
        If IsObj($oFoo) Then
            $oFoo3.Test()
            consolewrite($oFoo3.Age)
        endif

    EndIf

;~  Local $oAssemblyVB = _CLR_CompileVB(FileRead("CodeVB.cs"), "System.dll | System.Windows.Forms.dll")
;~  If IsObj($oAssemblyVB) Then
;~      ConsoleWrite("$oAssemblyVB: " & IsObj($oAssemblyVB) & @CRLF)
;~      Local $oFoo = _CRL_CreateObject($oAssemblyVB, "Foo")
;~      ConsoleWrite("$oFoo: " & IsObj($oFoo) & @CRLF)
;~      If IsObj($oFoo) Then $oFoo.Test()
;~  EndIf

EndFunc   ;==>_Example81

codec#.cs (compatible with example 1 just 3 default constructors added to see if createinstance_3 is properly called)

using System;
//using System.Drawing;
using System.Windows;
using System.Windows.Forms;

class Foo
{
    //private System.Activator sa = new System.Activator();
    private string tName = "Its empty by default";
    private System.Int32 tAge = 0;
    private System.Boolean tBoolean = true;
    //Reference to windowsbase needed for this system.windows.point to compile
    //private System.Windows.Point tPoint;
    //    private System.Drawing.Point tPoint;


    //Standardized constructors with different names
    public Foo() { tAge = 18;}
    public Foo(int x, int y) { tAge = x + y; }
    public Foo(double x, double y) { tAge = (int)(2 * (x + y)); }

    //Some property getters / setters
    public string Name { get { return tName; } set { tName = value; } }
    public int Age { get { return tAge; } set { tAge = value; } }

    //Assembly qualified names
    public string aqNameString() { return tName.GetType().AssemblyQualifiedName.ToString(); }
    public string aqNameInt32() { return tAge.GetType().AssemblyQualifiedName.ToString(); }
    public string aqNameBoolean() { return tBoolean.GetType().AssemblyQualifiedName.ToString(); }
//    public string aqNamePoint() { return tPoint.GetType().AssemblyQualifiedName.ToString(); }

    //Just a method to be called
    public void Test()
    {
        MessageBox.Show(string.Concat("Hello, world, from C#! ", tAge));
    }
    public void TestPoint()
    {
	//	tPoint=new Point(125,250);
  //      MessageBox.Show(tPoint.X.ToString()+tPoint.Y.ToString());
    }
}

example gives 18, 3, 600 as expected (when forcing 150, 150 to be passed as double)

Edited by junkew
changed code exmample
Link to comment
Share on other sites

I feel the answer should be here https://msdn.microsoft.com/en-us/library/609yztkt(v=vs.95).aspx

some guessing

gettype("system.int32")
gettype("system.string")
gettype("system.windows.point")

https://msdn.microsoft.com/en-us/library/ya5y69ds.aspx

Edited by junkew
Link to comment
Share on other sites

post 150 examples changed to print full assembly qualified name for string, int and boolean

Struggling with point anyway even in C# (class compiles fine in visual studio but not from AutoIt on the fly when point stuff is in the CS file)

conflicts with windowsbase, system.windows.form, system.drawing seems to be the cause.

 

Link to comment
Share on other sites

HI I am learning as we go along...

I was trying a simple test using System.IO.FileSystemInfo and it did not return an object ... after reading a bit I found that you can't access Base Types ...

https://social.technet.microsoft.com/Forums/scriptcenter/en-US/3365d053-4526-4aaa-a14e-1594c08e1e26/powershell-newobject-what-is-the-argumentlist?forum=ITCG

These are easily to recognize when using ILSpy you can see the Blue arrow UP and arrow DOWN. It means that there are other types derived from this BASE TYPE.

In this case you need to access the Derived Types

System.IO.Directorylnfo
System.IO.Filelnfo
 

Example_DirectoryInfo()

Func Example_DirectoryInfo()
  Local $Dir = @UserProfileDir
  Local $oAssembly = _CLR_LoadLibrary( "mscorlib" )
  Local $oDirectoryInfo = _CRL_CreateObject( $oAssembly, "System.IO.DirectoryInfo", $Dir & "\Downloads" )
  ConsoleWrite( "IsObj( $oDirectoryInfo ) = " & IsObj( $oDirectoryInfo ) & @CRLF & @CRLF)

  ConsoleWrite("$oDirectoryInfo.Root() = " &  $oDirectoryInfo.Exists() & @CRLF)

EndFunc

But then again one of the Properties is PARENT and ROOT, but I can't get it to return any values ... ?

Example_DirectoryInfo()

Func Example_DirectoryInfo()
  Local $Dir = @UserProfileDir
  Local $oAssembly = _CLR_LoadLibrary( "mscorlib" )
  Local $oDirectoryInfo = _CRL_CreateObject( $oAssembly, "System.IO.DirectoryInfo", $Dir & "\Downloads" )
  ConsoleWrite( "IsObj( $oDirectoryInfo ) = " & IsObj( $oDirectoryInfo ) & @CRLF & @CRLF)

  ConsoleWrite("$oDirectoryInfo.Root() = " &  $oDirectoryInfo.Parent() & @CRLF)

EndFunc

 

Link to comment
Share on other sites

Edited by junkew
clr via c#
Link to comment
Share on other sites

Hi Junew, these are really specific .Net developer related questions ... ? 

Nice book you shared I will start reading this for sure... 

As far as I know from what I read on the internet, is that we should go and use Reflection in order to get a good view on which Types are available in which Assembly...

Reflection is the only door into the heart of an Assembly for an unmanaged host I would say...

If you open ILSpy you can see the Assemblies : 

System.Reflection &  System.Reflection.Emit

So I guess with the current CLR.Au3 we need to make some functions arround the Reflection Assembly.

This will help answering your above questions on which Object Types we are dealing with and what are the interface methods etc :

https://www.codeproject.com/articles/55710/reflection-in-net

Quote

the System.Reflection namespace provides, and the importance of the Type class in .NET Reflection. You will also learn how to get the type information using different ways. Use of properties and methods of the Type class in .NET Reflection, with examples :

 

Contents

·        Introduction

·        What is .NET Reflection?

·        Road Map

o   The System.Reflection Namespace

o   The System.Type Class

o   Using System.Object.GetType()

o   Using System.Type.GetType()

o   Using the typeof () C# Operator

·        Type Properties

·        Type Methods

·        Reflecting on Methods

·        Reflecting on Fields and Properties

·        Reflecting on Implemented Interfaces

·        Reflecting on Method Parameters and Return Values

·        Reflecting on Constructor

·        Assembly Class

·        Dynamically Loading an Assembly

·        Late Binding

·        Reflection Emit

 

Edited by ptrex
Link to comment
Share on other sites

Hi Larsj,

I am a bit confused (again...) 

In your new version of the CLR.au3 where did the 'unwrap' go ... 

Before the previous approach was like this : Get the Object handle and do an UNWRAP

Func Example()
  Local $oAppDomain = _CLR_GetDefaultDomain()

  ; Create a 1D array with one integer element
  Local $aArgs = [ 128 ], $psa = CreateSafeArray( $aArgs )

  ; Create an instance of ArrayList using a parameterized constructor
  Local $pHandle
  $oAppDomain.CreateInstance_3( "mscorlib", "System.Collections.ArrayList", True, 0, 0, $psa, 0, 0, 0, $pHandle )
  ConsoleWrite( @CRLF & "$pHandle = " & $pHandle & @CRLF )

  Local $oHandle = ObjCreateInterface( $pHandle, $sIID_IObjectHandle, $sTag_IObjectHandle )
  ConsoleWrite( @CRLF & "IsObj( $oHandle ) = " & IsObj( $oHandle ) & @CRLF )

  ; Unwrap the ArrayList instance inside the ObjectHandle
  Local $oArrayList
  $oHandle.Unwrap( $oArrayList )
  ConsoleWrite( @CRLF & "IsObj( $oArrayList ) = " & IsObj( $oArrayList ) & @CRLF )

  ; Print ArrayList Capacity
  ConsoleWrite( @CRLF & "$oArrayList.Capacity() = " & $oArrayList.Capacity() & @CRLF )
EndFunc

 

In the new version I only see that GLOBAL declaration on the UNWRAP interface but not the actual UNWRAP of the Object handle ?

Am I missing something ...  

Link to comment
Share on other sites

You only need unwrapping if you're using the CreateInstance_3 method of the _AppDomain interface to create objects. This is demonstrated in the code in posts 140, 141 and 156.

Don't use CreateInstance_3 method of the _AppDomain interface to create objects. Use _CRL_CreateObject function. _CRL_CreateObject returns an object directly and no unwrapping is needed. _CRL_CreateObject is implemented through the CreateInstance_2 (no parameters) and CreateInstance_3 (one or more parameters) of the _Assembly interface.

In the update of CLR.au3 in post 140 _CRL_CreateObject is not changed at all. There is only added interface definitions (copied directly from mscorlib.tlh) needed to get the code in the post 140 to work.

Link to comment
Share on other sites

Link to comment
Share on other sites

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example_DirectoryInfo()

Func Example_DirectoryInfo()
  Local $Dir = @UserProfileDir
  Local $oAssembly = _CLR_LoadLibrary( "mscorlib" )
  Local $oDirectoryInfo = _CRL_CreateObject( $oAssembly, "System.IO.DirectoryInfo", $Dir & "\Downloads" )
  ConsoleWrite( @CRLF & "@UserProfileDir\Downloads = " & $Dir & "\Downloads" & @CRLF )
  ConsoleWrite( "IsObj( $oDirectoryInfo ) = " & IsObj( $oDirectoryInfo ) & @CRLF )
  ConsoleWrite( "$oDirectoryInfo.Parent() = " & $oDirectoryInfo.Parent().ToString() & @CRLF )
  ConsoleWrite( "$oDirectoryInfo.Root() = " & $oDirectoryInfo.Root().ToString() & @CRLF )
EndFunc

 

Link to comment
Share on other sites

  • Melba23 pinned and unpinned this topic

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...