Jump to content
Sign in to follow this  
mjolnirmarkiv

Using .NET libary with AutoIt, possible?

Recommended Posts

Is the HP "dotnetfactory" a dotnetAssembly ? is so can you provide me a copy so I can look into the Assembly DLL to see if an learn from that code base...

Regarding the reflection I posted some nice material a fews days back, can be of interest to see post 46

.Net Reflection

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

Downside of the reflection is the speed ... compared to te CLR approach is seems. But better slow speed than no speed :)

 


Share this post


Link to post
Share on other sites

Event_handling.au3:

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example()

Func Example()
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelper.cs" ) )
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )

  ; Create our test object, which simply exposes a single event.
  Local $oTest, $oTestAsm = _CLR_CompileCSharp( FileRead( "TestObject.cs" ) )
  $oTestAsm.CreateInstance( "ObjectWithEvent", $oTest )
  ConsoleWrite( "IsObj( $oTest ) = " & IsObj( $oTest ) & @CRLF )

  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  $oHelper.AddHandler( $oTest, "OnEvent", $pEventHandler )

  ; Make an event handler (event must be of the EventHandler type).
  Local $oHandler = $oHelper.MakeHandler( $pEventHandler )
  $oTest.add_OnEvent( $oHandler )

  ; Test the event handlers.
  $oTest.RaiseEvent()
EndFunc

; Our event handler is called with a SAFEARRAY of parameters.  This
; makes it much easier to get the type and value of each parameter.
Func EventHandler( $pprm )
  ConsoleWrite( "$pprm = " & $pprm & @CRLF )

  Local $iDim = SafeArrayGetDim( $pprm )
  ConsoleWrite( "$iDim = " & $iDim & @CRLF )

  Local $iLBound, $iUBound
  SafeArrayGetLBound( $pprm, 1, $iLBound )
  SafeArrayGetUBound( $pprm, 1, $iUBound )
  ConsoleWrite( "$iLBound = " & $iLBound & @CRLF )
  ConsoleWrite( "$iUBound = " & $iUBound & @CRLF )

  Local $tprm = DllStructCreate( $tagSAFEARRAY, $pprm )
  Local $fFeatures = DllStructGetData( $tprm, "fFeatures" )
  ConsoleWrite( "$fFeatures = 0x" & Hex( $fFeatures ) & @CRLF )
  Local $cbElements = DllStructGetData( $tprm, "cbElements" )
  ConsoleWrite( "$cbElements = " & $cbElements & @CRLF )

  Local $vt
  SafeArrayGetVartype( $pprm, $vt )
  ConsoleWrite( "$vt = " & $vt & @CRLF )

  Local $prmData, $tvt, $data, $obj
  SafeArrayAccessData( $pprm, $prmData )

  $tvt = DllStructCreate( "word", $prmData )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + 8 ), 1 )
  $obj = ConvertPtrToIDispatch($data)
  ConsoleWrite( $obj.ToString() & @CRLF )

  $tvt = DllStructCreate( "word", $prmData + ( @AutoItX64 ? 24 : 16 ) )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + ( @AutoItX64 ? 24 : 16 ) + 8 ), 1 )
  $obj = ConvertPtrToIDispatch($data)
  ConsoleWrite( $obj.ToString() & @CRLF )

  SafeArrayUnaccessData( $pprm )
EndFunc

; In the end we still want the autoit object. This function converts a raw pointer to an autoit object
Func ConvertPtrToIDispatch($IDispatch_Ptr)
  ; This would have been 10000x easier if autoit had supported the idispatch* type in dllstructs...
  ; Fortunetely memcpy can copy the pointer into a idispatch*, lucky us.
  $ptr_struct=DllStructCreate("ptr")
  DllStructSetData($ptr_struct,1,$IDispatch_Ptr)
  $aCall = DllCall("ntdll.dll","ptr:cdecl","memcpy","idispatch*","","ptr",DllStructGetPtr($ptr_struct),"long",4)
  return $aCall[1]
EndFunc

EventHelper.cs

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

public class EventHelper {
    // Delegate type for the AutoHotkey callback.
    public delegate void CallbackType([MarshalAs(UnmanagedType.SafeArray)] object[] argv);
    // AddHandler: Adds a callback as a handler for the given event of the given object.
    public void AddHandler(object target, string eventName, string pcb) {
        var cb = ParseCB(pcb);
        // Reference: http://msdn.microsoft.com/en-us/library/ms228976
        EventInfo evt = target.GetType().GetEvent(eventName);
        Type handlerType = evt.EventHandlerType;
        MethodInfo handlerSig = handlerType.GetMethod("Invoke");
        ParameterInfo[] parameters = handlerSig.GetParameters();
        Type[] parameterTypes = new Type[parameters.Length+1];
        parameterTypes[0] = typeof(CallbackType);
        for (int i = 0; i < parameters.Length; i++)
            parameterTypes[i+1] = parameters[i].ParameterType;
        
        var handler = new DynamicMethod("", handlerSig.ReturnType, parameterTypes, true);
        
        var il = handler.GetILGenerator();
        var loc = il.DeclareLocal(typeof(object[]));
        il.Emit(OpCodes.Ldc_I4_2);
        il.Emit(OpCodes.Newarr, typeof(object));
        il.Emit(OpCodes.Stloc_0);
        
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ldc_I4_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Stelem_Ref); 
        
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Ldc_I4_1);
        il.Emit(OpCodes.Ldarg_2);
        il.Emit(OpCodes.Stelem_Ref);
        
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldloc_0);
        il.Emit(OpCodes.Call, typeof(CallbackType).GetMethod("Invoke"));
        il.Emit(OpCodes.Ret);
        
        var delg = handler.CreateDelegate(handlerType, cb);
        var adder = evt.GetAddMethod();
        adder.Invoke(target, new object[] { delg });
    }
    // Much simpler method, restricted to a specific delegate type.
    public EventHandler MakeHandler(string pcb) {
        var cb = ParseCB(pcb);
        return (sender, e) => cb(new object[]{ sender, e });
    }
    public CallbackType ParseCB(string cb) {
        // For 32-bit, simply marking the parameter of AddHandler/MakeHandler with:
        //   [MarshalAs(UnmanagedType.FunctionPtr)] CallbackType cb
        // is adequate, but since IDispatch doesn't support 64-bit integers,
        // we have to pass the callback address as a string for x64 builds.
        return (CallbackType) Marshal.GetDelegateForFunctionPointer(
            (IntPtr)Int64.Parse(cb), typeof(CallbackType));
    }
}

TestObject.cs

public class ObjectWithEvent {
  public void RaiseEvent() {
    if (OnEvent != null)
      OnEvent(this, System.EventArgs.Empty);
  }
  public event System.EventHandler OnEvent;
}

tst00.au3

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example() ; Form Using System.Windows.Forms.Form

Func Example()
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelper.cs" ) )
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )

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

  ConsoleWrite( @CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF )
  Local $oForm = _CRL_CreateObject( $oAssembly, "System.Windows.Forms.Form" )
  ConsoleWrite( "IsObj( $oForm ) = " & IsObj( $oForm ) & @CRLF )

  $oForm.Text = "Form From Net - AutoIt Rocks"
  $oForm.Width = 800
  $oForm.Height = 400

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF )
  Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton1.Text = "button"
  $oButton1.Width = 60
  $oButton1.Height = 30

  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  $oHelper.AddHandler( $oButton1, "Click", $pEventHandler )

  ;$oForm.Controls.Add( $oButton1 ) ; ERR
  $oButton1.Parent = $oForm ; OK

  $oForm.ShowDialog()

  $oForm.Dispose()
