Jump to content

Using .NET libary with AutoIt, possible?


Recommended Posts

ptrex I think  It was my fault while traslating the AHK script.  You need to conver this to AutoIt 

Loop % argCount
        vargs[A_Index-1] := Args[A_Index]

basically a SafeArray.

 
If @NumParams >= 3 Then
 
Make a loop and Add the parameter. Something like this for handle the parameters. 
 
_Test("X", "X", "P1", "P2", "P3")
_Test("X", "X", "Something", 10, 10.10)

Func _Test($Pa = "", $Pb = "", $Parameter1 = "", $Parameter2 = "", $Parameter3 = "")

    If @NumParams >= 3 Then
        Local $Var=0
        For $i = 3 To @NumParams
             $Var=Eval("Parameter" & ($i-2))
            ConsoleWrite($Var & @TAB & "VarType: " & VarGetType($Var)  &  @CRLF)
        Next
    EndIf

EndFunc   ;==>_Test

 

Saludos
 
Link to comment
Share on other sites

^^ There's no need for Eval():

Func _Test($Pa = "", $Pb = "", $Parameter1 = "", $Parameter2 = "", $Parameter3 = "")
    Local $aParams = [$Parameter1, $Parameter2, $Parameter3]

    If @NumParams >= 3 Then
        Local $Var = 0
        For $i = 0 To @NumParams - 3
            $Var = $aParams[$i]
            ConsoleWrite($Var & @TAB & "VarType: " & VarGetType($Var) & @CRLF)
        Next
    EndIf

EndFunc

 

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

Dannyfirex / trancexx : thanks for the input !

Something like this NOT TESTED YET !

Func _CRL_CreateObject(ByRef $oAssembly, $sTypeName = "", $sParameter1 = "", $sParameter2 = "", $sParameter3 = "")
    #forceref $oAssembly, $sTypeName, $sParameter3

    If @NumParams = 2 Then
        Local $oObject = 0
        $oAssembly.CreateInstance_2($sTypeName, True, $oObject)
        Return $oObject
    EndIf

#cs
    If @NumParams = 3 Then
        ; static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
        Local $pSAEmpty, $tSAB = DllStructCreate($tagSAFEARRAYBOUND)
        DllStructSetData($tSAB, "cElements", 0)
        DllStructSetData($tSAB, "lLbound", 0)
        $pSAEmpty = SafeArrayCreate($VT_VARIANT, 0, $tSAB)
        Local $oObject = 0
        $oAssembly.CreateInstance_3($sTypeName, True, 0, 0, CreateSafeArray($sParameter3), 0, $pSAEmpty, $oObject)
        Return $oObject
    EndIf
#ce
    If @NumParams >= 3 Then
        Local $Var = 0
        Local $aParams[@NumParams]

        For $i = 0 To @NumParams - 3
            $Var = $aParams[$i]
            ConsoleWrite($Var & @TAB & "VarType: " & VarGetType($Var) & @CRLF)
        Next

        ; static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
        Local $pSAEmpty, $tSAB = DllStructCreate($tagSAFEARRAYBOUND)
        DllStructSetData($tSAB, "cElements", 0)
        DllStructSetData($tSAB, "lLbound", 0)
        $pSAEmpty = SafeArrayCreate($VT_VARIANT, 0, $tSAB)
        Local $oObject = 0
        $oAssembly.CreateInstance_3($sTypeName, True, 0, 0, CreateSafeArray($aParams), 0, $pSAEmpty, $oObject)
        Return $oObject
    EndIf

EndFunc   ;==>_CRL_CreateObject

 

Edited by ptrex
Link to comment
Share on other sites

 

 

Some things to try based on http://codoid.com/capturing-screen-region/

This below is not working (also not when i remove $x and $y)

The System.Drawing.Graphics seems also not creating an object

