Jump to content
LarsJ

DotNet.au3 UDF to access .NET Framework from AutoIt

Recommended Posts

LarsJ
ptrex

Hi Lars,

Thanks for jumping on the .NET wagon, and delivering this nice UDF. !! 

In the theoretical background you provided, there's 1 crucial item missing to get to understand the full picture of the .NET CodeDOM Compiler Class ...

The .NET CodeDom Class is just a wrapper around the CSC and VBC EXE. And has some limitations :

https://stackoverflow.com/questions/7852926/microsoft-roslyn-vs-codedom 

CodeDom is a precursor to Roslyn, but is only marginally related. Essentially, CodeDom is a simple and (somewhat) language agnostic way to generate code that was added in .NET 1.0 to support designers (a la WinForms). Because CodeDom was an attempt at providing a unified model that can generate code in C#, VB, and other languages, it lacks high fidelity with any of the languages that it supports (that's why you can't create a switch statement with CodeDom). CSharpCodeProvider.CompileAssemblyFromSource is simply a wrapper around executing csc.exe

...
One big difference I see: with CodeDom, each time you compile some C# or VB.NET, it happens out of process. CSC.exe or VBC.exe are the real workers behind the scene.

So basically you can do the same with just a few lines of code.

DotNet Compiler Wrapper

image64.png

Hopefully you keep us surprising with your expertise on this matter :)

Rgds

ptrex

 

Edited by ptrex

Share this post


Link to post
Share on other sites
LarsJ

Hopefully, I do not offend anyone by saying that the code in CLR.au3 is a bit messy. DotNet.au3 is primarily a rewrite of CLR.au3 so the code appears a bit nicer. And at the same time it's a complete translation of CLR.ahk. DotNet.au3 (and CLR.ahk) can also be used on Windows XP.

I'm not very excited about the .NET Framework or .NET code, so don't expect a lot of code from me.

There are a few topics that I find interesting, which I also find interesting from an AutoIt point of view. One of these topics is the ability to execute compiled code in particular in relation to array manipulations.

This is illustrated in the example with prime numbers. So this is the kind of examples with just a few code lines I have in mind. And for such small pieces of code, I don't think I need anything more advanced than this. All examples I've tested works fine.

There are a few other topics I find interesting. Maybe I'll make a couple of examples for these topics.

The section in first post about .NET concepts is just a simple overview. It certainly is not the full picture of anything. And I don't think you need the full picture to use the UDF or to add compiled C# or VB code to your AutoIt scripts.

Share this post


Link to post
Share on other sites
ptrex

Not offended at all ... always happy to see a good UDF popping up. ;)

Just wanted to complete that background info, which dependencies CodeDom has (relying on CSC.exe and VBC.exe), for those who wants to take a shortcut..

(Please regard this as complementary info)

At least it must have been a good "Brain Gym" for you doing the conversion from AHK to AU3 ;)

Rgds

ptrex

Share this post


Link to post
Share on other sites
junkew

Would be nice to see example on generics. We struggle with the powershell automation namespace when we get a collection of psobjects back. Will check the clr and dotnet udfs to see if this udf gives better result. Endstate should be a broad native support for .net.

Share this post


Link to post
Share on other sites
LarsJ

ptrex, I was very curious to see if it was possible in a straightforward way to translate the AutoHotkey code into AutoIt code. And that was possible. My conclusion is that there is not much they can do in AutoHotkey code that we can't do in AutoIt code.

junkew, I don't think there are many generic examples that are particular interesting from an AutoIt point of view. I have read most of the posts. I have to admit that I have not clicked all the links. I don't use PowerShell so I'll not be able to help in this area.

Share this post