EndFunc

; Our event handler is called with a SAFEARRAY of parameters.  This
; makes it much easier to get the type and value of each parameter.
Func EventHandler( $pprm )
  ConsoleWrite( "$pprm = " & $pprm & @CRLF )

  Local $iDim = SafeArrayGetDim( $pprm )
  ConsoleWrite( "$iDim = " & $iDim & @CRLF )

  Local $iLBound, $iUBound
  SafeArrayGetLBound( $pprm, 1, $iLBound )
  SafeArrayGetUBound( $pprm, 1, $iUBound )
  ConsoleWrite( "$iLBound = " & $iLBound & @CRLF )
  ConsoleWrite( "$iUBound = " & $iUBound & @CRLF )

  Local $tprm = DllStructCreate( $tagSAFEARRAY, $pprm )
  Local $fFeatures = DllStructGetData( $tprm, "fFeatures" )
  ConsoleWrite( "$fFeatures = 0x" & Hex( $fFeatures ) & @CRLF )
  Local $cbElements = DllStructGetData( $tprm, "cbElements" )
  ConsoleWrite( "$cbElements = " & $cbElements & @CRLF )

  Local $vt
  SafeArrayGetVartype( $pprm, $vt )
  ConsoleWrite( "$vt = " & $vt & @CRLF )

  Local $prmData, $tvt, $data, $obj
  SafeArrayAccessData( $pprm, $prmData )

  $tvt = DllStructCreate( "word", $prmData )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + 8 ), 1 )
  $obj = ConvertPtrToIDispatch($data)
  ConsoleWrite( $obj.ToString() & @CRLF )

  $tvt = DllStructCreate( "word", $prmData + ( @AutoItX64 ? 24 : 16 ) )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + ( @AutoItX64 ? 24 : 16 ) + 8 ), 1 )
  $obj = ConvertPtrToIDispatch($data)
  ConsoleWrite( $obj.ToString() & @CRLF )

  SafeArrayUnaccessData( $pprm )
EndFunc

; In the end we still want the autoit object. This function converts a raw pointer to an autoit object
Func ConvertPtrToIDispatch($IDispatch_Ptr)
  ; This would have been 10000x easier if autoit had supported the idispatch* type in dllstructs...
  ; Fortunetely memcpy can copy the pointer into a idispatch*, lucky us.
  $ptr_struct=DllStructCreate("ptr")
  DllStructSetData($ptr_struct,1,$IDispatch_Ptr)
  $aCall = DllCall("ntdll.dll","ptr:cdecl","memcpy","idispatch*","","ptr",DllStructGetPtr($ptr_struct),"long",4)
  return $aCall[1]
EndFunc

 

Share this post


Link to post
Share on other sites

Hi Larsj, again a victory with your 'event handler' !!!

Also good to see that the SafeArray do really fit in, into this project...

A lot of hightech code to get it working though, but it works that's most important ...

I was reading through the code, and tried to figure out where you add the trigger in the eventhandler to activate a function ?

Like this :

$oButton1.add_click(test())
Edited by ptrex

Share this post


Link to post
Share on other sites

Chimp, This was a good laugh.

ptrex, Add some Switch statements to the bottom of the event handler. Here demonstrated with MsgBoxes. Note that the MsgBoxes are not blocking. You can use Tab to navigate between buttons and Enter/Space to click.

tst01.au3

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example() ; Form Using System.Windows.Forms.Form

Func Example()
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelper.cs" ) )
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )

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

  ConsoleWrite( @CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF )
  Local $oForm = _CRL_CreateObject( $oAssembly, "System.Windows.Forms.Form" )
  ConsoleWrite( "IsObj( $oForm ) = " & IsObj( $oForm ) & @CRLF )

  $oForm.Text = "Form From Net - AutoIt Rocks"
  $oForm.Width = 800
  $oForm.Height = 400

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF )
  Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton1.Text = "button1"
  $oButton1.Width = 60
  $oButton1.Height = 30
  $oButton1.Left = 100
  $oButton1.Top = 100

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF )
  Local $oButton2 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton2.Text = "button2"
  $oButton2.Width = 60
  $oButton2.Height = 30
  $oButton2.Left = $oButton1.Right + 50
  $oButton2.Top = $oButton1.Top

  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  $oHelper.AddHandler( $oButton1, "Click", $pEventHandler )
  $oHelper.AddHandler( $oButton2, "Click", $pEventHandler )

  ;$oForm.Controls.Add( $oButton1 ) ; ERR
  $oButton1.Parent = $oForm ; OK
  $oButton2.Parent = $oForm ; OK

  $oForm.ShowDialog()

  $oForm.Dispose()
EndFunc

; Our event handler is called with a SAFEARRAY of parameters.  This
; makes it much easier to get the type and value of each parameter.
Func EventHandler( $pprm )
  ConsoleWrite( "$pprm = " & $pprm & @CRLF )

  Local $iDim = SafeArrayGetDim( $pprm )
  ConsoleWrite( "$iDim = " & $iDim & @CRLF )

  Local $iLBound, $iUBound
  SafeArrayGetLBound( $pprm, 1, $iLBound )
  SafeArrayGetUBound( $pprm, 1, $iUBound )
  ConsoleWrite( "$iLBound = " & $iLBound & @CRLF )
  ConsoleWrite( "$iUBound = " & $iUBound & @CRLF )

  Local $tprm = DllStructCreate( $tagSAFEARRAY, $pprm )
  Local $fFeatures = DllStructGetData( $tprm, "fFeatures" )
  ConsoleWrite( "$fFeatures = 0x" & Hex( $fFeatures ) & @CRLF )
  Local $cbElements = DllStructGetData( $tprm, "cbElements" )
  ConsoleWrite( "$cbElements = " & $cbElements & @CRLF )

  Local $vt
  SafeArrayGetVartype( $pprm, $vt )
  ConsoleWrite( "$vt = " & $vt & @CRLF )

  Local $prmData, $tvt, $data, $obj
  SafeArrayAccessData( $pprm, $prmData )

  $tvt = DllStructCreate( "word", $prmData )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + 8 ), 1 )
  $obj = ConvertPtrToIDispatch($data)
  Local $sCtrlInfo = $obj.ToString()
  ConsoleWrite( $sCtrlInfo & @CRLF )

  $tvt = DllStructCreate( "word", $prmData + ( @AutoItX64 ? 24 : 16 ) )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + ( @AutoItX64 ? 24 : 16 ) + 8 ), 1 )
  $obj = ConvertPtrToIDispatch($data)
  ConsoleWrite( $obj.ToString() & @CRLF )

  SafeArrayUnaccessData( $pprm )

  Local $aCtrlInfo = StringSplit( $sCtrlInfo, ", ", 2 ) ; 2 = $STR_NOCOUNT
  For $i = 0 To UBound( $aCtrlInfo ) - 1
    ConsoleWrite( "$i = " & $i & ", $aCtrlInfo[$i] = " & $aCtrlInfo[$i] & @CRLF )
  Next
  Switch $aCtrlInfo[0]
    Case "System.Windows.Forms.Button"
      Switch $aCtrlInfo[3]
        Case "button1"
          MsgBox( 0, "", "button1" )
        Case "button2"
          MsgBox( 0, "", "button2" )
      EndSwitch
  EndSwitch