Func _Example()
    Local $oAssembly = _CLR_LoadLibrary("mscorlib")
    ConsoleWrite("!$oAssembly: " & IsObj($oAssembly) & @CRLF)

    Local $oAssDrawing = _CLR_LoadLibrary("System.Drawing")
    ConsoleWrite("!$oAssDrawing: " & IsObj($oAssDrawing) & @CRLF)
        
    local $oGraphic=_CRL_CreateObject($oAssDrawing,"System.Drawing.Graphics")
    ConsoleWrite("!$oGraphic " & IsObj($oGraphic) & @CRLF)
    
;~ 'Point structure to specify x and y to capture a region
local $x=10
local $y=10
    local $oPoint=_CRL_CreateObject($oAssDrawing,"System.Drawing.Point",$X,$Y)
    $oPoint.x=15
    ConsoleWrite("!$oPoint " & IsObj($oPoint) & @CRLF)
    ConsoleWrite("!$oPoint " & $oPoint.x & @CRLF)
EndFunc

 

Link to comment
Share on other sites

It's not running in VBA we are pretty sure it is a CLR limitation, correct ?

The issue is that we probably trying call managed code.

As you can read here there are some extra functions needed to do the "unwrap"

http://stackoverflow.com/questions/37074533/how-to-call-net-methods-from-excel-vba

https://msdn.microsoft.com/nl-nl/library/system.runtime.remoting.objecthandle.unwrap(v=vs.110).aspx

More interesting reading here The Complete Interoperability Guide

Some User Case Example here : http://netcode.ru/dotnet/?artID=7476

 

Edited by ptrex
Link to comment
Share on other sites

VBA has its own limitations. Hosting .NET in VBA is probably not the first thing microsoft would have thought of.

VBA Office 2010 I am on and it has limitations in number of types in Variant structure. Not sure if that is better in VBA office 2013.

From my side it looks I am more the limitation myself than VBA or AutoIt is. .NET is huge in possibilities but Microsoft seems to be preferring managed implementations.

local $oPoint=_CRL_CreateObject($oAssDrawing,"System.Drawing.Point",$X,$Y)

creates a value type which is not an object.

As far as I understand this know you have to make a small wrapper in managed code with the different reflection solutions to expose back to the unmanaged language. There are multiple examples on codeproject I am trying to understand a little better.

Somehow that sounds silly to me as what is then the purpose of hosting from an unmanaged language (like AutoIt)

Like larsJ already summarized I feel we should wrap up some stuff and make some nice examples and post the results in examples section to gain some attention from other AutoIt users refer them to this thread so we can more help.

  1. Examples for "all" system.collections.* as thats probably most people are interested in
  2. Examples for the forms as was done so far   (is there any form you cannot do out of the box in AutoIT)
  3. ....

 

 

Link to comment
Share on other sites

Sure, agree on this... If this is published in the wide open forum. There might be other smart people that can shed some light on this too. 

But I would suggest first to try some more examples here. Other then GUI examples.

I will try to test some too... 

Edited by ptrex
Link to comment
Share on other sites

I also found this :

Remarks
 
 

This is a convenience method that combines CreateInstance and ObjectHandle.Unwrap. This method calls the default constructor for typeName.

https://msdn.microsoft.com/en-us/library/3c4f1xde(v=vs.110).aspx

Just to keep us all awake when getting bored :D

Edited by ptrex
Link to comment
Share on other sites

If you replace _CRL_CreateObject and CreateSafeArray in CLR.au3 with the code below it should be possible to handle more parameters.

_CRL_CreateObject:

Func _CRL_CreateObject(ByRef $oAssembly, $sTypeName, $v3 = Default, $v4 = Default, $v5 = Default, $v6 = Default, $v7 = Default, $v8 = Default, $v9 = Default)
  Local $aParams = [ $v3, $v4, $v5, $v6, $v7, $v8, $v9 ], $oObject = 0

  If @NumParams = 2 Then
    $oAssembly.CreateInstance_2($sTypeName, True, $oObject)
    Return $oObject
  EndIf

  Local $iArgs = @NumParams - 2, $aArgs[$iArgs]
  For $i = 0 To $iArgs - 1
    $aArgs[$i] = $aParams[$i]
  Next

  ; static Array_Empty := ComObjArray(0xC,0), null := ComObject(13,0)
  Local $pSAEmpty, $tSAB = DllStructCreate($tagSAFEARRAYBOUND)
  DllStructSetData($tSAB, "cElements", 0)
  DllStructSetData($tSAB, "lLbound", 0)
  $pSAEmpty = SafeArrayCreate($VT_VARIANT, 0, $tSAB)
  
  $oAssembly.CreateInstance_3($sTypeName, True, 0, 0, CreateSafeArray($aArgs), 0, $pSAEmpty, $oObject)
  Return $oObject
