Jump to content

DotNet.au3 UDF to access .NET Framework from AutoIt


LarsJ
 Share

Recommended Posts

hmmmmm. not sure it can. maybe others here can help out here. i've never considered it or tried. i still don't get why you would want to use autoit, do you have a bunch of scripts you already use? c# is fully capable of doing what you need.

Edited by Earthshine

My resources are limited. You must ask the right questions

 

Link to comment
Share on other sites

Link to comment
Share on other sites

2 hours ago, Earthshine said:

hmmmmm. not sure it can. maybe others here can help out here. i've never considered it or tried. i still don't get why you would want to use autoit, do you have a bunch of scripts you already use? c# is fully capable of doing what you need.

for me (as Network engineer not Pro programmer ) autoit is very good for its simplicity and far less  coding lines & time with acceptable performance ,i start to use C# to counter some autoit limitation like (single thread ping tool ,unsupported SNMP v3 , pure SSH , private and public key encryption ) . 

Link to comment
Share on other sites

2 hours ago, ptrex said:

You will find .NET EventHandler Helper Example.au3 in the CLRv3a.zip that relies on a .CS helper function...

This will help get going ...

rgds,

ptrex

 

thanks that help alot here is the working code but i faced weird behavior :-
1- $oTest.add_OnEvent( $oHandler ) =====> i cant understand where is this function and how it work and why to use it at all + when i use 
$Timer.add_Elapsed( $oHandler ) always emit function add_Elapsed not defined error .
2. when i use msgbox in Autoit EventHandler Elapsed event keep firing even i use $timer.AutoReset = false.

any idea ?
 

#include<DotNetAll.au3>

#region Load Test Code
 $oNetCode = DotNet_LoadCScode( FileRead( "CS_Code.cs" ), "System.dll" ) ;*
if not IsObj($oNetCode) then msgbox(0,"","CS code not loaded")

$ClassObject=DotNet_CreateObject( $oNetCode, "AU3")
if not IsObj($ClassObject) then msgbox(0,"","Class Object not Created")

$Timer=$ClassObject.MyMethod()
if not IsObj($timer) then msgbox(0,"","Timer Object not Created")
#endregion


#region event helper
$HelperCode=DotNet_LoadCScode( FileRead( "EventHelper.cs" ), "System.dll" )
if not IsObj($HelperCode) then msgbox(0,"","Helper code not loaded")

$oHelper=DotNet_CreateObject( $HelperCode, "EventHelper")
if not IsObj($oHelper) then msgbox(0,"","Helper Object not Created")
#endregion

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

$oHelper.AddHandler( $Timer, "Elapsed", $pEventHandler )

;~ Local $oHandler = $oHelper.MakeHandler( $pEventHandler )
;~ $Timer.add_Elapsed( $oHandler )                     ;===============> not working
$timer.AutoReset = false
$timer.Enabled=true

sleep(5000)

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 )
;msgbox( 0,"",$obj.SignalTime & @CRLF )         ;=============> if uncommented Msgbox will keep poping up
  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

 

Link to comment
Share on other sites

Network_Guy, The answer here is without reading your last post carefully.

 

Don't return objects back and forth between AutoIt code and C# code. Only integers, floats, strings and arrays. Arrays of arrays (embedded arrays) will also work.

The C# method, which is called from the AutoIt script, must be fairly simple in the definition (the method definition in first line). But in the internal C# code you can do whatever you want.

Events from C# (or VB.NET) code cannot be catched with ObjEvent(). Simpel event handling will typically be impelmented this way (based on an example for the Timer class).

CS_Code.cs:

using System;
using System.Timers;

public class Example
{
  private static System.Timers.Timer aTimer;
  private static string sTime;

  public void Start()
  {
    Console.WriteLine("Timer started at {0:HH:mm:ss.fff}", DateTime.Now);
    Main();
  }

  public string GetTime()
  {
    return sTime;
  }