EndFunc

; In the end we still want the autoit object. This function converts a raw pointer to an autoit object
Func ConvertPtrToIDispatch($IDispatch_Ptr)
  ; This would have been 10000x easier if autoit had supported the idispatch* type in dllstructs...
  ; Fortunetely memcpy can copy the pointer into a idispatch*, lucky us.
  $ptr_struct=DllStructCreate("ptr")
  DllStructSetData($ptr_struct,1,$IDispatch_Ptr)
  $aCall = DllCall("ntdll.dll","ptr:cdecl","memcpy","idispatch*","","ptr",DllStructGetPtr($ptr_struct),"long",4)
  return $aCall[1]
EndFunc

 

Share this post


Link to post
Share on other sites

Hi Larsj,

Working like a charm again one step closer to getting the GUI to run including controls...

Thanks again for all the efforts :graduated: There are still some challenges to tackle though ;)

Trancexx,

Indeed works as well like this ? Thanks for looking over our shoulders :)

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Example() ; Form Using System.Windows.Forms.Form

Func Example()
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelper.cs" ) )
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )

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

  ConsoleWrite( @CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF )
  Local $oForm = _CRL_CreateObject( $oAssembly, "System.Windows.Forms.Form" )
  ConsoleWrite( "IsObj( $oForm ) = " & IsObj( $oForm ) & @CRLF )

  $oForm.Text = "Form From Net - AutoIt Rocks"
  $oForm.Width = 800
  $oForm.Height = 400

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF )
  Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton1.Text = "button1"
  $oButton1.Width = 60
  $oButton1.Height = 30
  $oButton1.Left = 100
  $oButton1.Top = 100

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF )
  Local $oButton2 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton2.Text = "button2"
  $oButton2.Width = 60
  $oButton2.Height = 30
  $oButton2.Left = $oButton1.Right + 50
  $oButton2.Top = $oButton1.Top

  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  $oHelper.AddHandler( $oButton1, "Click", $pEventHandler )
  $oHelper.AddHandler( $oButton2, "Click", $pEventHandler )

  ;$oForm.Controls.Add( $oButton1 ) ; ERR
  $oButton1.Parent = $oForm ; OK
  $oButton2.Parent = $oForm ; OK

  $oForm.ShowDialog()

  $oForm.Dispose()
EndFunc

; Our event handler is called with a SAFEARRAY of parameters.  This
; makes it much easier to get the type and value of each parameter.
Func EventHandler( $pprm )
  ConsoleWrite( "$pprm = " & $pprm & @CRLF )

  Local $iDim = SafeArrayGetDim( $pprm )
  ConsoleWrite( "$iDim = " & $iDim & @CRLF )

  Local $iLBound, $iUBound
  SafeArrayGetLBound( $pprm, 1, $iLBound )
  SafeArrayGetUBound( $pprm, 1, $iUBound )
  ConsoleWrite( "$iLBound = " & $iLBound & @CRLF )
  ConsoleWrite( "$iUBound = " & $iUBound & @CRLF )

  Local $tprm = DllStructCreate( $tagSAFEARRAY, $pprm )
  Local $fFeatures = DllStructGetData( $tprm, "fFeatures" )
  ConsoleWrite( "$fFeatures = 0x" & Hex( $fFeatures ) & @CRLF )
  Local $cbElements = DllStructGetData( $tprm, "cbElements" )
  ConsoleWrite( "$cbElements = " & $cbElements & @CRLF )

  Local $vt
  SafeArrayGetVartype( $pprm, $vt )
  ConsoleWrite( "$vt = " & $vt & @CRLF )

  Local $prmData, $tvt, $data, $obj
  SafeArrayAccessData( $pprm, $prmData )

  $tvt = DllStructCreate( "word", $prmData )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + 8 ), 1 )

    ;~   $obj = ConvertPtrToIDispatch($data)
  $obj = ObjCreateInterface($data, $sIID_IDispatch)

  Local $sCtrlInfo = $obj.ToString()
  ConsoleWrite( $sCtrlInfo & @CRLF )

  $tvt = DllStructCreate( "word", $prmData + ( @AutoItX64 ? 24 : 16 ) )
  $vt = DllStructGetData( $tvt, 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF ) ; EventArgs Class
  $data = DllStructGetData( DllStructCreate( "ptr", $prmData + ( @AutoItX64 ? 24 : 16 ) + 8 ), 1 )
;~   $obj = ConvertPtrToIDispatch($data)
  $obj = ObjCreateInterface($data, $sIID_IDispatch)
  ConsoleWrite( $obj.ToString() & @CRLF )

  SafeArrayUnaccessData( $pprm )

  Local $aCtrlInfo = StringSplit( $sCtrlInfo, ", ", 2 ) ; 2 = $STR_NOCOUNT
  For $i = 0 To UBound( $aCtrlInfo ) - 1
    ConsoleWrite( "$i = " & $i & ", $aCtrlInfo[$i] = " & $aCtrlInfo[$i] & @CRLF )
  Next
  Switch $aCtrlInfo[0]
    Case "System.Windows.Forms.Button"
      Switch $aCtrlInfo[3]
        Case "button1"
          MsgBox( 0, "", "button1" )
        Case "button2"
          MsgBox( 0, "", "button2" )
      EndSwitch
  EndSwitch
EndFunc

#cs
; In the end we still want the autoit object. This function converts a raw pointer to an autoit object
Func ConvertPtrToIDispatch($IDispatch_Ptr)
  ; This would have been 10000x easier if autoit had supported the idispatch* type in dllstructs...
  ; Fortunetely memcpy can copy the pointer into a idispatch*, lucky us.
  $ptr_struct=DllStructCreate("ptr")
  DllStructSetData($ptr_struct,1,$IDispatch_Ptr)
  $aCall = DllCall("ntdll.dll","ptr:cdecl","memcpy","idispatch*","","ptr",DllStructGetPtr($ptr_struct),"long",4)
  return $aCall[1]
EndFunc
#ce

 

 

Edited by ptrex

Share this post


Link to post
Share on other sites

In the code in the post above you can replace

; Add an event handler for the "OnEvent" event.  Use "" to pass the
; address as a string, since IDispatch doesn't support 64-bit integers.
$oHelper.AddHandler( $oButton1, "Click", $pEventHandler )
$oHelper.AddHandler( $oButton2, "Click", $pEventHandler )

with

; Make an event handler (event must be of the EventHandler type).
Local $oHandler = $oHelper.MakeHandler( $pEventHandler )
$oButton1.add_Click( $oHandler )
$oButton2.add_Click( $oHandler )

if you prefer. And in fact it's probably the best way.

 

And in bottom of the event handler it's much better to compare the objects directly instead of just checking the text of the object:

For $i = 0 To UBound( $aObjects ) - 1
  If $obj.Equals( $aObjects[$i] ) Then ExitLoop
Next

If $i < UBound( $aObjects ) Then
  MsgBox( 0, "", $obj.ToString() )
EndIf

 

tst02.au3:

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Global $aObjects[2]

Example() ; Form Using System.Windows.Forms.Form