EndFunc   ;==>_CRL_CreateObject

CreateSafeArray:

Func CreateSafeArray( $aArgs )
  Local $tSafeArrayBound = DllStructCreate($tagSAFEARRAYBOUND)
  Local $iArgs = UBound( $aArgs ), $pSafeArray, $pSafeArrayData
  DllStructSetData($tSafeArrayBound, "cElements", $iArgs)
  $pSafeArray = SafeArrayCreate($VT_VARIANT, 1, $tSafeArrayBound)

  SafeArrayAccessData($pSafeArray, $pSafeArrayData)

  For $i = 0 To $iArgs - 1
    Switch VarGetType( $aArgs[$i] )
      Case "Bool"
        DllStructSetData(DllStructCreate("word", $pSafeArrayData), 1, $VT_BOOL)
        DllStructSetData(DllStructCreate("short", $pSafeArrayData + 8), 1, $aArgs[$i])
      Case "Double"
        DllStructSetData(DllStructCreate("word", $pSafeArrayData), 1, $VT_R8)
        DllStructSetData(DllStructCreate("double", $pSafeArrayData + 8), 1, $aArgs[$i])
      Case "Int32"
        DllStructSetData(DllStructCreate("word", $pSafeArrayData), 1, $VT_I4)
        DllStructSetData(DllStructCreate("int", $pSafeArrayData + 8), 1, $aArgs[$i])
      Case "String"
        DllStructSetData(DllStructCreate("word", $pSafeArrayData), 1, $VT_BSTR)
        DllStructSetData(DllStructCreate("ptr", $pSafeArrayData + 8), 1, SysAllocString($aArgs[$i]))
    EndSwitch
    $pSafeArrayData += @AutoItX64 ? 24 : 16
  Next

  SafeArrayUnaccessData($pSafeArray)

  Return $pSafeArray
EndFunc   ;==>CreateSafeArray

 

Link to comment
Share on other sites

Extensions from LarsJ are exactly the points I am having trouble with on how to map as there seems not to be one table in AutoIt telling me all the types we somehow support

Help file datatypes gives me

Data Sub-type   Range and Notes
Int32           A 32bit signed integer number.
Int64           A 64bit signed integer number
Double          A double-precision floating point number.
String          Can contain strings of up to 2147483647 characters.
Binary          Binary data, can contain up to 2147483647 bytes.
Pointer         A memory address pointer. 32bit or 64bit depending on the version of AutoIt used.

Help file DllStructCreate gives me some more together with objCreate and objCreateInterface

.NET gives me

VARIANT struct gives me (or in detail in windows SDK include files)

 

And if I then try to use some system.windows.point to put a position of a button its somehow not working

I can understand why as its most likely a structure and not an object (same for system.drawing.point)

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

When you have the point it should be possible to do btn.location=$oPoint 

left/top properties work fine but its more for my understanding on how to map differences between struct/enum and object/properties.
All examples I found so far on the internet make a small wrapper around dynamicobject with the try... methods available since .NET 4.0 in a C# object which you can reach from unmanaged code by com.

 

 

 

 

Edited by junkew
Link to comment
Share on other sites

A few more Examples to include in the release  :) :

;#AutoIt3Wrapper_UseX64=y

#include "CLR.Au3"

_Example()