Link to post
Share on other sites
junkew
  1. The general problem we face in clr.au3 but assume with dotnet.au3 will be similar (i will test coming week) is calling methods on generic collections. 
    So also looking for another function in another namespace that return(s) a generic collection and manage it from AutoIt code (no issue in C#).
    Powershell collection is just an example 
Return Value
Type: System.Collections.ObjectModel.Collection(Of PSObject)
A Collection(Of T) collection of PSObject objects that contain the output of the pipeline.

 2 .  Exercise :D instead of compiling with the compilers of .net you can emit on the fly (much harder and did not see many examples on the internet)
      https://docs.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/emitting-dynamic-methods-and-assemblies
      would be in the end similar to FASM solutions but then completely in AutoIt.

Share this post


Link to post
Share on other sites
ptrex

Larj,  Thanks, ....Good to know we don't have to be shy working with AU3 rather than AHK :ILA2:  It's a pitty you don't use PowerShell because it has a lot to offer !  As mentiioned before it can access all .NET classes and much more. But then again if you don't have a use case for it, it makes sense.

Junkew, Yes I still hope someone can break this open how to access the PSOBJECT Members  which is derived a .NET BASE Object:)

AutoIt returns  these values from IsObj () COM Object Type:

$objPsCollection = $pObjectPS.EndInvoke($objAsync)
    
ConsoleWrite("$objPsCollection: " & IsObj($objPsCollection) & @TAB & "$objPsCollection: " & ObjName($objPsCollection) & " - " & ObjName($objPsCollection,6) & " - " & ObjName($objPsCollection,3) & @CRLF)
Quote

$objPsCollection: 1    $objPsCollection: Object - {81C5FE01-027C-3E1C-98D5-DA9C9862AA21} - System.Object

 

 

Share this post


Link to post
Share on other sites
AppleB

In the function DotNet_LoadCScode(), is there a way to reference more than one .dll file?

So far I can only reference one and one of my C# programs uses some non-standard libraries and they need their .dlls referenced in order to work.

Also, it doesn't recognize multiple System dlls. Is there a way to solve this?

Thanks in advance! 

image.png.162842278d150fa8e2c62aba8489ba8c.png

image.png.d58dfa8ee4da3cc998a8548d2ca428cb.png

Share this post


Link to post
Share on other sites
Earthshine
Posted (edited)

you do it like this, your's will have to reflect the libraries you use, this is an example that goes with the sample code I modified for learning purposes. I will attach the program so you can see what it does (multi threaded directory search)

#include "..\..\Includes\DotNet.au3"

Opt( "MustDeclareVars", 1 )

Example()

Func Example()
    ; Compiles C# source code on the fly
    ; Creates a .NET assembly DLL-file in memory
    ; Loads the memory assembly file into the default domain
