In IE10 and other new browsers one may create MessageChannel objects that have two MessagePorts each connected (w3c spec calls it entangled) to one another such that postMessage on one port results in the message event firing on the other. You can pass an array of ports as the last parameter to postMessage and they show up in the ports property of the message event arg.
The postMessage here is like the worker postMessage and unlike the window and iframe postMessage in that it applies no origin checking:
Unfortunately the origin isn't an optional parameter at the end to make the two postMessages have the same signature.
On the event handler side, the event arg always has an origin property. But in the no origin case it is always the empty string.
There is also a source property on the message event arg which if set is an object that has a postMessage property allowing you to post back to your caller. It is set for the origin case, however, in the no origin case this property is null. This is somewhat reasonable because in the case of MessagePort and Workers there are only two endpoints so you always know the source of a message implicitly. Unlike the origin case in which any iframe or window can be calling postMessage on any other iframe or window and the caller is unknown. So not unreasonable but it would be nice if the source property was always set for consistency.
When a MessageChannel is created it has two MessagePorts, but until those ports are started they will queue up any messages they receive. Once started they will dispatch all queued messages. Ports don't have to be started to send messages.
A port may be started in two ways, either by explicitly calling the start method on the port, or by setting the onmessage callback property on the port. However, adding an event listener via addEventListener("message", does not start the port. It works this way in IE and Chrome and the spec states this as well.
The justification is that since you can have only one callback via onmessage that once set you must implicitly be ready to receive messages and its fine to start the port. As opposed to the addEventListener in which case the user agent cannot start implicitly because it doesn't know how many event listeners will be added. I found Hixie stating this justification in geoloc meeting notes.
Cool and (relatively) new methods on the JavaScript Array object are here in the most recent versions of your favorite browser! More about them on ECMAScript5, MSDN, the IE blog, or Mozilla's documentation. Here's the list that's got me excited:
For my GeolocMock weekend project I intended to use the Bing Maps API to display a map in a WebBrowser control and allow the user to interact with that to select a location to be consumed by my application. Getting my .NET code to talk to the JavaScript in the WebBrowser control was surprisingly easy.
To have .NET execute JavaScript code you can use the InvokeScript method passing the name of the JavaScript function to execute and an object array of parameters to pass:
this.webBrowser2.Document.InvokeScript("onLocationStateChanged",
new object[] {
latitudeTextBoxText,
longitudeTextBoxText,
altitudeTextBoxText,
uncertaintyTextBoxText
});
The other direction, having JavaScript call into .NET is slightly more complicated but still pretty easy as far as language interop goes. The first step is to mark your assembly as ComVisible so that it can interact with JavaScript via COM. VS had already added a ComVisible declaration to my project I just had to change the value to true.
[assembly: ComVisible(true)]
Next set ObjectForScripting attribute to the object you want to expose to JavaScript.
this.webBrowser2.ObjectForScripting = this.locationState;
Now that object is exposed as window.external in JavaScript and you can call methods on it.
window.external.Set(lat, long, alt, gUncert);
However you don't seem to be able to test for the existence of methods off of it. For example the following JavaScript generates an exception for me even though I have a Set method:
if (window.external && window.external.Set) {