Note: this article is no longer maintained on this site.I got more than a little tired of having to format code using no-plugin WordPress, so I set up my own. For updates & submitting comments, please check www.active6.com/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>
December 25, 2007 at 7:41 pm
Brilliant!
Thanks for the tutorial.
Makes an excellent base for writing something with similar capabilites as http://www.multidmedia.com/software/zinc/ or other third-party Flash projectors.
July 18, 2008 at 1:38 am
SOG knives…
Interesting ideas… I wonder how the Hollywood media would portray this?…
August 15, 2008 at 9:01 pm
hmm.. very interesting
August 19, 2008 at 5:51 am
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.
November 27, 2008 at 2:07 pm
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
April 27, 2009 at 6:15 pm
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.