Sign in to follow this  
Followers 0
Uten

AutoIt script plugin

8 posts in this topic

#1 ·  Posted (edited)

Demonstration of a simple Autoit script plug-in architecture.

I have a fascination for distributed computing. Collecting the power of spare CPU cycles within a organization or on computers administrated by people willing to donate spare resources (and electricity).

When I took a look at Blue Security "opt out spam client", I realized that AutoIt could be a very strong contender if you need to build a quick distributed computing system.

The first step towards a simple distributed computing framework utilizing AutoIts compact core language and a selection of powerful functions, was do collect the code fragments needed to support a plug-in architecture.

This is what I came up with:

  • mainProg.au3: Basically a simple installation program. It has to contain the Autoit compiler, your application scripts and probably some default plug-ins.
  • runner.au3: The application script. It will be modified and compiled by mainProg.au3 to use the plug-ins (default, user-modified or downloaded from the net).
  • plugin.au3: A default plug-in used to demonstrate "prof of concept".
I also defined a api provided by the runner (implemented in runner.au3). The api can be used by plug-ins.
  • apiMsg( $argMsg ): A message function.
  • $apiVersion: A global variable containing a version number.
To let the runner know how to use the plug-in the plug-in has to implement a specific interface. In this case it is rather simple:

* IRun(): Called by runner to run plug-in code.

* ITerminate(): Called by runner to lett plug-in clean up and terminate (ex: external processes)

So here goes. A the simplest working plug-in sample. NOTE: You have to modify paths to reflect your development machine (necessary places should be marked with TODO:)

; PURPOSE:  Demonstarting a Autoit Plug-in architecture.
;            This is the plugin used by runner.au3. It could be 
;             downloaded from the net or modified by a user.
; FILENAME:   plugin.au3
; CREATED BY: Uten
; HOME:
; CHANGE LOG:
;----------------------------------------------------------------------
; Uten    14 mar 2006: Published
;
;----------------------------------------------------------------------
Func IRun()
    apiMsg("Hello from plug-in" & @CRLF & "I have done my work.:D")
EndFunc
Func ITerminate()
    msgbox(0,"Plug-in sample, in plug-in", "Terminating" & @CRLF & "NOTE: $apiVersion:=" & $apiVersion & @CRLF & "I have cleand up my act")
EndFunc

; PURPOSE:  Demonstarting a Autoit Plug-in architecture.
;            This is the real application. Define api to be used by 
;            plug-ins here.
; FILENAME:   runner.au3
; CREATED BY: Uten
; HOME:
; CHANGE LOG:
;----------------------------------------------------------------------
; Uten    14 mar 2006: Published
;
;----------------------------------------------------------------------

Global $apiVersion="1.0"; Global variable accessable from the 
Func apiMsg($argMsg)
        msgbox(0, "Plug-in sample, runner prog", $argMsg)
EndFunc 

; Call to a function that must exist in the plugin!
IRun()
sleep(2000)
; Call ITerminate to lett the plugin clean up.
ITerminate()
Exit

; PURPOSE:  Demonstrating a Autoit Plug-in architecture.
;            This is the main application whos purpose is to configure
;            and build the real application.
; FILENAME:   mainProg.au3
; CREATED BY: Uten
; HOME:
; CHANGE LOG:
;----------------------------------------------------------------------
; Uten    14 mar 2006: Published
;
;----------------------------------------------------------------------
dim $mainProg = "\runner.au3"
dim $plugin = "plugin.au3"
dim $targetAtoit = "\_au3.exe"; Use uniqe name to avoid conflicts.
;----------------------------------------------------------------------
; Installer section
; fileinstall will package the files at compiletime and unpack them at 
; run time. 
; NOTE: fileinstall must have absolute path at compiletime. Variables 
;      are not evaluated.
; TODO: Modify location of AutoIt3.exe
fileinstall("C:\Program Files\AutoIt3\beta\AutoIt3.exe", @TempDir & _
    $targetAtoit, 1)
fileinstall("runner.au3", @TempDir & $mainProg,1)
; NOTE: You could download "plugin" files from the net rather than 
; writing the default, or lett the user write one, like this.
fileinstall("plugin.au3", $plugin,0);0->Do not overwrite?
;----------------------------------------------------------------------
; Modify necesary filesto relect new plugins, locations and such
; Add "plugin" include files to the end of the "main" prog. The "main" 
; prog should be fresh each time.
$file = FileOpen(@TempDir & $mainProg, 1)
FileWrite($file, "#include "& Chr(34)  & @ScriptDir & "\" & _
    $plugin & Chr(34) & @CRLF)
