AutoIT with Flex GUIs using the AS3 ExternalAPI

Written by Bob de Wit. Posted in ActionScript, AutoIT, Developer Blog, Flex

I recently started writing a clan tool for my kinship in the Lord Of The Rings Online (LOTRO) using the open source macro programming language AutoIT 3. As the GUI functions of this language are really limited and it’s very time-consuming to create even a simple GUI, I checked if there was a way to use Flex as the GUI. I ended up with something endlessly more versatile than what the Adobe AIR project allows with regard to interfacing with the Win32 API. In this article I’ll go through the basic principles of SWF embedding into AI3, but bear in mind this principle can be applied to any development language that supports ActiveX embedding. About AutoIT AutoIt is a freeware Windows automation language written in C. It can be used to script most simple Windows-based tasks (great for PC rollouts or home automation). AutoIt has been in popular use since 1999 and continues to provide users and administrators with an easy way to script the Windows GUI. In February 2004 the latest version of AutoIt – known as AutoIt v3 – was released and added powerful scripting features. AutoIt v3 was developed in a small team with the help of contributors around the world and this has led to a great set of help files, examples, support forum, mailing list, editor files, and third-party utilities. Check out www.autoitscript.com About The ActionScript 3 External API This API is Flash 8’s new replacement for fscommand and setVariable or getURL. Although primarily intended for flash-javascript communication, it’s perfect for embedded SWFs in applications. The ExternalInterface can be used to communicate from a Flash or Flex .swf file to any kind of a supported container. The ExternalInterface Class is only available from Flash 8 and above and will work only in Flash Player 8 and above. The External Interface API enables sending and receiving as many arguments as we want or none. With the old fscommand only 1 and at least 1 string could have been sent to an external function.The API supports arguments of the types: Boolean, String, Number, Array, and Object. XML is used as the transfer format. Calling AutoIT from Flex To call any external function, simply include the API library in your Flex (or Flash) project: import flash.external.ExternalInterface; then call the externally defined function, for example to call the AI3 function CallAI3(Parameter), do as follows: ExternalInterface.call(”CallAI3″, Parameter ); Flex will call a function via the container called FlashCall( ). In AutoIt, you can set the function to be called from an ActiveX control with a prefix for the function like this: $SinkObject=ObjEvent($oFlex, “Flex_”) ; and then define the function as such: Func Flex_FlashCall( $xml ) MsgBox( 1, “We received a call from Flex”, “Full XML:” & $xml ) ;In theory, we can now set return value(s) in XML format – however, in Flex this doesn’t seen to work. ;So we can send whatever series of values as a separate result function call back to Flex. $oFlex.CallFunction(’<invoke name=”AI3CallReturn”><arguments><string>This is the return value for your call to FlashCall()</string></arguments></invoke>’) EndFunc Calling Flex From AutoIT As you can see, for the moment, the setting of return values does not seem to work in Flex. So we must define a callback entry in Flex for passing the return value the same way as for any Flex function being called. For example: ExternalInterface.addCallback( “AI3Call”, AI3Call ); ExternalInterface.addCallback( “AI3CallReturn”, AI3CallReturn ); Then simply define the function to be called and the return callback function: private function AI3Call( message:String ) { doSomethingWith( message); } private function AI3CallReturn( message:String ) { doSomethingWithReturnValue(message); } Complete AutoIT Code
;Go into event capturing mode in stead of standard messaging mode
Opt("GUIOnEventMode", 1)

;Set busy for GUI event loop
global $busy = true

;External SWF File Name (assumed in same folder)
$swffile = "externalAPI.swf"

;Create the Shockwave Flash Object - this can contain Flex as well as Flash SWF Files
$oFlex = ObjCreate("ShockwaveFlash.ShockwaveFlash")

;Create the AutoIT GUI Window
$hModWnd = GuiCreate("Flex External API Demo", 400, 400, -1, -1, -1 )

;Create the ActiveX Container
$GUIActiveX = GUICtrlCreateObj( $oFlex, 0, 0 , 400, 400 )

