Tuesday, January 22, 2008

Flex talking to a ActiveX (using ExternalInterface)

I keep seeing/getting request to know how Flex can communicate with a ActiveX control/DLL. So thought will post this sample in which calls were being exchanged between a Flex app and a ActiveX C++ DLL. You can find the source code here.

The sample has two portions a flex app called CalledApp and a C++ DLL called CallingDLL. Load the CalledApp project in FlexBuilder and CallingDLL project is Visual Studio 2003 or later. Build the DLL and the Flex app. Run the Flex app and click on the button. When flex app calls the DLL function the DLL calls back the flex app.

The key is to make the ActiveX DLL scriptable in IE. I went through the trouble long back. The C++ code shows how to traverse the browser DOM to get access to the correct player and how to invoke functions exposed by the SWF.

The Flex app uses ExternalInterface to create a instance of the ActiveX and make calls to it.

However the sample doesn't show passing arrays to the ActiveX which requires conversion of JavaScript Arrays to COM arrays. I am sure smart developers out there can figure out this :).

If you are looking for a sample where in the SWF is loaded in the Flash player ActiveX control embedded in a Desktop application it can be found here.

27 comments:

Bruce W said...

Hi Sreenivas, thanks for the nice writeup. It was very easy to follow and get your example working. I had a question about this that I posted on Adobe's FB forum, but I later realized that I should've just asked you. You can see the post if you want, but I've been playing around with your example some more and noticed 2 more interesting things.

When I first try to run CalledFlashApp.swf, I get a SecurityError about the swf trying to communicate with html. I looked at a white paper on Flash Player security which said on page 28 "The dialog box only appears for operations that would have succeeded in Flash Player 7 or earlier, and are undertaken by SWF files that were produced for versions of Flash Player prior to Flash Player 8. The dialog box appears no more than one time for each time the player is executed. Also, it does not appear if either the administrator or user options have been set to request silent failures."

The first thing is that I'm using the latest FB 3 beta and I'm wondering why it's producing swf files for older Flash Player versions.

The second thing is why the SecurityError occurs on some machines but not others. When it doens't occur, the communication between Flash and ActiveX silently fails.

I've googled for answers and played around with various FB and browser settings but haven't found anything, and I thought I'd check with you to see if you knew what's happening. --Bruce

Sreenivas said...

Hi Bruce,

I looked at your post on Adobe forum too. Let me make an attempt to your queries. The answers are based on my knowledge so might be wrong.

1. Timer not running during activeX call.

Flash player is a single threadead environment. Hence two things cannot be executing at the same time. Hence when ActiveX call is made the Flex thread is blocked and hence no timer would fire.

I think the workaround would be to swtich to a wait cursor before making ExternalInterface calls which might take long time to return.

2. Script time out is not happening.

Player has time out of 60 seconds. This is a hard coded limit in 8.0 and above. I think only 7.0 had a timeout which the user can set to any limit and default was 15s.

The error thrown for this timeout is misleading as it says 15s elapsed, where as in reality 60s have elapsed.

For the ExternalInterface call I think the 60s timeout may not be getting applied because the control is now in the player side and not in the ActtionScript code. I think the ScriptTimeout applies only when the control is in the AS code. I am not very sure about this.

3. running CalledFlashApp.swf shows securityError.

I don't think you are seeing this because of a Player 7 swf. It is a genuine error.

I am unable to guess what you mean by running the SWF.

Are you trying to run the SWF outside the browser?

ExternalInterface calls work only inside the ActiveX player and it doesn't work in the Standalone player. You may be seeing the error due to this.

The error can also occur if the SWF is in a untrusted directory. As the SWF is trying to load a ActiveX Dll from the system and the SWF is not trusted Player would throw this error.

To see the thing working you need to place the SWF in a trusted directory or make the SWF or its directory trusted. Load it in the browser only.