FileClose($file)
;----------------------------------------------------------------------
; Compile the new program. 
dim $cmd=  chr(34) & @TempDir & $targetAtoit & chr(34) & _
    " /AutoIt3ExecuteScript " & chr(34) &  @TempDir & _
    $mainProg & chr(34) 
;----------------------------------------------------------------------
; Run the new program. This will appear in taskmanager as a new PID.
RunWait($cmd, @TempDir)
;----------------------------------------------------------------------
; Clean up unpacked files if you want to. They will be unpacked again 
; next time.
FileDelete(@TempDir & $mainProg)
FileDelete(@TempDir & $targetAtoit)

Try it out.

Run mainProg.exe. This will create the default version of the program. A modifiable plug-in (plugin.au3) will be created in the same folder as you run mainProg.exe from. This file will not be replaced the next time you run mainProg.exe.

Now lets modify plugin.au3:

Func ITerminate()
    apiMsg("Terminating" & @CRLF & "NOTE: $apiVersion:=" & $apiVersion & @CRLF & "Ready to terminate.")
EndFunc

And run mainProg.exe again.

If your modifications were successful the user experience of mainProg.exe should change.

When you design you next killer application you might want to consider:

  • How can you prevent users from tampering with plug-ins you do not want them to touch?
  • How will errors in user-modified scripts be handled?
  • Is it possible to have multiple plugins. Say, load all plugins from a directory. (The demonstrated architecture only suports one plugin file).
Hopefully this little sample will give you a head start and inspiration to create the next modifiable, and possibly distributed, killer application.

Happy coding

plugin_architecture.zip

Edited by Uten

Share this post


Link to post
Share on other sites



:mellow: Outch, I have used the same file twice. .:) Realy sorry about that. The attached file has what you need to compile the sample. It should work with version 3.1.1 (acka. does not need beta).

I'l corect the first post asap.

Regards

Uten

Share this post


Link to post
Share on other sites

This is a really good idea for scripts which are used by different users with different rights or needs.

Only problem I have is that AutoIt must be installed. Which is not the case for most users........

Could there be a way like a Mainscript and then plugins in say .au3 format which can still be used by the Mainscript? (I hope you understand.....)

PS: I really like your example!! :think:

Share this post


Link to post
Share on other sites

You don't need to have AutoIt installed, just run this line when running an uncompiled .au3 file

Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & $PathToFile & '"')

Also, Uten, I like your idea for distributed computing in AutoIt. I've developed two functions that work well to pack and unpack variables for sending across a network, the internet, etc. Take a look:

;===============================================================================
;
; Function Name:    _PackVarToStr()
; Description:    Packs a variable into a string form for sending to another
;                       script. Maintains array integrity up to 4 dimensions.
;                       Also supports nested arrays inside array elements.
; Parameter(s):  $vPackVar = Variable to be packed into a string.
;                       NOTE: Variables of type Object or DllStructs are not yet
;                       supported.
; Return Value(s):  Returns packed string to be unpacked by _UnpackStrToVar()
; Author(s):        Ben Brightwell
;
;===============================================================================
Func _PackVarToStr(ByRef $vPackVar)
    Local $iNumDims = UBound($vPackVar, 0); Number of dimensions of $vPackVar
    Local $sVarStr = "$[" & $iNumDims & "]$"; Return string of packed variable
    Local $iCounter1 = ""; Nested Counter
    Local $iCounter2 = ""; Nested Counter
    Local $iCounter3 = ""; Nested Counter
    Local $iCounter4 = ""; Nested Counter
    For $i = 1 To $iNumDims
        $sVarStr &= "$[" & UBound($vPackVar, $i) & "]$"
    Next
    Select
        Case $iNumDims == 0
            If $vPackVar == "" Then
                $sVarStr &= "$[0]$<nil>"
            Else
                $sVarStr &= $vPackVar
            EndIf
        Case $iNumDims == 1
            For $iCounter1 = 0 To UBound($vPackVar, 1) - 1
                If $vPackVar[$iCounter1] == "" And UBound($vPackVar[$iCounter1], 0) == 0 Then
                    $sVarStr &= "$[0]$<nil>"
                Else
                    $sVarStr &= _PackVarToStr($vPackVar[$iCounter1])
                EndIf
            Next
        Case $iNumDims == 2
            For $iCounter1 = 0 To UBound($vPackVar, 1) - 1
                For $iCounter2 = 0 To UBound($vPackVar, 2) - 1
                    If $vPackVar[$iCounter1][$iCounter2] == "" And UBound($vPackVar[$iCounter1][$iCounter2], 0) == 0 Then
                        $sVarStr &= "$[0]$<nil>"
                    Else
                        $sVarStr &= _PackVarToStr($vPackVar[$iCounter1][$iCounter2])
                    EndIf
                Next
            Next
        Case $iNumDims == 3
            For $iCounter1 = 0 To UBound($vPackVar, 1) - 1
                For $iCounter2 = 0 To UBound($vPackVar, 2) - 1
                    For $iCounter3 = 0 To UBound($vPackVar, 3) - 1
                        If $vPackVar[$iCounter1][$iCounter2][$iCounter3] == "" And UBound($vPackVar[$iCounter1][$iCounter2][$iCounter3], 0) == 0 Then
                            $sVarStr &= "$[0]$<nil>"
                        Else
                            $sVarStr &= _PackVarToStr($vPackVar[$iCounter1][$iCounter2][$iCounter3])
                        EndIf
                    Next
                Next
            Next
        Case $iNumDims == 4
            For $iCounter1 = 0 To UBound($vPackVar, 1) - 1
                For $iCounter2 = 0 To UBound($vPackVar, 2) - 1
                    For $iCounter3 = 0 To UBound($vPackVar, 3) - 1
                        For $iCounter4 = 0 To UBound($vPackVar, 4) - 1
                            If $vPackVar[$iCounter1][$iCounter2][$iCounter3][$iCounter4] == "" And UBound($vPackVar[$iCounter1][$iCounter2][$iCounter3][$iCounter4], 0) == 0 Then
                                $sVarStr &= "$[0]$<nil>"
                            Else
                                $sVarStr &= _PackVarToStr($vPackVar[$iCounter1][$iCounter2][$iCounter3][$iCounter4])
                            EndIf
                        Next
                    Next
                Next
            Next
    EndSelect
    Return $sVarStr
EndFunc  ;==>_PackVarToStr

;===============================================================================
;
; Function Name:    _UnpackStrToVar()
; Description:    Turns a packed variable string back into a variable.
; Parameter(s):  $sVarStr = A packed variable string as returned by _PackVarToStr()
; Return Value(s):  Variable of type that was passed to _PackVarToStr()
; Author(s):        Ben Brightwell
;
;===============================================================================
Func _UnpackStrToVar(ByRef $sVarStr)
    Local $aiNumDims = StringRegExp($sVarStr, '(?:\$\[)(\d*)(?:\]\$)(\#)', 1)
    Local $aiDimSizes[1]; To contain the size of each dimension as passed through $sVarStr
    Local $aiDimSize = ""; To contain the size of current dimension and string position for stripping
    Local $avRetArr[1]; To be redimensioned and have $sVarStr parsed and stored into as an array
    Local $avElementStr = ""; To contain each element as a string as it is parsed from $sVarStr
    If IsArray($aiNumDims) Then
        $sVarStr = StringTrimLeft($sVarStr, $aiNumDims[1])
        If $aiNumDims[0] > 0 Then
            ReDim $aiDimSizes[$aiNumDims[0]]
            For $iCounter1 = 0 To $aiNumDims[0] - 1
                $aiDimSize = StringRegExp($sVarStr, '(?:\$\[)(\d*)(?:\]\$)(\#)', 1)
                $aiDimSizes[$iCounter1] = $aiDimSize[0]
                $sVarStr = StringTrimLeft($sVarStr, $aiDimSize[1])
            Next
        EndIf
        Select
            Case $aiNumDims[0] == 0
                If StringInStr($sVarStr, "$[") Then
                    $avElementStr = StringRegExp($sVarStr, '(.*?)(\#)(?:\$\[)', 1)
                    $sVarStr = StringTrimLeft($sVarStr, $avElementStr[1])
                    If $avElementStr[0] <> "<nil>" Then
                        Return $avElementStr[0]
                    Else
                        Return ""
                    EndIf
                Else
                    If $sVarStr == "<nil>" Then
                        Return ""
                    Else
                        Return $sVarStr
                    EndIf
                EndIf
            Case $aiNumDims[0] == 1
                ReDim $avRetArr[$aiDimSizes[0]]
                For $iCounter1 = 0 To $aiDimSizes[0] - 1
                    $avRetArr[$iCounter1] = _UnpackStrToVar($sVarStr); In case element holds another array (Recursive)
                Next
            Case $aiNumDims[0] == 2
                ReDim $avRetArr[$aiDimSizes[0]][$aiDimSizes[1]]
                For $iCounter1 = 0 To $aiDimSizes[0] - 1
                    For $iCounter2 = 0 To $aiDimSizes[1] - 1
                        $avRetArr[$iCounter1][$iCounter2] = _UnpackStrToVar($sVarStr); In case element holds another array (Recursive)
                    Next
                Next
            Case $aiNumDims[0] == 3
                ReDim $avRetArr[$aiDimSizes[0]][$aiDimSizes[1]][$aiDimSizes[2]]
                For $iCounter1 = 0 To $aiDimSizes[0] - 1
                    For $iCounter2 = 0 To $aiDimSizes[1] - 1
                        For $iCounter3 = 0 To $aiDimSizes[2] - 1
                            $avRetArr[$iCounter1][$iCounter2][$iCounter3] = _UnpackStrToVar($sVarStr); In case element holds another array (Recursive)
                        Next
                    Next
                Next
            Case $aiNumDims[0] == 4
                ReDim $avRetArr[$aiDimSizes[0]][$aiDimSizes[1]][$aiDimSizes[2]][$aiDimSizes[3]]
                For $iCounter1 = 0 To $aiDimSizes[0] - 1
                    For $iCounter2 = 0 To $aiDimSizes[1] - 1
                        For $iCounter3 = 0 To $aiDimSizes[2] - 1
                            For $iCounter4 = 0 To $aiDimSizes[3] - 1
                                $avRetArr[$iCounter1][$iCounter2][$iCounter3][$iCounter4] = _UnpackStrToVar($sVarStr); In case element holds another array (Recursive)
                            Next
                        Next
                    Next
                Next
        EndSelect
        Return $avRetArr
    EndIf