Func _Example()
    Local $oAssembly = _CLR_LoadLibrary("mscorlib")
    ConsoleWrite("!$oAssembly: " & IsObj($oAssembly) & @CRLF)

    ;1. System.Random Example
    ; https://msdn.microsoft.com/en-us/library/system.random(v=vs.110).aspx
    local $oRnd =_CRL_CreateObject($oAssembly,"System.Random")
    ConsoleWrite("!$oRnd " & IsObj($oRnd) & @CRLF)

    MsgBox(0,".Net CLR", "System.Random # : " & $oRnd.next() & @CRLF)

    ;2. System.String Example
    ; https://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx
    local $oText =_CRL_CreateObject($oAssembly,"System.Text.UTF8Encoding")
    ConsoleWrite("!$oText " & IsObj($oText) & @CRLF & @CRLF)

    local $sPswd = "P@ssW0rd"
    MsgBox(0,".Net CLR",$sPswd & " Text Using : " & @CRLF & "System.Text.UTF8Encoding :" & @CRLF & @CRLF & $oText.GetBytes_4($sPswd))

    local $oSHA512 =_CRL_CreateObject($oAssembly,"System.Security.Cryptography.SHA512Managed")
    ConsoleWrite($oSHA512.ComputeHash_2($oText.GetBytes_4("P@ssW0rd"))   & @CRLF)
    MsgBox(0,".Net CLR",$sPswd & " UTF8Encoding To : " & @CRLF & "System.Security.Cryptography.SHA512Managed :" & @CRLF & @CRLF & $oSHA512.ComputeHash_2($oText.GetBytes_4("P@ssW0rd")))

    ;3. SafeArray RankMismatch Example
    ; https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safearrayrankmismatchexception(v=vs.110).aspx
    local $oSafeArrayError =_CRL_CreateObject($oAssembly,"System.Runtime.InteropServices.SafeArrayRankMismatchException")
    ConsoleWrite(@CRLF & "$oSafeArrayError Obj. : " & IsObj($oSafeArrayError) & @CRLF & _
                "SafeArrayRankMismatch intercepted !" & @CRLF & _
                $oSafeArrayError.data & @CRLF & _
                $oSafeArrayError.HelpLink & @CRLF & _
                $oSafeArrayError.HResult & @CRLF & _
                $oSafeArrayError.InnerException & @CRLF & _
                $oSafeArrayError.Message & @CRLF & _
                $oSafeArrayError.Source & @CRLF & _
                $oSafeArrayError.StackTrace & @CRLF & _
                $oSafeArrayError.TargetSite)
Endfunc

Hi Larj, As Junkew mentioned already the multi-parameter version you posted did not solve the issue unfortunately.

The only possibility is we can get this approach running :  https://msdn.microsoft.com/en-us/library/3c4f1xde(v=vs.110).aspx 

What started off as a mission impossible ended up in a nice project. Which has much more potential then we have seen so far...

Link to comment
Share on other sites

array<Object^>^ args,

Do we think above states its a safearray?

Local $oAssembly = _CLR_LoadLibrary("mscorlib")
    ConsoleWrite("!$oAssembly: " & IsObj($oAssembly) & @CRLF)
    Local $oArrayList = _CRL_CreateObject($oAssembly, "System.Collections.ArrayList")

maybe we can pass $oArrList to _CLR_CreateObject internal createinstance.

;~Local $iArgs = @NumParams - 2, $aArgs[$iArgs]
  Local $oAssembly = _CLR_LoadLibrary("mscorlib")
  ConsoleWrite("!$oAssembly: " & IsObj($oAssembly) & @CRLF)
  $oArrayList=$oAssembly.CreateInstance_2("System.Collections.ArrayList", True, 0)
  ConsoleWrite("!$oArrayList: " & IsObj($oArrayList) & @CRLF)
    
  For $i = 0 To $iArgs - 1
     $oArrayList.Add($aParams[$i])
  Next
  
  $oAssembly.CreateInstance_3($sTypeName, True, 0, 0, $oArrayList, 0, $pSAEmpty, $oObject)

Will try to clean up to see if above works. Didn't work
see more plain code: https://searchcode.com/codesearch/view/59947170/ which indicates logic on safearray is right
 