You can also load the ActiveX player in Windows applications and use ExternalInterface to make calls to C++ DLLs as given in the sample link I provided in the blog.

Hope this helps.

Bruce W said...

Hi Sreenivas, thanks for your answers. I had similar thoughts to yours on some of the questions but wanted to hear opinions from someone else.

1. I was thinking the same thing about ActiveX blocking the Flash Player thread. But I'm still puzzled as to why the ExternalInterface call to ActiveX blocks the FP but the ExternalInterface call to the Javascript setTimeout does not.

2. Your answer makes sense.

3. Sorry not to be more explicit. By "running the SWF" I mean executing CalledFlashApp.html in a browser which then runs CalledFlashApp.swf in the Flash Player. The first time I do this, I get the Security Error. After I mark the SWF as trusted, everything works fine. But when I copy the DLL, SWF, and HTML files to another PC and register the DLL, I do not get the Security Error, and there is no communication between Flex and ActiveX. The explanation may be in the last sentence I quoted above from the Flash Player security paper, which is talking about the Security Settings dialog box: "Also, it does not appear if either the administrator or user options have been set to request silent failures."

Thanks again for you help. --Bruce

Sreenivas said...

Hi Bruce,

1. I think the call to setTimeOut is non blocking because it sets up a timer and immediately returns. The call to ActiveX is blocking because the call made is not returning and is executing something.

3.I think on your machine you have a debug flash player and hence seeing the security error. On the other machine you have a Release flash player hence not seeing any security error. Release version of the player is known to be very silent :)

Bruce W said...

Hi Sreenivas, thanks for your quick reply. Both answers make sense. Thanks a lot for all of your help. --Bruce

mimi c",) said...

HI Sreenivas, Thanks for your post. It is very useful to my project. I tried it and it run smooth in IE. However i have a question here.

I learn from ExternalInterface API provides a function "call". It calls a function exposed by the Flash Player container, and passing 0 or more arguments. E.g.

call(methodName:String, [parameter1:Object]) : Object

However, i read from your code:
ExternalInterface.call("eval",
.......);

I could not find where is the "eval" function is declared. Can you please tell me please?

Really thanks a lot and appreciate if you could answer me.

Sreenivas said...

"eval" is the JavaScript API.

ExternalInterface gets executed in the JavaScript environment and hence you can pass JavaScript code in call.

mimi c",) said...

Okay, Thanks Sreenivas. Yes you are right. The eval() is a JavaScript function evaluates a string and executes it as if it was script code. So basically you instantiate the ActiveXObject at that line of code, right? :) Sorry because I seldom use C/C++ code so a bit blur just now. i normally use Java and now just start learning Flex :) anyway, thanks again! :)

neilwu said...

sorry,i didn't know how to test it
could you show a demo
i really want to know flex & Dll connection

my English isn't well,i am so sorry that give you a big program.

by neil

Sreenivas said...

I cannot put any demo here because it needs client machine configuration.

The steps are very simple.

1. Load the DLL project in VisualStudio .NET 2003 or later.

2. Build the project. A DLL should get build. It would be automatically registered by the build process.

3. Load the Flex project in Flex Builder.

4. Build the Flex app.

5. Run the Flex app and click on the button.

Hope this helps!

KW said...

Hi...and thanks. I can get this working when my Flex code runs in a browser, but do you have any ideas to make it work for running my Flex code as an AIR application? Do you know if AIR applications can instantiate ActiveX components? ...Thanks again!

Sreenivas said...

I am not sure whether ExternalInterface will work when FlashPlayer is being used as a ActiveX control outside a browser.

I don't think ActiveX is supported in current version of AIR.

spai said...

Hi Sreenivas,

At the end this topic you mentioned that you are not sure whether ExternalInterface will work for AIR app..

As you know the Flex AIR 1.5 has a component called HTML component which acts similar to a browser and can be embedded in an AIR app...

I was wondering, would it be possible to call the ExternalInterface through this HTML Object from an AIR app..