Func Example()
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelper.cs" ) )
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )

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

  ConsoleWrite( @CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF )
  Local $oForm = _CRL_CreateObject( $oAssembly, "System.Windows.Forms.Form" )
  ConsoleWrite( "IsObj( $oForm ) = " & IsObj( $oForm ) & @CRLF )

  $oForm.Text = "Form From Net - AutoIt Rocks"
  $oForm.Width = 800
  $oForm.Height = 400

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF )
  Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton1.Text = "button1"
  $oButton1.Width = 60
  $oButton1.Height = 30
  $oButton1.Left = 100
  $oButton1.Top = 100
  $aObjects[0] = $oButton1

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF )
  Local $oButton2 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton2.Text = "button2"
  $oButton2.Width = 60
  $oButton2.Height = 30
  $oButton2.Left = $oButton1.Right + 50
  $oButton2.Top = $oButton1.Top
  $aObjects[1] = $oButton2

  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  ;$oHelper.AddHandler( $oButton1, "Click", $pEventHandler )
  ;$oHelper.AddHandler( $oButton2, "Click", $pEventHandler )

  ; Make an event handler (event must be of the EventHandler type).
  Local $oHandler = $oHelper.MakeHandler( $pEventHandler )
  $oButton1.add_Click( $oHandler )
  $oButton2.add_Click( $oHandler )

  ;$oForm.Controls.Add( $oButton1 ) ; ERR
  $oButton1.Parent = $oForm ; OK
  $oButton2.Parent = $oForm ; OK

  $oForm.ShowDialog()

  $oForm.Dispose()
EndFunc

; Our event handler is called with a SAFEARRAY of parameters.  This
; makes it much easier to get the type and value of each parameter.
Func EventHandler( $pprm )
  ConsoleWrite( "$pprm = " & $pprm & @CRLF )

  Local $iDim = SafeArrayGetDim( $pprm )
  ConsoleWrite( "$iDim = " & $iDim & @CRLF )

  Local $iLBound, $iUBound
  SafeArrayGetLBound( $pprm, 1, $iLBound )
  SafeArrayGetUBound( $pprm, 1, $iUBound )
  ConsoleWrite( "$iLBound = " & $iLBound & @CRLF )
  ConsoleWrite( "$iUBound = " & $iUBound & @CRLF )

  Local $tprm = DllStructCreate( $tagSAFEARRAY, $pprm )
  Local $fFeatures = DllStructGetData( $tprm, "fFeatures" )
  ConsoleWrite( "$fFeatures = 0x" & Hex( $fFeatures ) & @CRLF )
  Local $cbElements = DllStructGetData( $tprm, "cbElements" )
  ConsoleWrite( "$cbElements = " & $cbElements & @CRLF )

  Local $vt
  SafeArrayGetVartype( $pprm, $vt )
  ConsoleWrite( "$vt = " & $vt & @CRLF )

  Local $prmData, $pData, $obj
  SafeArrayAccessData( $pprm, $prmData )

  $vt = DllStructGetData( DllStructCreate( "word", $prmData ), 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF & @CRLF ) ; EventArgs Class
  $pData = DllStructGetData( DllStructCreate( "ptr", $prmData + 8 ), 1 )
  $obj = ObjCreateInterface( $pData, $sIID_IDispatch )

  SafeArrayUnaccessData( $pprm )

  For $i = 0 To UBound( $aObjects ) - 1
    If $obj.Equals( $aObjects[$i] ) Then ExitLoop
  Next

  If $i < UBound( $aObjects ) Then
    MsgBox( 0, "", $obj.ToString() )
  EndIf
EndFunc

 

Edited by LarsJ

Share this post


Link to post
Share on other sites

Hi Larsj,

Nice you reworked the EventHandler in clean code ... !

I added some more controls to the Example :

  1. Label
  2. CheckBox
  3. TextBox
  4. ComboBox
  5. Listview : issues here adding columns ?!
;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Global $aObjects[2]

Example() ; Form Using System.Windows.Forms.Form

Func Example()
#Region Register EventHelper
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelper.cs" ) )
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )
#EndRegion

#Region Add Controls
  ConsoleWrite( "_CLR_LoadLibrary System.Windows.Forms" & @CRLF )
  Local $oAssembly = _CLR_LoadLibrary( "System.Windows.Forms" )
  ConsoleWrite( "IsObj( $oAssembly ) = " & IsObj( $oAssembly ) & @CRLF )

  ConsoleWrite( @CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF )
  Local $oForm = _CRL_CreateObject( $oAssembly, "System.Windows.Forms.Form" )
  ConsoleWrite( "IsObj( $oForm ) = " & IsObj( $oForm ) & @CRLF )

  $oForm.Text = "Form From Net - AutoIt Rocks"
  $oForm.Width = 800
  $oForm.Height = 400

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button 1" & @CRLF )
  Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton1.Text = "button1"
  $oButton1.Width = 60
  $oButton1.Height = 30
  $oButton1.Left = 40
  $oButton1.Top = 10
  $aObjects[0] = $oButton1

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button 2" & @CRLF )
  Local $oButton2 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton2.Text = "button2"
  $oButton2.Width = 60
  $oButton2.Height = 30
  $oButton2.Left = $oButton1.Right + 50
  $oButton2.Top = $oButton1.Top
  $aObjects[1] = $oButton2

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.checkbox" & @CRLF )
  Local $checkbox1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.checkbox")
  $checkbox1.Top = 55
  $checkbox1.Left = 155

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ComboBox" & @CRLF )
  Local $Combo = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ComboBox")
  $Combo.Width = 50
  $Combo.Top = 15
  $Combo.Left = 290

    For $i = 1 to 4
        $Combo.Items.Add("test" & $i)
    Next

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Label" & @CRLF )
  Local $Label = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Label")
  $Label.Width = 140
  $Label.Top = 55
  $Label.Left = 15
;~   $Label.Font = "Microsoft Sans Serif, 18pt, style=Bold, Italic" ; Does not Work
  $Label.Text = "Press The Buttons ..."

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.TextBox" & @CRLF )
  Local $Textbox = _CRL_CreateObject($oAssembly, "System.Windows.Forms.TextBox")
  $Textbox.Width = 120
  $Textbox.Top = 55
  $Textbox.Left = 295
  $Textbox.Text = "Enter Text Here ..."

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ListView" & @CRLF )
  Local $ListView = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ListView")
  $ListView.Width = 220
  $ListView.Top = 95
  $ListView.Left = 295

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ColumnHeader" & @CRLF )
  Local $columnHeader1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ColumnHeader")
  ConsoleWrite("$columnHeader1 : " & IsObj($columnHeader1) & @CRLF & @CRLF)

  $ListView.Columns.add($columnHeader1) ; Does not work !!!

#EndRegion

#Region Events
  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  ; $oHelper.AddHandler( $oButton1, "Click", $pEventHandler )
  ; $oHelper.AddHandler( $oButton2, "Click", $pEventHandler )

  ; Make an event handler (event must be of the EventHandler type).
  Local $oHandler = $oHelper.MakeHandler( $pEventHandler )

  $oButton1.add_Click( $oHandler )
  $oButton2.add_Click( $oHandler )
#EndRegion

#Region Add Controls
  ;$oForm.Controls.Add( $oButton1 ) ; ERR
  $oButton1.Parent = $oForm ; OK
  $oButton2.Parent = $oForm
  $checkbox1.Parent = $oForm
  $Combo.Parent = $oForm
  $Label.Parent = $oForm
  $Textbox.Parent = $oForm
  $ListView.Parent = $oForm