EndFunc  ;==>_UnpackStrToVar

Use _PackVarToStr() to pack a variable up for sending, and then on the other end, once you receive the string, use _UnpackStrToVar() to turn it back into its original variable state. If it's an array, it can even send up to a 4-dimensional array, and nested arrays inside elements of other arrays. All untouched when they come out the other side. Very useful for sending information between scripts via the Std***() and Console***() functions and via TCP/IP, etc.


[u]My UDFs[/u]Coroutine Multithreading UDF LibraryStringRegExp GuideRandom EncryptorArrayToDisplayString"The Brain, expecting disaster, fails to find the obvious solution." -- neogia

Share this post


Link to post
Share on other sites

$file = FileOpen(@TempDir & $mainProg, 1)

FileWrite($file, "#include "& Chr(34) & @ScriptDir & "\" & _

$plugin & Chr(34) & @CRLF)

FileClose($file)

You don't need to have AutoIt installed, just run this line when running an uncompiled .au3 file

Run(@AutoItExe & ' /AutoIt3ExecuteScript "' & $PathToFile & '"')
Thank you both so much, I have been looking for a way to do modules for a program I am making, I combined the two and got this:
#include <Array.au3>
#include <File.au3>

Dim $moduleList[1]
$moduleList=_FileListToArray(@ScriptDir & "\Modules\", "*.au3")
If (Not IsArray($moduleList)) Or (@Error=1) Then
    MsgBox (0,"","No modules found.")
    Exit
EndIf
_ArrayReverse($moduleList)
_ArrayPop($moduleList)
$file = FileOpen(@ScriptDir & '\includes.au3', 2)
For $plugin In $moduleList
    FileWrite($file, "#include "& Chr(34)  & @ScriptDir & "\Modules\" & $plugin & Chr(34) & @CRLF)
Next
FileClose($file)

Run(@AutoItExe & ' /AutoIt3ExecuteScript "'&_PathFull('Main.au3')&'"')

This loads everything in the /Modules directory that ends in .au3 and puts it in includes.au3 which is included at the bottom of Main.au3. Have fun with this. :whistle:

P.S. This requires the Beta

P.S.S. The modules are loaded in reverse alphabetical order.

Share this post


Link to post
Share on other sites

P.S. This requires the Beta

Out of pure curiousity... you say this requires "beta", if you are using the above scripts, I can see where in the latest betas they may break...what beta(s) are you using?

[center]Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.[/center]

Share this post


Link to post
Share on other sites

Sorry I'm late on this. Fore some reason I don't get mail notifications on several threads that I'd like to monitor. Could be my own fiddling with forum settings though ;)

Sorry but I can't really remember. I think I used 3.1.1.102 at the time, but I have not made any notes on it.

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  
Followers 0