https://docs.microsoft.com/en-us/dotnet/articles/framework/interop/default-marshaling-for-arrays

 

 

Edited by junkew
reference to marshaling of arrays
Link to comment
Share on other sites

This is again a lot of SafeArray material you posted in those links... good to read but not my cup of tea to honest...

The link you posted from "Searchcode.com" has everything covered apparently :)

Just for information, you can create a .Net Array like this as well, because it is COM Visible

$oArray = ObjCreate( "System.Collections.ArrayList")
        $oArray.Add("F")
        $oArray.Add("D")
        $oArray.Add("B")
        $oArray.Add("C")

        $oArray.Sort

        For $i in $oArray
            ConsoleWrite($i & @CRLF)
        Next

 

 

 

 

Link to comment
Share on other sites

More readings brings us to this restriction :(

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

Quote

Applications that receive less than full trust from their host or sandbox are not allowed to call shared managed libraries unless the library writer specifically allows them to through the use of the AllowPartiallyTrustedCallersAttribute attribute. Therefore, application writers must be aware that some libraries will not be available to them from a partially trusted context. 

...

Libraries must be signed with a strong name in order to be shared by multiple applications. Strong names allow your code to be placed in the global assembly cache or added to the full-trust list of a sandboxing AppDomain, and allow consumers to verify that a particular piece of mobile code actually originates from you.

...

  • In order to disable the automatic LinkDemand and prevent the exception from being thrown, you can place the AllowPartiallyTrustedCallersAttribute attribute on the assembly scope of a shared library. This attribute allows your libraries to be called from partially trusted managed code.

  • Partially trusted code that is granted access to a library with this attribute is still subject to further restrictions defined by the AppDomain.

  • There is no programmatic way for partially trusted code to call a library that does not have the AllowPartiallyTrustedCallersAttribute attribute.

This might be why we are not able to call the method of the .Net assemblies ...

 

 

Link to comment
Share on other sites

Hi all, 

Hope you all have not abandoned the project yet ;) Giving a long weekend ahead of us and bad weather, give us all lot's of free time.

Lets recapitulate where we are :

Most of the things are working, EXCEPT we are not able yet to get access to the native .NET Classes - Methods / Properties / Events etc,