#EndRegion

  $oForm.ShowDialog()
  $oForm.Dispose()

EndFunc

#Region EventHandler
; Our event handler is called with a SAFEARRAY of parameters.  This
; makes it much easier to get the type and value of each parameter.
Func EventHandler( $pprm )
  ConsoleWrite( "$pprm = " & $pprm & @CRLF )

  Local $iDim = SafeArrayGetDim( $pprm )
  ConsoleWrite( "$iDim = " & $iDim & @CRLF )

  Local $iLBound, $iUBound
  SafeArrayGetLBound( $pprm, 1, $iLBound )
  SafeArrayGetUBound( $pprm, 1, $iUBound )
  ConsoleWrite( "$iLBound = " & $iLBound & @CRLF )
  ConsoleWrite( "$iUBound = " & $iUBound & @CRLF )

  Local $tprm = DllStructCreate( $tagSAFEARRAY, $pprm )
  Local $fFeatures = DllStructGetData( $tprm, "fFeatures" )
  ConsoleWrite( "$fFeatures = 0x" & Hex( $fFeatures ) & @CRLF )
  Local $cbElements = DllStructGetData( $tprm, "cbElements" )
  ConsoleWrite( "$cbElements = " & $cbElements & @CRLF )

  Local $vt
  SafeArrayGetVartype( $pprm, $vt )
  ConsoleWrite( "$vt = " & $vt & @CRLF )

  Local $prmData, $pData, $obj
  SafeArrayAccessData( $pprm, $prmData )

  $vt = DllStructGetData( DllStructCreate( "word", $prmData ), 1 )
  ConsoleWrite( "$vt = " & $vt & @CRLF & @CRLF ) ; EventArgs Class
  $pData = DllStructGetData( DllStructCreate( "ptr", $prmData + 8 ), 1 )
  $obj = ObjCreateInterface( $pData, $sIID_IDispatch ) ; Convert Pointer to iDispatch

  SafeArrayUnaccessData( $pprm )

  For $i = 0 To UBound( $aObjects ) - 1
    If $obj.Equals( $aObjects[$i] ) Then ExitLoop
  Next

  If $i < UBound( $aObjects ) Then
    MsgBox( 0, "", $obj.ToString() )
  EndIf

EndFunc
#EndRegion

Again issues with adding controls using the .NET syntax :(

Anyhow there are a few more hurdles to take ... like  the  _CRL_CreateObject( xxx, Arg1, Arg2, ...) is missing  list of arguments to pass to the object's constructor.

Examples : 

System.Drawing.Size(130,60)

- System.Drawing.Font("Times New Roman",12)

Also found this was implemented on the AHK CLR :  CLR_CreateObject( Assembly, sType [, Type1, Arg1, Type2, Arg2 ... ] ) (CLR)

Instantiates an object of the specified type from the specified assembly. Optionally accepts a list of arguments to pass to the object's constructor. For AutoHotkey Basic, TypeN is a value from the VARENUM enumeration

Again we are a few steps closer to the finish line ... :)

 

 


Share this post


Link to post
Share on other sites

You don't need to use .Equals to compare objects. AutoIt can do that by itself.

Besides this all can be reduced on both sides, maybe like this:
EventHelper.cs

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.InteropServices;

public class EventHelper {
  // Delegate type for the AutoIt callback.
  public delegate void CallbackType([MarshalAs(UnmanagedType.LPArray)] object[] argv);

  public EventHandler MakeHandler([MarshalAs(UnmanagedType.FunctionPtr)] CallbackType cb) {
    return (sender, e) => cb( new[] {sender} );
  }
}

And then the last example LarsJ posted

#include "CLR.au3"


Global $aObjects[2]
Example() ; Form Using System.Windows.Forms.Form



Func Example()
    ; Compile the helper class. This could be pre-compiled.
    Local $oHelper, $oHelperAsm = _CLR_CompileCSharp(FileRead("EventHelper.cs"))
    $oHelperAsm.CreateInstance("EventHelper", $oHelper)
    ConsoleWrite("IsObj( $oHelper ) = " & IsObj($oHelper) & @CRLF)

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

    ConsoleWrite(@CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF)
    Local $oForm = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Form")
    ConsoleWrite("IsObj( $oForm ) = " & IsObj($oForm) & @CRLF)

    $oForm.Text = "Form From Net - AutoIt Rocks"
    $oForm.Width = 800
    $oForm.Height = 400

    ConsoleWrite(@CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF)
    Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
    $oButton1.Text = "button1"
    $oButton1.Width = 60
    $oButton1.Height = 30
    $oButton1.Left = 100
    $oButton1.Top = 100
    $aObjects[0] = $oButton1

    ConsoleWrite(@CRLF & "_CRL_CreateObject System.Windows.Forms.Button" & @CRLF)
    Local $oButton2 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
    $oButton2.Text = "button2"
    $oButton2.Width = 60
    $oButton2.Height = 30
    $oButton2.Left = $oButton1.Right + 50
    $oButton2.Top = $oButton1.Top
    $aObjects[1] = $oButton2

    Local $hEventHandler = DllCallbackRegister("EventHandler", "int", "ptr")
    Local $pEventHandler = DllCallbackGetPtr($hEventHandler)


    ; Make an event handler (event must be of the EventHandler type).
    Local $oHandler = $oHelper.MakeHandler($pEventHandler)


    $oButton1.add_Click($oHandler)
    $oButton2.add_Click($oHandler)

    $oButton1.Parent = $oForm ; OK
    $oButton2.Parent = $oForm ; OK

    $oForm.ShowDialog()

    $oForm.Dispose()
EndFunc

; Event handler is called with a LPArray of 1 parameter (variant pointer).
Func EventHandler($pprm)

    ConsoleWrite("$pprm = " & $pprm & @CRLF)

    Local $vVar = DllStructCreate($tagVARIANT, $pprm)
    $obj = ObjCreateInterface(DllStructGetData($vVar, "data"), $sIID_IDispatch)

    For $i = 0 To UBound($aObjects) - 1
        If $obj = $aObjects[$i] Then
            MsgBox(0, "", $obj.ToString(), 0, $obj.Handle) ; give it parent handle not to have ten boxes one over other
            ExitLoop
        EndIf
    Next

EndFunc

 


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

trancexx,

Nice clean up ! works like a charm ... but

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Global $aObjects[3]

Example() ; Form Using System.Windows.Forms.Form

Func Example()
#Region Register EventHelper
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelperNEW.cs" ) ) ; NEWER Version
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )
#EndRegion