;   Local $oCode = DotNet_LoadCScode( FileRead( "CodeCS.cs" ), "System.Windows.Forms.dll");
    Local $oCode = DotNet_LoadCScode( FileRead( "Program.cs" ), "Microsoft.CSharp.dll | System.dll | System.Core.dll | System.Data.dll | System.Windows.Forms.dll | System.Data.DataSetExtensions.dll | System.Net.Http.dll | System.Xml.dll | System.Xml.Linq.dll" ) ; You must add the "System.Windows.Forms.dll"
    If @error Then Return ConsoleWrite( "DotNet_LoadCScode ERR" & @CRLF ) ; assembly because of line 1 in the C# code.
    ConsoleWrite( "DotNet_LoadCScode OK" & @CRLF )

    Local $oFoo = DotNet_CreateObject( $oCode, "Foo" ) ; $oFoo is an object of the "Foo" class in the C# code
    Local $str[2] = ["d:\", "*.rul"]
;    ConsoleWrite("Argument 1: " & $str[0] & @CRLF)
;    ConsoleWrite("Argument 2: " & $str[1] & @CRLF)

   If IsObj( $oFoo ) Then $oFoo.Test("d:\", "*.dll")  ; Test is a method (function) of the $oFoo object

EndFunc

if your target does not have those dlls, you will have to provide them.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Diagnostics;

class Foo
{
    public void Test(string dir, string filespec)
    {
//        if (argv.Length < 2)
//        {
//            Console.WriteLine(value: "ERROR: args = null please provide a path and a file specification to search for.");
//            Console.WriteLine(value: "Example: list c:\\ *.dll");
//        }
//        else
//        {       
            //DirectoryInfo testdr = new DirectoryInfo(path: argv[0]);
            //WalkDirectoryTree(testdr, searchname: argv[1]);
            DirectoryInfo testdr = new DirectoryInfo(path: dir);
            WalkDirectoryTree(testdr, searchname: filespec);
//        }
    }

    public static void WalkDirectoryTree(DirectoryInfo dr, string searchname)
    {
        System.IO.FileInfo[] files = null;
        DirectoryInfo[] subDirs = null;

        try
        {
            files = dr.GetFiles(searchname);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        if (files != null)
        {
            foreach (FileInfo fi in files)
            {
                string dir = fi.DirectoryName;
                string file = fi.ToString();
                if (dir.Length <= 3)
                {
                  Console.WriteLine(value: dir + file);
                }
                else
                {
                    Console.WriteLine(value: dir + '\\' + file);
                }
            }
            subDirs = dr.GetDirectories();

            Parallel.ForEach(subDirs, dir => WalkDirectoryTree(dir, searchname));
        }
    }

    public override bool Equals(object obj)
    {
        return base.Equals(obj);
    }

    public override int GetHashCode()
    {
        return base.GetHashCode();
    }

    public override string ToString()
    {
        return base.ToString();
    }
}

notice that I can't use a string array, in order to pass string arrays, Lars said I need to pass arrays of objects, but this is just a sample that works

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
AppleB

It worked! Thank you so much. I really appreciate the quick response AND the solution.

Hope you have a great day!

Share this post


Link to post
Share on other sites
AppleB

Actually, I spoke too soon. Now I am getting these errors and I do not know what they mean. There are more than are in this picture

 

image.thumb.png.9681ba7305db1cc27d08b7f18f2d38de.png

Share this post


Link to post
Share on other sites
Earthshine
Posted (edited)

it looks like your cs code does not compile. does it compile in VSCode or whatever you are using? Where you are compiling, are those libraries installed? You can use NuGet in VSCode to get your libraries you need references to. Anyway, start a new thread

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
AppleB

Well it is only a class library, so it doesnt really compile. But this wasnt a problem when I wasn't connecting to a database..

Share this post


Link to post
Share on other sites
Earthshine
Posted (edited)

class libs should still compile dude, can you make your dlls properly in your IDE? look at the bin output dir for all the necessary DLLS your app needs

you should make a new thread and post sample code. 

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
AppleB

Ok well it compiles to a .dll that i reference in the autoit code. I meant that there was no executable. Im just not sure what it is asking me to do

Share this post


Link to post
Share on other sites
Earthshine
Posted (edited)

well, in your case, would you not rather be using the capability to run your compiled assembly from memory? you are using the LoadCS Code, no?

do me a favor, make this a different support thread and give me the vcsproj files, 

Edited by Earthshine
  • Thanks 1

My resources are limited. You must ask the right questions

 

Share this post


Link to post
Share on other sites
LarsJ

Passing variables and arrays

Passing variables and arrays back and forth between AutoIt code and C#/VB.NET is demonstrated in examples in UsingCSandVB.7z as you can find in bottom of first post in this example. There are two set of examples: A set with C# code and a set with VB code. You can find the examples in these folders:

  • Examples\1) Introductory C# and VB examples\
    • 3) Passing variables\
      • 1) From AutoIt to C# or VB\
      • 2) From C# or VB to AutoIt\
    • 4) Passing 1D arrays\
      • 1) From AutoIt to C# or VB\
      • 2) From C# or VB to AutoIt\
    • 5) Passing 2D arrays\
      • 1) From AutoIt to C# or VB\
      • 2) From C# or VB to AutoIt\

Share this post


Link to post
Share on other sites

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

×