Using the _CRL_CreateObject(), not even with the multi parameter version that was created by Larsj ... :(

Information so far :

Apart from the security issues that might be in the middle see post 121. Which I am not convinced that this is the mean reason why it is not working. 

I found this article showing a working version in VBA : Start reading as of 

Quote

.... Here's your solution, tested for .NET 2.0 and .NET 4.0, 32 bit and 64 bit, courtesy of Soraco Technologies.  

http://stackoverflow.com/questions/37074533/how-to-call-net-methods-from-excel-vba

See this example code : 

Quote

Private Declare PtrSafe Function CorBindToRuntimeEx Lib "mscoree" ( _
    ByVal pwszVersion As LongPtr, _
    ByVal pwszBuildFlavor As LongPtr, _
    ByVal startupFlags As Long, _
    ByRef rclsid As Long, _
    ByRef riid As Long, _
    ByRef ppvObject As mscoree.CorRuntimeHost) As Long

Private Declare PtrSafe Function VariantCopy Lib "oleaut32" (dest, src) As Long


''
' Creates a .Net object with the CLR 4 without registration.  '
''
Function CreateInstance(assembly As String, typeName As String) As Variant
  Const CLR$ = "v4.0.30319"

  Static domain As mscorlib.AppDomain
  If domain Is Nothing Then
    Dim host As mscoree.CorRuntimeHost, hr&, T&(0 To 7)
    T(0) = &HCB2F6723: T(1) = &H11D2AB3A: T(2) = &HC000409C: T(3) = &H3E0AA34F
    T(4) = &HCB2F6722: T(5) = &H11D2AB3A: T(6) = &HC000409C: T(7) = &H3E0AA34F

    hr = CorBindToRuntimeEx(StrPtr(CLR), 0, 3, T(0), T(4), host)
    If hr And -2 Then err.Raise hr

    host.Start
    host.GetDefaultDomain domain
  End If

  VariantCopy CreateInstance, domain.CreateInstanceFrom(assembly, typeName).Unwrap
End Function

If you look at this you can definitely access native .Net Classes. in an unmanaged Host.

Keep in mind that in this code they CorBindToRuntimeEX function, which is obsolete on the meantime. And replaced by the CreateInstance function is CLR.

Review : 

A. This code made me go back to the drawing board and think why does it not work when we instantiate the Object. And AFTERWARD try to access the methods ?

B. So we need to take 1 step back and have a look in which functions are available in the CLR APDDOMAIN function has to offer ?

And what we see is that in the MSCORLIB -> Appdomain there it is where it is ALL HAPPENING

Global Const $sIID_IAppDomain = "{05F696DC-2B29-3663-AD8B-C4389CF2A713}"
Global Const $sTag_IAppDomain = _
        ...
        "remove_AssemblyResolve hresult();" & _
        "add_UnhandledException hresult();" & _
        "remove_UnhandledException hresult();" & _
        "DefineDynamicAssembly hresult();" & _
        "DefineDynamicAssembly_2 hresult();" & _
        "DefineDynamicAssembly_3 hresult();" & _
        "DefineDynamicAssembly_4 hresult();" & _
        "DefineDynamicAssembly_5 hresult();" & _
        "DefineDynamicAssembly_6 hresult();" & _
        "DefineDynamicAssembly_7 hresult();" & _
        "DefineDynamicAssembly_8 hresult();" & _
        "DefineDynamicAssembly_9 hresult();" & _
        "CreateInstance hresult(bstr;bstr;object*);" & _
        "CreateInstanceFrom hresult();" & _
        "CreateInstance_2 hresult();" & _
        "CreateInstanceFrom_2 hresult();" & _
        "CreateInstance_3 hresult();" & _
        "CreateInstanceFrom_3 hresult();" & _
        "Load hresult();" & _
        "Load_2 hresult();" & _
        "Load_3 hresult();" & _
    ...

Meaning that the we need to access the methods as is demontrated in the VBA example.

Quote

domain.CreateInstanceFrom(assembly, typeName).Unwrap

Starting off from the Appdomain using the unique Assembly referance like for example ; mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

and not after the the creation of the CRL_CREATEOBJECT ?

If you take a look using ILSpy in the MSCORLIB you will see that the majority .NET framework is relying on this single Assembly/

We are not far of from getting it done ... believe me MSCORLIB is where the gold is ... 

I will try to post some trial and errors later today, to see how far I get ...

I hope you guys are not giving up this close to the finish line  ?:drool:

Edited by ptrex
Link to comment
Share on other sites

I am certainly not giving up but I think the solution is in safearray (and in the other parts a lot of reading and trying)

https://msdn.microsoft.com/en-us/library/windows/desktop/ms221558(v=vs.85).aspx

as far as I can see the safearray.au3 is a multidimensional array and not a one-dimensional array. 

So when we extend safearray.au3 with the SafeArrayCreateVector function it most likely will work.

DotnetFacorty is doing a small .NET wrapper class around with a createinstance(....,...., par1,par2,par3, .....) and then first make the par1,par n into an array before it calls the actual createinstance method.

All comvisible=false you most likely only reach thru a .NET wrapper class that makes use of the reflection or dynamic parts of later .net versions

interesting link you share for VBA. this way VBA will never die ;-) 

Link to comment
Share on other sites

If I read this code it show what we see in the VBA code ;

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

domain.CreateInstance("Assembly text name, Version, Culture, PublicKeyToken", "MyDynamicType");
using System;
using System.Reflection;
using System.Reflection.Emit;

class Test {
   public static void Main() {
      AppDomain currentDomain = AppDomain.CurrentDomain;

      InstantiateMyDynamicType(currentDomain);   // Failed!

      currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);

