The LocalConnection is a very powerfull way to have multiple Flash player instances exchange complex data.
LocalConnection class definition in the Actionscript dictionary:
“The LocalConnection object lets you develop Flash movies (SWFs) that can send instructions to each other without the use of FSCommand or JavaScript. LocalConnection objects can communicate only between movies that are running on the same client machine, but they can be running in two different applications—for example, a Flash movie running in a browser and a Flash movie running in a projector.”
You might wonder: only between Flash movies?
Having Flash movies and applications communicate through LocalConnections would be much more powerfull than the limited fscommand/setvariable interface: you wouldn’t be limited to exchanging strings but any AMF datatype (string, number, array, object, etc). This isn’t even against Macromedia interests to document how the LocalConnection works so hopefully we will have a complete, cross platform documentation here.
Notes:
So I made a dummy SWF which calls some dummy method from a dummy LocalConnection.
To know what’s going on when the LocalConnection is created, you can use some tool to spy the Flash player. I used the great and free Systernal's ProcessExplorer.
The Process Explorer shows us all the kernel objects owned by SAFlashPlayer.exe. We can see two new items that where not here before the creation of the LocalConnection:
| Type | Name |
|---|---|
| Section | \BaseNamedObject\MacromediaFMOmega |
| Mutant | \BaseNamedObject\MacromediaMutexOmega |
It means that Macromedia simply uses the most common and reliable way to exchange data between process.
The good news is that any application that knows the name of a kernel object can have access to it. So technically, if you can call Win32 API functions, you will be able to fake a LocalConnection.
Listening
To create a listening LocalConnection, you just have to set a thread to:
Accessing the memory is the easy part. The tough part will be to “read the message” because the LocalConnection can be used to send complex data. These data are encoded as AMF data types, so you will have to check AMFPHP (PHP), AMF::Perl (Perl) or AMFPP (C++) sources to decode the messages.
Sending
To send a message to a LocalConnection apparently works like that:
The main thing you have to care about is the timestamp - simply call GetTickCount() - and the message size. If your message is correctly encoded, it should be received by the listening LocalConnection.
Some facts:
| HEADER | |
|---|---|
| unsigned long | unknown |
| unsigned long | unknown |
| unsigned long | timestamp1) |
| unsigned long | message size |
| MESSAGE | |
| AMF string | connection name |
| AMF string | protocol |
| AMF string | method name |
| any AMF type | message data |
| ... | |
| LISTENERS | |
| string | connection name |
| ... | |
For more detailed AMF format info look here:
http://vanrijkom.org/archives/2005/06/amf_format.html
This describes the implementation on Linux. It may also clarify some points for the Windows section, particularly on data expiry and listener markers.
As on Windows, the shared memory section is divided into an initial data section and a listeners section. The listeners section begins at 40976 bytes: the same as on Windows.
The header is the same as on windows. It comprises the eight bytes:
01 00 00 00 01 00 00 00
followed by a long timestamp and a long data length value. The timestamp is the number of milliseconds since the flashplayer started. This is not the same as what is documented for Windows.
Data may not be overwritten while the timestamp and length fields are not zero.
Sending comprises two stages: checking whether the buffer may be written, and writing the data.
Expiry check
A sender checks the timestamp and length fields any data in the buffer. If they are zero, the data may be overwritten and we can proceed to write our data. If they are non-zero, the sender checks whether it can be marked as expired
Data expires after 4 seconds. Processes only delete data they (think they) wrote. If the timestamp matches the timestamp of the last data that the sender wrote, it assumes it can invalidate the data. If the timestamp is more than 4 seconds old, the sender overwrites the timestamp and length with zero. This means it may be overwritten.
If the data has not expired, the sender continues to check whether the data has expired as long as the data is not marked for overwriting. No changes are made to the buffer by a sender as long as the timestamp is there.
Writing the data
Once the buffer is ready for writing, the sender checks if the correct listener is present by searching the listeners section for the name of the connection. If the name is found, the sender writes the first message in its queue and stores the messages timestamp. If the listener is not present, the sender iterates through the queue until a message for an existing listener is found.
If none is found, the last message in the buffer is sent with no timestamp. (It’s not clear if there’s any point in sending it, but it happens).
A listener registers itself by adding its name to the listeners section of the shared memory. The name is null-terminated and followed by a further marker, which is of the form:
3a 3a 33 00 3a 3a 34 00 : : 3 : : 4
The numbers vary, e.g. ::3::4, ::3::1, ::3::2. We do not know the significance of these numbers, though they seem to be related to the domain of the SWF (http, local etc).
A listener merely checks whether the data has a timestamp and if the data is intended for it (by reading the first string field). If it is, the data is deserialized, the encoded function called, and the datamarked for deletion.
Functions are encoded in a particular order after the timestamp and length fields:
License for the following sources: Public domain.
UPDATE 2007/05/31: bidirectional communication
This code sets a bidirectional local connection between an EXE file (ANSI C implementation) and a SWF. When the SWF sends a text message, the EXE sends a message back.
ARCHIVE: listener
Here is a sample ANSI C application which registers itself as a listening LocalConnection.
ARCHIVE: sender
Here is a sample ANSI C application which waits for a LocalConnection to register itself as a listening LocalConnection.