#Region Add Controls
  ConsoleWrite( "_CLR_LoadLibrary System.Drawing" & @CRLF )
  Local $oAssemblyDraw = _CLR_LoadLibrary( "System.Drawing" )
  ConsoleWrite( "IsObj( $oAssemblyDraw ) = " & IsObj( $oAssemblyDraw ) & @CRLF )

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

  ConsoleWrite( @CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF )
  Local $oForm = _CRL_CreateObject( $oAssembly, "System.Windows.Forms.Form" )
  ConsoleWrite( "IsObj( $oForm ) = " & IsObj( $oForm ) & @CRLF )

  $oForm.Text = "Form From Net - AutoIt Rocks"
  $oForm.Width = 800
  $oForm.Height = 400

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button 1" & @CRLF )
  Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton1.Text = "button1"
  $oButton1.Width = 60
  $oButton1.Height = 30
  $oButton1.Left = 40
  $oButton1.Top = 10
  $aObjects[0] = $oButton1

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button 2" & @CRLF )
  Local $oButton2 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton2.Text = "button2"
  $oButton2.Width = 60
  $oButton2.Height = 30
  $oButton2.Left = $oButton1.Right + 50
  $oButton2.Top = $oButton1.Top
  $aObjects[1] = $oButton2

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.checkbox" & @CRLF )
  Local $checkbox1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.checkbox")
  $checkbox1.Top = 55
  $checkbox1.Left = 155
  $checkbox1.Checked = True

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ComboBox" & @CRLF )
  Local $Combo = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ComboBox")
  $Combo.Width = 50
  $Combo.Top = 15
  $Combo.Left = 290

    For $i = 1 to 4
        $Combo.Items.Add("test" & $i)
    Next

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Label" & @CRLF )
  Local $Label = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Label")
  $Label.Width = 140
  $Label.Top = 55
  $Label.Left = 15
;~   $Label.Font = "Microsoft Sans Serif, 18pt, style=Bold, Italic" ; Does not Work
  $Label.Text = "Press The Buttons ..."

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.TextBox" & @CRLF )
  Local $Textbox = _CRL_CreateObject($oAssembly, "System.Windows.Forms.TextBox")
  $Textbox.Width = 120
  $Textbox.Top = 55
  $Textbox.Left = 295
  $Textbox.Text = "Enter Text Here ..."

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ListView" & @CRLF )
  Local $ListView = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ListView")
  $ListView.Width = 220
  $ListView.Top = 95
  $ListView.Left = 295
  $ListView.Name = "listView1"

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ColumnHeader" & @CRLF )
  Local $columnHeader1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ColumnHeader")
  ConsoleWrite("$columnHeader1 : " & IsObj($columnHeader1) & @CRLF & @CRLF)

  $ListView.Columns.add($columnHeader1) ; Does not work !!!

#EndRegion

#Region Events
  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  ; $oHelper.AddHandler( $oButton1, "Click", $pEventHandler )
  ; $oHelper.AddHandler( $oButton2, "Click", $pEventHandler )

  ; Make an event handler (event must be of the EventHandler type).
  Local $oHandler = $oHelper.MakeHandler( $pEventHandler )

  $oButton1.add_Click( $oHandler )
  $oButton2.add_Click( $oHandler )
  $checkbox1.add_Click( $oHandler )
#EndRegion

#Region Add Controls
  ;$oForm.Controls.Add( $oButton1 ) ; ERR
  $oButton1.Parent = $oForm ; OK
  $oButton2.Parent = $oForm
  $checkbox1.Parent = $oForm
  $Combo.Parent = $oForm
  $Label.Parent = $oForm
  $Textbox.Parent = $oForm
  $ListView.Parent = $oForm
 ; $Panel.Parent = $oForm
#EndRegion

  $oForm.ShowDialog()
  $oForm.Dispose()

EndFunc

#Region EventHandler
; Event handler is called with a LPArray of 1 parameter (variant pointer).
Func EventHandler($pprm)

    ConsoleWrite("$pprm = " & $pprm & @CRLF)

    Local $vVar = DllStructCreate($tagVARIANT, $pprm)
    $obj = ObjCreateInterface(DllStructGetData($vVar, "data"), $sIID_IDispatch)

    For $i = 0 To UBound($aObjects) - 1

        ConsoleWrite("test " & $obj & " " & $aObjects[$i] & @CRLF)

        If $obj = $aObjects[$i] Then
            MsgBox(0, "Event Output", $obj.ToString(), 0, $obj.Handle) ; give it parent handle not to have ten boxes one over other
            ExitLoop
        EndIf
    Next

EndFunc
#EndRegion

Added an event to checkbox but no output ?

the $obj does not return anything ?

 


Share this post


Link to post
Share on other sites
18 minutes ago, ptrex said:

trancexx,

Nice clean up ! works like a charm ... but

;#AutoIt3Wrapper_UseX64=y

#include "CLR.au3"

Global $aObjects[3]

Example() ; Form Using System.Windows.Forms.Form

Func Example()
#Region Register EventHelper
  ; Compile the helper class. This could be pre-compiled.
  Local $oHelper, $oHelperAsm = _CLR_CompileCSharp( FileRead( "EventHelperNEW.cs" ) ) ; NEWER Version
  $oHelperAsm.CreateInstance( "EventHelper", $oHelper )
  ConsoleWrite( "IsObj( $oHelper ) = " & IsObj( $oHelper ) & @CRLF )
#EndRegion

#Region Add Controls
  ConsoleWrite( "_CLR_LoadLibrary System.Drawing" & @CRLF )
  Local $oAssemblyDraw = _CLR_LoadLibrary( "System.Drawing" )
  ConsoleWrite( "IsObj( $oAssemblyDraw ) = " & IsObj( $oAssemblyDraw ) & @CRLF )

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

  ConsoleWrite( @CRLF & "_CRL_CreateObject: System.Windows.Forms.Form" & @CRLF )
  Local $oForm = _CRL_CreateObject( $oAssembly, "System.Windows.Forms.Form" )
  ConsoleWrite( "IsObj( $oForm ) = " & IsObj( $oForm ) & @CRLF )

  $oForm.Text = "Form From Net - AutoIt Rocks"
  $oForm.Width = 800
  $oForm.Height = 400

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button 1" & @CRLF )
  Local $oButton1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton1.Text = "button1"
  $oButton1.Width = 60
  $oButton1.Height = 30
  $oButton1.Left = 40
  $oButton1.Top = 10
  $aObjects[0] = $oButton1

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Button 2" & @CRLF )
  Local $oButton2 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
  $oButton2.Text = "button2"
  $oButton2.Width = 60
  $oButton2.Height = 30
  $oButton2.Left = $oButton1.Right + 50
  $oButton2.Top = $oButton1.Top
  $aObjects[1] = $oButton2

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.checkbox" & @CRLF )
  Local $checkbox1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.checkbox")
  $checkbox1.Top = 55
  $checkbox1.Left = 155
  $checkbox1.Checked = True

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ComboBox" & @CRLF )
  Local $Combo = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ComboBox")
  $Combo.Width = 50
  $Combo.Top = 15
  $Combo.Left = 290

    For $i = 1 to 4
        $Combo.Items.Add("test" & $i)
    Next

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.Label" & @CRLF )
  Local $Label = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Label")
  $Label.Width = 140
  $Label.Top = 55
  $Label.Left = 15
;~   $Label.Font = "Microsoft Sans Serif, 18pt, style=Bold, Italic" ; Does not Work
  $Label.Text = "Press The Buttons ..."

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.TextBox" & @CRLF )
  Local $Textbox = _CRL_CreateObject($oAssembly, "System.Windows.Forms.TextBox")
  $Textbox.Width = 120
  $Textbox.Top = 55
  $Textbox.Left = 295
  $Textbox.Text = "Enter Text Here ..."

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ListView" & @CRLF )
  Local $ListView = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ListView")
  $ListView.Width = 220
  $ListView.Top = 95
  $ListView.Left = 295
  $ListView.Name = "listView1"

  ConsoleWrite( @CRLF & "_CRL_CreateObject System.Windows.Forms.ColumnHeader" & @CRLF )
  Local $columnHeader1 = _CRL_CreateObject($oAssembly, "System.Windows.Forms.ColumnHeader")
  ConsoleWrite("$columnHeader1 : " & IsObj($columnHeader1) & @CRLF & @CRLF)

  $ListView.Columns.add($columnHeader1) ; Does not work !!!