      InstantiateMyDynamicType(currentDomain);   // OK!
   }

   static void InstantiateMyDynamicType(AppDomain domain) {
      try {
         // You must supply a valid fully qualified assembly name here. 
         domain.CreateInstance("Assembly text name, Version, Culture, PublicKeyToken", "MyDynamicType");
      } catch (Exception e) {
         Console.WriteLine(e.Message);
      }
   }   

   static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) {
      return DefineDynamicAssembly((AppDomain) sender);
   }

   static Assembly DefineDynamicAssembly(AppDomain domain) {
      // Build a dynamic assembly using Reflection Emit API.

      AssemblyName assemblyName = new AssemblyName();
      assemblyName.Name = "MyDynamicAssembly";

      AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
      ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MyDynamicModule");
      TypeBuilder typeBuilder = moduleBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
      ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, null);
      ILGenerator ilGenerator = constructorBuilder.GetILGenerator();

      ilGenerator.EmitWriteLine("MyDynamicType instantiated!");
      ilGenerator.Emit(OpCodes.Ret);

      typeBuilder.CreateType();

      return assemblyBuilder;
   }
}

If you can figger out the SafeArray mistery, then I will do some Appdomain trial and errors

Here we see all the AppDomain COM interfaces : https://msdn.microsoft.com/en-us/library/system._appdomain(v=vs.110).aspx

Global Const $sIID_IAppDomain = "{05F696DC-2B29-3663-AD8B-C4389CF2A713}"
Global Const $sTag_IAppDomain = _
        "GetTypeInfoCount hresult();" & _
        "GetTypeInfo hresult();" & _
        "GetIDsOfNames hresult();" & _
        "Invoke hresult();" & _
        "get_ToString hresult();" & _
        "Equals hresult();" & _
        "GetHashCode hresult();" & _
        "GetType hresult(ptr*);" & _
        "InitializeLifetimeService hresult();" & _
        "GetLifetimeService hresult();" & _
        "get_Evidence hresult();" & _
        "add_DomainUnload hresult();" & _
        "remove_DomainUnload hresult();" & _
        "add_AssemblyLoad hresult();" & _
        "remove_AssemblyLoad hresult();" & _
        "add_ProcessExit hresult();" & _
        "remove_ProcessExit hresult();" & _
        "add_TypeResolve hresult();" & _
        "remove_TypeResolve hresult();" & _
        "add_ResourceResolve hresult();" & _
        "remove_ResourceResolve hresult();" & _
        "add_AssemblyResolve hresult();" & _
        ...

So this should be something that would return an object ?

$oDomain1.CreateInstance("mscorlib","Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089","System.Text")

 

Link to comment
Share on other sites

Some more background info regarding Appdomain.CreateInstance()

http://www.codemag.com/Article/021108

Quote

Creating Code in Alternate AppDomains

Loading an assembly and creating a class instance from it in a different application domain involves the following steps:

·  Create a new AppDomain.

·  Dynamically create the dynamic assembly and store it to disk.

·  Create a separate assembly that acts as an object factory and returns an Interface rather than a physical object reference. This assembly can be generic and is reusable but must be a separate DLL from the rest of the application.

·  Create an object reference using AppDomain::CreateInstance and then call a method to return the remote Interface. Note the important point here is that an Interface not an object reference is returned.

·  Use the Interface to call into the remote object indirectly using a custom method that performs the passthrough calls to the remote object.

The whole point of this convoluted exercise is to load the object into another AppDomain and access it without using any of the object's type information. Accessing type information via Reflection forces an assembly to load into the local AppDomain and this is exactly what we want to avoid. By using a proxy that only publishes an Interface your code load only a single assembly that publishes this generic Interface.

 

Link to comment
Share on other sites

Added 2 variant functions

1st one creates a static array directly fixed number of parameters

2nd one removes the need for SafeArrayAccessData / SafeArrayUnAccessData