;Set up event handling for Flex externalAPI calls
$SinkObject=ObjEvent($oFlex, "Flex_") ;

;Set up COM error handling
$oMyError = ObjEvent("AutoIt.Error","COMErrFunc")

;Initialize the Flex ActiveX
With $oFlex; Object tag pool
.Movie = @scriptdir & ‘\’& $swffile;
.ScaleMode = 3; 0 showall, 1 noborder, 2 exactFit, 3 noscale
.bgcolor = "#000000";
.Loop = False
.wmode = "Opaque"; Opaque / transparent
.allowScriptAccess = "Always"
EndWith

;Set close handler for AI GUI
GUISetOnEvent($GUI_EVENT_CLOSE, "closeTest" )

;Show the GUI
GUISetState ()

;Now call the Flex defined function AI3Call()
$oFlex.CallFunction(’Hello Flex!’)

;Loop until closed
while $busy
sleep(10)
WEnd

;The ExternalAPI Callback handler - the function that Flex will try to invoke is called FlashCall
;We have defined "Flex_" as a prefix here: $SinkObject=ObjEvent($oFlex, "Flex_") ;
Func Flex_FlashCall( $xml )
;Create an XML DOM Parser with the call XML string
_XMLLoadXML( $xml )

;Get the invoked function name
$invokedFunction = _XMLGetAttrib( "/invoke", "name" )
MsgBox( 1, "Invoked Function Name", $invokedFunction )

;Get the first (and in this case the only) parameter
$parameters = _XMLGetValue( "/invoke/arguments/string" )

MsgBox( 1, "We received a call from Flex", "Invoked Function: " & $invokedFunction & @CRLF & "Parameter: " & $parameters[1] & @CRLF & "Full XML:" & $xml )

;In theory, we can now set return value(s) in XML format - however, in Flex this doesn’t seen to work.
;So we can send whatever series of values as a separate result function call back to Flex.
$oFlex.CallFunction(’This is the return value for your call to FlashCall()’)
EndFunc

;Close GUI Event Handler
Func closeTest()
$busy = false
GUIDelete()
EndFunc

; COM error handler
Func COMErrFunc()

Msgbox(0,"AutoItCOM Test","We intercepted a COM Error !" & @CRLF & @CRLF & _
"err.description is: " & @TAB & $oMyError.description & @CRLF & _
"err.windescription:" & @TAB & $oMyError.windescription & @CRLF & _
"err.number is: " & @TAB & hex($oMyError.number,8) & @CRLF & _
"err.lastdllerror is: " & @TAB & $oMyError.lastdllerror & @CRLF & _
"err.scriptline is: " & @TAB & $oMyError.scriptline & @CRLF & _
"err.source is: " & @TAB & $oMyError.source & @CRLF & _
"err.helpfile is: " & @TAB & $oMyError.helpfile & @CRLF & _
"err.helpcontext is: " & @TAB & $oMyError.helpcontext _
)

Local $err = $oMyError.number
If $err = 0 Then $err = -1

SetError($err) ; to check for after this function returns
Endfunc

Complete Flex Code





















Trackback from your site.

Comments (3)

  • kenn

    |

    Very nice, Bob. Thanks!

    One small element of confusion: in the intro you refer to a function called “CallAI3.”

    Later, in the implementation, you refer to it as “AI3Call.”

    Reply

  • Bob de Wit

    |

    Hi Kenn, thanks for the feedback. CallAI3() and AI3Call() are resp. the calling function from Flex to AutoIt and vice versa. Sorry if that wasn’t clear.

    Reply

  • kenn

    |

    Sorry, I guess I got confused when I couldn’t find a function ‘CallAI3′ in the AutoIt3 script :)

    I don’t know Flex, but I adapted your example to OpenLaszlo.

    I couldn’t get AutoIt3 to return a value to OpenLaszlo (just as you said), but I was able to get OpenLaszlo to return a value (xml) to AutoIt3, which is interesting.

    Thanks, again!

    Reply

Leave a comment