  public void Stop()
  {
    aTimer.Stop();
    aTimer.Dispose();
    Console.WriteLine("Timer stopped at {0:HH:mm:ss.fff}\n", DateTime.Now);
  }

  private static void Main()
  {
    SetTimer();    
  }

  private static void SetTimer()
  {
    // Create a timer with a one second interval.
    aTimer = new System.Timers.Timer(1000);
    // Hook up the Elapsed event for the timer. 
    aTimer.Elapsed += OnTimedEvent;
    aTimer.AutoReset = true;
    aTimer.Enabled = true;
  }

  private static void OnTimedEvent(Object source, ElapsedEventArgs e)
  {
    sTime = e.SignalTime.ToString("HH:mm:ss.fff");
    //Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}", e.SignalTime);
  }
}
#include <GUIConstantsEx.au3>
#include "DotNetAll.au3"

Example()

Func Example()
  Local $oNetCode = DotNet_LoadCScode( FileRead( "CS_Code.cs" ), "System.dll" ) ; Above C# code
  if Not IsObj( $oNetCode ) Then Return ConsoleWrite( "CS code not loaded" & @CRLF )
  Local $oClassObject = DotNet_CreateObject( $oNetCode, "Example" )
  if not IsObj( $oClassObject ) Then Return ConsoleWrite( "Class Object not Created" & @CRLF )

  Local $hGui = GUICreate( "C# Timer", 200, 100 )
  Local $idStart = GUICtrlCreateButton( "Start", 50, 20, 100, 25 )
  Local $idStop =  GUICtrlCreateButton( "Stop",  50, 55, 100, 25 )
  GUICtrlSetState( $idStop, $GUI_DISABLE )

  Local $bStarted, $sTime, $sTimePrev

  GUISetState()

  While 1
    If $bStarted Then
      $sTime = $oClassObject.GetTime()
      If $sTimePrev <> $sTime Then
        ConsoleWrite( "Timer GetTime at " & $sTime & @CRLF )
        $sTimePrev = $sTime
      EndIf
    EndIf
  
    Switch GUIGetMsg()
      Case $idStart
        $oClassObject.Start()
        GUICtrlSetState( $idStart, $GUI_DISABLE )
        GUICtrlSetState( $idStop, $GUI_ENABLE )
        $bStarted = True

      Case $idStop
        $oClassObject.Stop()
        GUICtrlSetState( $idStart, $GUI_ENABLE )
        GUICtrlSetState( $idStop, $GUI_DISABLE )
        $bStarted = False

      Case $GUI_EVENT_CLOSE
        ExitLoop
    EndSwitch
  WEnd

  If $bStarted Then $oClassObject.Stop()
EndFunc

Run the code in SciTE with F5.

If you need more advanced event handling then look at this post and the following posts. You can find the same code in the thread that ptrex has referred to.

Edited by LarsJ
Run the code in SciTE with F5.
Link to comment
Share on other sites

@LarsJ
thanks for advice , but can i know why passing object between autoit & Dotnet is a bad idea ? , and btw i found that my code which use your CS event handler is working fine , its Dotnet timer class issue when i block event handle function with msgbox() from Link :-
 

Spoiler

If the SynchronizingObject property is null,the Elapsed event is raised on a ThreadPool thread. If the processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In this situation, the event handler should be reentrant.

 finally i found that your c# code calling the autoit function code , using this concept threads can created  from autoit code removing autoit single thread limitation ^_^

 

 

Link to comment
Share on other sites

You're passing a Timer object to the AutoIt code. But can it be used for anything in the AutoIt code? I don't think so. Why then pass it?

Link to comment
Share on other sites

2 hours ago, LarsJ said:

You're passing a Timer object to the AutoIt code. But can it be used for anything in the AutoIt code? I don't think so. Why then pass it?

about timer it just for learning &testing but i will use this knowledge in something useful in future as parallel ping tool , SNMP v3, SSH Client  using autoit without using any external exe , dll , thanks a lot .

 

Edited by Network_Guy
Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...