If so, then I think the same method that you explained for the browser will work for the AIR also to call DLL files, ??

Basically, I need to call a DLL from an AIR app. I read in some Adobe docs that it can be done thru Remote Object / HTTP services / remoting...

Thanks in advance

Chitra

flanker said...

Hello sir

First of all thanks for the code
But I am not able to test it
as my flex showing an error message

"ActiveXObject is not defined".

what could be the possible reason for the error. If you could guide me on this it will be a great help.

Thankx

Sreenivas said...

If a SWF is loaded by the HTML control available in AIR 1.5 ExternalInterface should work.

"ActiveX object not defined" might mean that the DLL has not registered properly.

Mountain Man said...

We are testing this example, but are receiving the error "Automation server can't create object." A few attempts to correct it have not helped. Do you have any ideas of how to correct it? Thanks.

Sreenivas said...

Same thing as above. You need to see if the DLL is registered properly or not. You can search in the registry or using any OLE tool to check whteher the DLL is registered properly.

You can even try registering the DLL manually from the command line and see if it throws any errors. This might happen due to non availability of the some dependent DLLs.

Abhilash said...

Thank u sir

My problem "ActiveX object not defined" is solved. It was just because i was using mozilla.I solved the problem using IE. Thank U for the help.

TJ said...

Hi Sreenivas, great code. I have been trying to extend it to arrays because I need to import significant sized data sets into Flex. Can receive an array and send it right back to flex using [in] VARIANT msgIn, [out,retval] VARIANT *msgOut. Except, these don't seem to be variants or SAFEARRAYs as I expected. Do you know how Flex stores array data? Cleary, different data types can be stored in the same array. I can get a hex dump of the info received. Looks like some offsets, but I can't make much sense of it.
--Thomas

Arun Kumar Madas said...

Big B Srini,

Great post... I was also looking at something similar for AIR and ActiveX.

AIR 1.5 and ActiveX does not work. I found that even if you use HTML reference in AIR, the WebKIT included in AIR is similar to SAFARI browser and not IE. So ActiveX instance creation in AIR app will fail.

I have a whole bunch of Javascript code which creates ActiveXObject instances to perform XML parsing, DOM parsing, HTTPStreaming etc. none of it i can use it in AIR. Oh yes, in Flex based web app running in IE, lowering the IE security settings to allow scriptlets to get executed - all this works pretty fine.

Hope this helps someone...

Arun Kumar Madas said...

ExternalInterface is not supported in AIR. We need to make use of the HTML (loader.window.invokeJSFunction())

"Automation server can't create object"- This is something to do with your settings on IE... you need to ensure to lower your settings to allow some scriptless and some more settings to get it to work...

Bindas said...

Hi Sreenivas,

Thanks for ur great post. Presently I am facing a strange problem. I don't know why this is happening. The problem is like below:

If I execute the sample code provided by you & create a flex application(not using IIS) then its working fine.

If run the flex application through IIS on server then also it works fine.

But now if I run flex application hosted on IIS through client machine then neither it asks for installing activex on client nor it works.

Please provide some idea if you have.

Regards,
Ujjwal

Sreenivas said...

Ujjwal, the application doesn't have any logic to detect the missing activeX and demand a installation of it. You need to add that logic separately using html/javascript.

pierce79 said...

HI well fellas one think for a better life you need to Buy viagra and for everything else flex talking to a active bye,

criticpapa said...

http://www.mensitaly.com/tools.aspx?id=230

Archie Pavia said...

This is nice post. I love it! Very creative! That's actually really cool. Thanks for this nice information shared. -- Atlanta Airfare

vsk said...

Hi,

I've a requirement to stream media content (CCTV surveillance camera)to a flex app. The DVR Vendor has a native SDK (in C++ DLL)..

Would it be possible integrate this component with flex.

Any help is appreciated..

We are ok to have paid support for this integration.