#EndRegion

#Region Events
  Local $hEventHandler = DllCallbackRegister( "EventHandler", "int", "ptr" )
  Local $pEventHandler = DllCallbackGetPtr( $hEventHandler )

  ; Add an event handler for the "OnEvent" event.  Use "" to pass the
  ; address as a string, since IDispatch doesn't support 64-bit integers.
  ; $oHelper.AddHandler( $oButton1, "Click", $pEventHandler )
  ; $oHelper.AddHandler( $oButton2, "Click", $pEventHandler )

  ; Make an event handler (event must be of the EventHandler type).
  Local $oHandler = $oHelper.MakeHandler( $pEventHandler )

  $oButton1.add_Click( $oHandler )
  $oButton2.add_Click( $oHandler )
  $checkbox1.add_Click( $oHandler )
#EndRegion

#Region Add Controls
  ;$oForm.Controls.Add( $oButton1 ) ; ERR
  $oButton1.Parent = $oForm ; OK
  $oButton2.Parent = $oForm
  $checkbox1.Parent = $oForm
  $Combo.Parent = $oForm
  $Label.Parent = $oForm
  $Textbox.Parent = $oForm
  $ListView.Parent = $oForm
 ; $Panel.Parent = $oForm
#EndRegion

  $oForm.ShowDialog()
  $oForm.Dispose()

EndFunc

#Region EventHandler
; Event handler is called with a LPArray of 1 parameter (variant pointer).
Func EventHandler($pprm)

    ConsoleWrite("$pprm = " & $pprm & @CRLF)

    Local $vVar = DllStructCreate($tagVARIANT, $pprm)
    $obj = ObjCreateInterface(DllStructGetData($vVar, "data"), $sIID_IDispatch)

    For $i = 0 To UBound($aObjects) - 1

        ConsoleWrite("test " & $obj & " " & $aObjects[$i] & @CRLF)

        If $obj = $aObjects[$i] Then
            MsgBox(0, "Event Output", $obj.ToString(), 0, $obj.Handle) ; give it parent handle not to have ten boxes one over other
            ExitLoop
        EndIf
    Next

EndFunc
#EndRegion

Added an event to checkbox but no output ?

the $obj does not return anything ?

 

Shouldn't you have $aObjects[2] = $checkbox1 somewhere there?


♡♡♡

.

eMyvnE

Share this post


Link to post
Share on other sites

Listview. Can't you use the parent parameter of $columnHeader1?

So far CLR.au3 only contains code that is used in the specific examples.

The code in my examples is not finished code. So it may well be possible to optimize some bits of the code.

EventHelper.cs. The AddHandler function is not used in these examples. But I still think there is a need for it. Eg. to detect events generated through C#/VB code.

trancexx, Do you have an idea of what this problem with Controls.Add and Columns.Add (Form.Controls.Add(Button), ListView.Columns.Add(ColumnHeader)) is? And if so how we solve the problem?

Share this post


Link to post
Share on other sites

The question is first to find out where the problem is in CLR or in AU3 ?

Junkew can you do a test if it works in VBA ? 

Larsj is it working in AHK ?

If it is not working there it is not an AU3 issue but a limitation of CLR. :mad:

Edited by ptrex

Share this post


Link to post
Share on other sites

Little to busy with other stuff maybe in the weekend Ï will try further

Nice reading on

Share this post


Link to post
Share on other sites

So far we have successfully been able to implement the following:

  • Load the Common Language Runtime (CLR) into the AutoIt process (post 25 by Danyfirex)
  • Examples in the following posts by Danyfirex, junkew and ptrex
  • From the code in post 25 it was possible to create the _AppDomain object (post 56)
  • From there we've managed to translate two AutoHotkey examples. The first example in post 62 loads a XPTable.dll assembly, creates a listview with checkboxes and buttons, and displays the listview in an AutoIt GUI. The second example in post 65 compiles and executes C#-code on the fly.
  • Danyfirex has collected all code and examples in the zip file in post 68
  • At this point we can load .Net assemblies (DLL-files), compile and execute C#/VB-code on the fly and create simple Windows.Forms GUIs.
  • Example code by ptrex and junkew in posts 80 - 98 shows some issues with .Net Windows.Forms code related to collections of controls.
  • Examples in posts 102 - 110 demonstrates how to handle events. Two event handlers are translated from AutoHotkey code in post 102. trancexx has shown an event handler with reduced code in post 110. (If $aObjects[] is replaced with a dictionary object, the array loop in bottom of the event handler function can be avoided and replaced by a dictionary lookup.)
  • With these event handlers we can handle events from Windows.Forms controls, .Net assemblies and C#/VB-code

We've been able to implement all this without too overwhelming effort. Personally I'm happy with what we've achieved and that means I'll scale down my own efforts significantly.

It should be possible to create up to several interesting UDFs based on the code in previous posts. Of course the code has to be completed and cleaned up but that should not be too hard. I'll not go into this. Maybe I'll create a few UDFs for my own purposes. But it'll not be soon.

It has been fun. Regards Lars.

Share this post


Link to post
Share on other sites

LarsJ, My thanks as well, you made it at least possible to access the .Net framework !!!

Junkew,

if I look at the AHK examples there is an other issue not solved yet and that is the parameters, that are missing in the _CRL_CreateObject.

Like this :

drawing := CLR_LoadLibrary("System.Drawing")
headerFont := CLR_CreateObject(drawing, "System.Drawing.Font", "Tahoma", 20)
rowFont := CLR_CreateObject(drawing, "System.Drawing.Font", "Tahoma", 12)

This is crucial in many in many of this objects; that need to be created, not only the GUI Controls...

Anyhow let's see how this evolves... the links you posted is definitely interesting reading material too.


Share this post


Link to post
Share on other sites

@ptrex

Did we already have an example on that parameter thing? should be "straight forward" with a safe array as args parameter

public:
[SecurityCriticalAttribute]
[ObsoleteAttribute("Methods which use evidence to sandbox are obsolete and will be removed in a future release of the .NET Framework. Please use an overload of CreateInstance which does not take an Evidence parameter. See http://go.microsoft.com/fwlink/?LinkID=155570 for more information.")]
static ObjectHandle^ CreateInstance(
    AppDomain^ domain,
    String^ assemblyName,
    String^ typeName,
    bool ignoreCase,
    BindingFlags bindingAttr,
    Binder^ binder,
    array<Object^>^ args,
    CultureInfo^ culture,
    array<Object^>^ activationAttributes,
    Evidence^ securityAttributes
)

some HP UFT dotnetfactory examples (so no reason to believe it will not work in AutoIt)