;~ SAFEARRAY* SafeArrayCreateVector(_In_ VARTYPE vt,  _In_ LONG    lLbound,  _In_ ULONG   cElements);
Func SafeArrayCreateVector($vType, $ilBound, $cElements)
    Local $aCall = DllCall("OleAut32.dll", "ptr", "SafeArrayCreateVector", "dword", $vType, "LONG", $ilBound, 'ULONG', $cElements)
    If @error Then Return SetError(1, 0, 0)
    Return $aCall[0]
EndFunc
;~ HRESULT SafeArrayPutElement(  _In_ SAFEARRAY *psa,  _In_ LONG      *rgIndices,  _In_ void      *pv);
Func SafeArrayPutElement($pSA, $rgIndices, $pv)
    Local $aCall = DllCall("OleAut32.dll", "long", "SafeArrayPutElement", "ptr", $pSA, "LONG", $rgIndices, 'ptr', $pv)
    If @error Then Return SetError(1, 0, 0)
    Return $aCall[0]
EndFunc

transforming parts of https://searchcode.com/codesearch/view/59947170/ to see If with a parametrized create_instance3 we get an object to have a clear parametrized example working without direct complexity of point / forms classes that could lead to other issues

// Strings for CreateInstance_3
  asmName = SysAllocString(L"mscorlib");
  typeName = SysAllocString(L"System.Collections.ArrayList");

  // Create a 1D array with one integer element
  SAFEARRAY* psa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
  VariantInit(&param);
  param.vt = VT_I4;
  param.lVal = 128;
  LONG index = 0;

  hresult = SafeArrayPutElement(psa, &index, &param);
  if (FAILED(hresult))
  {
    printf("ERROR: Cannot set SAFEARRAY element: 0x%x\n", hresult);
    Cleanup();
    return -1;
  }

  // Create an instance of ArrayList using a parameterized constructor
  hresult = pDomain->CreateInstance_3(asmName, typeName, VARIANT_TRUE,
    BindingFlags_Default, NULL, psa, NULL, NULL, NULL, &pHandle);
  if (FAILED(hresult))
  {
    printf("ERROR: Cannot create instance: 0x%x\n", hresult);
    Cleanup();
    return -1;
  }

  // Unwrap the ArrayList instance inside the ObjectHandle
  VariantInit(&arrayList);
  hresult = pHandle->Unwrap(&arrayList);
  if (FAILED(hresult))
  {
    printf("ERROR: Could not unwrap object handle: 0x%x\n", hresult);
    Cleanup();
    return -1;
  }

  // Get the IDispatch interface so we can call the Capacity property
  hresult = arrayList.punkVal->QueryInterface(IID_IDispatch,
    (void**)&pDisp);
  if (FAILED(hresult))
  {
    printf("ERROR: Could not get IDispatch interface pointer: 0x%x\n",
      hresult);
    Cleanup();
    return -1;
  }

  // Get the DISPID for the Capacity property
  OLECHAR* name = L"Capacity";
  DISPID dispid;
  hresult = pDisp->GetIDsOfNames(IID_NULL, &name, 1, GetUserDefaultLCID(),
    &dispid);
  if (FAILED(hresult))
  {
    printf("ERROR: GetIDsOfNames failed: 0x%x\n", hresult);
    Cleanup();
    return -1;
  }

  // Invoke the Capacity property
  VARIANT result;
  VariantInit(&result);
  DISPPARAMS params = { NULL, NULL, 0, 0 };

  hresult = pDisp->Invoke(dispid, IID_NULL, GetUserDefaultLCID(),
    DISPATCH_PROPERTYGET, &params, &result, NULL, NULL);
  if (FAILED(hresult))
  {
    printf("ERROR: Invoke failed: 0x%x\n", hresult);
    Cleanup();
    return -1;
  }

  printf("ArrayList Capacity: %d\n", result.lVal);

I assume I need AutoITObject.au3

Is there an alternative to Func _AutoItObject_VariantSet($pVar, $vVal, $iSpecialType = 0) to create a variant?

 

Link to comment
Share on other sites

The code can be translated into AutoIt this way:

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example()

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

CLR.au3.7z

Edited by LarsJ
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...