AutoIT with Flex GUIs using the AS3 ExternalAPI

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

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(‘<invoke name=”AI3Call”><arguments><string>Hello Flex!</string></arguments></invoke>’) ;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(‘<invoke name=”AI3CallReturn”><arguments><string>This is the return value for your call to FlashCall()</string></arguments></invoke>’) 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 <?xml version=”1.0″ encoding=”utf-8″?> <mx:Application xmlns:mx=”http://www.adobe.com/2006/mxml” layout=”absolute” creationComplete=”init()” width=”400″ height=”400″> <mx:Script> <![CDATA[ import mx.controls.Alert; import flash.external.ExternalInterface; private function init():void { ExternalInterface.addCallback( "AI3Call", AI3Call ); ExternalInterface.addCallback( "AI3CallReturn", AI3CallReturn ); } private function AI3Call( message:String ) { this.response_tx.text = message; } private function AI3CallReturn( message:String ) { retval_tx.text = message; } private function MoreInfo():void { navigateToURL(new URLRequest("http://livedocs.adobe.com/flex/2/docs/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001971.html"), "_blank"); } private function SendToAI3():void { ExternalInterface.call("CallAI3", Send_tx.text ); } ]]> </mx:Script> <mx:TextArea x=”10″ y=”28″ width=”380″ height=”72″ id=”response_tx”/> <mx:TextInput x=”86″ y=”118″ width=”212″ id=”Send_tx” text=”Hello AutoIT!”/> <mx:Button x=”306″ y=”118″ label=”Send” width=”84″ click=”SendToAI3()”/> <mx:Label x=”10″ y=”120″ text=”Send Text” width=”68″/> <mx:Label x=”10″ y=”10″ text=”Receive Text from Calling AI Function” width=”380″/> <mx:Text x=”10″ y=”266″ text=”This example shows the basic comunication between a Flex Movie and an AutoIT3 ActiveX Container. It is more flexible than the Call() function and supports any combination of parameters sent back and forth using a simple XML format. This principle will also work for Flash 8 or higher movies, as it is pure ActionScript 3.0 on the SWF side. For more information on the AS3 externalAPI, click the link below.” width=”380″ height=”104″/> <mx:LinkButton x=”10″ y=”368″ label=”Adobe ExternalAPI LiveDocs” width=”380″ click=”{MoreInfo()}”/> <mx:TextArea x=”10″ y=”172″ width=”380″ height=”73″ id=”retval_tx”/> <mx:Label x=”10″ y=”155″ text=”Returned XML from Call to AI” width=”380″/> <mx:HRule x=”10″ y=”253″ width=”380″ height=”5″/> <mx:HRule y=”108″ right=”10″ left=”10″/> <mx:HRule y=”149″ left=”10″ right=”10″/> </mx:Application>

Trackback from your site.

Comments (7)

  • SOG knives

    |

    SOG knives…

    Interesting ideas… I wonder how the Hollywood media would portray this?…

    Reply

  • legendsoftheblackmoon

    |

    hmm.. very interesting

    Reply

  • chaitanya

    |

    I have the Js file in my flex project, i have included this js file in the src as well bin folder, but i was not able to communicate with the js file throught External interface.call().
    Can u pls suggest me, where i need to include the js file, exactly and what r the other things i need to include in the project.

    Thanks,
    Chaitanya.

    Reply

  • Flug

    |

    Thx! I read this blog more then one time ,and i must say-its great! Alot of answers were be answered.Step by step i learn to work with this progs, and without blogs like this one i would stand now also @ the beginning!

    Greets,flug

    Reply

  • DeployMan

    |

    Awesome article!

    Any ideas on how to make this technique work with Microsoft SilverLight? It looks like SilverLight requires a constructor to create an ActiveX object.

    Reply

  • Südafrika | Reiseziele Afrika

    |

    Südafrika | Reiseziele Afrika…

    Alles begann damals, so um 1981 herum, in der Körtestraße 10. Damals gab es dort das Geschäft eines Großhändlers, der vorwiegend Spiele aus dem asiatischen Raum nach Berlin importierte. 1994 ging es dann auch nach Spandau in die Havelstraße, 1997 folgt…

    Reply

Leave a comment