Set dialogForm = DotNetFactory.CreateInstance("System.Windows.Forms.Form", "System.Windows.Forms")
            Set dialogStartPosition = DotNetFactory.CreateInstance("System.Windows.Forms.FormStartPosition", "System.Windows.Forms")
            Set dialogBorderStyle = DotNetFactory.CreateInstance("System.Windows.Forms.FormBorderStyle", "System.Windows.Forms")
            Set dialogLabel = DotNetFactory.CreateInstance("System.Windows.Forms.Label", "System.Windows.Forms")
            Set dialogFont = DotNetFactory.CreateInstance("System.Drawing.Font", "System.Drawing", "Microsoft Sans Serif", 11)
            Set dialogContentAlign = DotNetFactory.CreateInstance("System.Drawing.ContentAlignment", "System.Drawing")

 

Share this post


Link to post
Share on other sites

Hi Junkew / Larsj,

This is the CreateObject function, it only accepts 1 parameter ?

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

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

    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

EndFunc   ;==>_CRL_CreateObject

If it exceeds 3 parameters or more, the SafeArray should probably be loaded with the additional parameters  data.

By looping through the parameters, this can be passed on to the $Assembly.CreateInstance_3

This is the AHK function ... https://pastebin.com/G1BrL6p6

CLR_CreateObject(Assembly, TypeName, Args*)
{
    if !(argCount := Args.MaxIndex())
        return Assembly.CreateInstance_2(TypeName, true)
   
    vargs := ComObjArray(0xC, argCount)
    Loop % argCount
        vargs[A_Index-1] := Args[A_Index]
   
    static Array_Empty := ComObjArray(0xC,0), nulln := ComObject(13,0)
   
    return Assembly.CreateInstance_3(TypeName, true, 0, nulln, vargs, nulln, Array_Empty)
}

Example is like this :

;~  #AutoIt3Wrapper_UseX64=y

#include "CLR.Au3"

_Example()

Func _Example()
;~  Local $ofrmAssembly = _CLR_LoadLibrary("System.Windows.Forms")
    Local $oAssembly = _CLR_LoadLibrary("System.Windows.Forms")

    ConsoleWrite("!$oAssembly: " & IsObj($oAssembly) & @CRLF)
    Local $oForm = _CRL_CreateObject($oAssembly, "System.Windows.Forms.Form")
    ConsoleWrite("!$oForm: " & IsObj($oForm) & @CRLF)

$oform.name="Form1"

#Region dynamic controls
 $oCol=$oForm.controls
 ConsoleWrite("!$oCol: " & IsObj($oCol) & @CRLF)

 Local $oBtn= _CRL_CreateObject($oAssembly, "System.Windows.Forms.Button")
 ConsoleWrite("!$oBtn " & IsObj($oBtn) & @CRLF)
 $oBtn.Name="Button1"
 $oBtn.Text="Button1"
 $oBtn.Top = 20
 $oBtn.Width=80
 $oBtn.Left = 150

 Local $oText= _CRL_CreateObject($oAssembly, "System.Windows.Forms.TextBox")
 ConsoleWrite("!$oText: " & IsObj($oText) & @CRLF)
  $oText.Top = 20
  $oText.Left = 20
  $oText.Text = "Font Test"

#cs AHK Syntax using Paramters is missing in AU3 - https://pastebin.com/G1BrL6p6
  drawing := CLR_LoadLibrary("System.Drawing")
  headerFont := CLR_CreateObject(drawing, "System.Drawing.Font", "Tahoma", 20)
  rowFont := CLR_CreateObject(drawing, "System.Drawing.Font", "Tahoma", 12)
 #ce
 Local $drawing = _CLR_LoadLibrary("System.Drawing")
 ConsoleWrite("!$drawing: " & IsObj($drawing) & @CRLF)

 $oFontText = _CRL_CreateObject($drawing, "System.Drawing.Font","Courier New", 10, 20)
 ConsoleWrite("!$oFontText: " & IsObj($oFontText) & @CRLF)

;~  Local $oSize = _CRL_CreateObject($drawing, "System.Drawing.Size", 10, 20)
;~  ConsoleWrite("!$oSize: " & IsObj($oSize) & @CRLF)
;~  $oBtn.Size = $oSize

;~  $oForm.opacity=0.75
 $oForm.Text = "Form From Net - AutoIt Rocks"
 $oForm.Width = 800
 $oForm.Height = 400

 ;~  consolewrite("ocol.count " & $ocol.count & @crlf)
 ;~  $oForm.controls.Add($oText) ; this does does not work ?!

 $oBtn.parent = $oForm
 $oText.parent = $oForm

#EndRegion

;~  $oForm.Show()
    $oForm.ShowDialog()

;~     Sleep(1000)

    ConsoleWrite("$oForm Handle: " & $oForm.Handle & @CRLF)

    $oForm.Dispose()

EndFunc   ;==>_Example

Most of the Type constructors have 2 or more parameters... so without handling this properly the use is very limited.

 


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
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Colduction
      Hi AutoIt Scripters/Programmers. I have a question about MIME Tools for Notepad++:
      I've recently found a UDF about Base64 in forum, but they can't decode\encode correctly some emojis , other UTFs and etc. so i decided to use mimeTools.dll of Notepad++ or main site
      My problem is how to use this dll in AutoIt Language?

      I will be happy with your comments and answers❤ Thanks.
    • By FrancescoDiMuro
      Good morning Forums 
      In these days, I am working on a project that involved me to use some Windows APIs to obtain some information about Terminal Servers.
      I'm doing this using wtsapi32.dll in a VBA Project, but, the lack of knowledge about few things threated in the articles make this quite difficult to
      implement and understand at the same time.
      The most difficult thing I'm facing is "translating" C/C++ functions or struct in VBA when pointers are used, or pointers of pointers, and so on.
      Since VBA seems to not have a pointer type, to make those functions work I need to implement other functions taken from other DLLs, and this confuses me a lot.
      For example, starting from this code, I splitted all the functions and all the definitions to understand why they are there, and why I need to use them.
      At the end, I've found out that the code I was going to implement starting from the functions provided in the Microsoft Docs won't be ever be able to work without some supplementary functions which are not mentioned anywhere.
      So, I was wondering if someone would please point me out to a good and practical exaplanation about pointers (in general) or specifically for VBA, because I need to use them quite often in these days, and I'd like to understand what I am doing.
      Thanks in advance.

      Best Regards and Stay at home 🏡
       
    • By zuladabef
      All my scripts were working fine and now I am getting this error.  How do I resolve it?  Which folder(s) do the DLLs need to be in?
      ! Dll not found or Call Dll error !  
    • By RAMzor
      Hello all!
      I got the Acroname Programmable USB Hub based on BrainStem platform. I will use it to manage ports and read current.
      They have development kit (BRAINSTEM DEVELOPMENT KIT) with examples for any languages like C#, C++, LabVIEW and python but no AutoIt.
      The kit include BrainStem2.dll (x32 and x64), BrainStem2_LabVIEW.dll, BrainStem2CLI.dll and many examples.
      Anyone used this dll and implemented it in AutoIt?
      Please share some example for Device Discovering, User LED Flashing or power enable/disable on port to start play with this HUB
      BrainStem Reference 
       
      BrainStem2 lib+example.7z USB HUB User Manual s79-usbhub-3p_v1.10_0.pdf
    • By matwachich
      Hi guys!
      A pretty simple UDF to convert HTML to PDF using wkHTMLtoPDF.
      It uses the C API of the tool (DLL), so no external process, no ActiveX or COM sh*t.
      See the example, and the documentation of wkHTMLtoPDF.
      Cheers
      https://github.com/matwachich/wkhtmltopdf-au3
×
×
  • Create New...