Saturday, February 6, 2010

Why does Safari/Flash always crash?

On a personal note, I have started a new job at Kontera, involving much more web-related development than I have ever done. I will continue posting experiences from this job I find interesting and worthy of sharing.

Safari users may have noticed often crashes when visiting sites that contain Flash. I certainly have. This is not related to a specific OS - it happens both on Windows and on Mac (I personally use a Mac). I noticed this when developing a web component that includes also some Flash, and easily reproduced quite frequent crashes on Safari 4.0.4 and Flash 2010.

Interestingly enough, Chrome which is based on the same engine does not have these crashes.

From examining the stack of Safari (and also knowing the behavior of my flash app ;-), I think that the crash happens when Safari is trying to do something while Flash is calling JavaScript code via ExternalInterface.call(). Reducing the number of calls from Flash to JavaScript and reducing the time spent in the JavaScript calls causes the probability of a crash to be reduced dramatically. The simplest technique is to modify the JavaScript callback to wrap it in a setTimeout(...) as such:

function foo(param1, param2) { .....}

should be replaced with:

function foo(param1, param2, afterTimeout) {
if (!afterTimeout) {
setTimeout(function() { foo(param1, param2, true) }, 20);
}
.... // the original code
}

The flash code does not need to be modified at all.

Happy hacking,

Noam

Monday, September 21, 2009

Outlook New Explorer Hook

When developing our add-in, we tried to add a callback on the creation of a new Explorer. Something like:

Application.Explorers.NewExplorer += new ExplorersEvents_NewExplorerEventHandler(Explorers_NewExplorer);

Unfortunatly, after a new explorer or two were created, our callback was no longer called by outlook.

What made this more consistent was:

Application.Explorers.NewExplorer += new ExplorersEvents_NewExplorerEventHandler(Explorers_NewExplorer);
GC.Collect();

Now, the NewExplorer callback was never called !!

The workaround: Create a global reference to the Explorers object, such as

Explorers explorers;
void Startup()
{
explorers = Application.Explorers;
explorers.NewExplorer += new ExplorersEvents_NewExplorerEventHandler(Explorers_NewExplorer);
....
}

It seems that without this reference, the Explorers object, together with my callback, were all collected by the GC.

This would be a good opportunity to thank my co-worker Arina for figuring this out.

Thursday, September 10, 2009

Outlook Add-Ins can be tricky

Lately I have been doing some development of an outlook add-in, and I learned that this can be challenging. I would like to share on this blog some of my experiences during this development.

So here is one of the more "fun" experiences:

As you probably know, it is possible in outlook to open more than one explorer window (the one with list of mail items, or the calendar, etc).

Another feature of outlook is that when you exit while there are unsent items in the outbox, you get a message box notifying you, and asking if you want to exit without sending, or send and then exit.

I had a bug: When the add-in is installed, and the user exits outlook, and there are unsent items in the outbox, the user gets asked if he really wants to exit not once, but several times, as many as the number of explorers that were ever opened in the session.

This is an annoying bug. It also doesn't seem connectd to what my add-in was doing, and this was weird. I scrambled to figure out the source of the bug by cutting out code from the add-in until I came to a simple addin reproducing the bug and containing these lines only:

private void SidebarAddIn_Startup(object sender, System.EventArgs e)
{
foreach (Explorer explorer in Application.Explorers)
{
}
}


A puzzlement indeed.

After a lot of pondering I came to the conclusion that the foreach() generates Explorer objects that are COM wrappers, and contain reference to the underlying Explorer objects. This keeps COM Explorer objects roaming around, and is probably the cause of this bug. And a simple workaround:

private void SidebarAddIn_Startup(object sender, System.EventArgs e)
{
foreach (Explorer explorer in Application.Explorers)
{
}
GC.Collect();
}

and the bug is solved.

Of course in my add-in, this did not actually work. It turns out there are more operations that leak managed Explorer objects. One of them is adding a CustomTaskPane to an explorer and removing it.

Good luck to all Outlook add-in developers....

Noam

Sunday, June 15, 2008

Stub Generator project

I just published a stub generator utility on CodePlex : http://www.codeplex.com/StubGenerator

The stub generator reads a DLL using Cecil and generates C# stubs for the DLL.

We have tested it on some complex DLLs, and although it is not bug free it pretty much works.

If someone wants to write a cool U/I this would be greatly appreciated.

Wednesday, June 11, 2008

Syndication - RSS 2.0 working !

The RSS 2.0 syndication sample in MSDN now works in Mono's latest bits.
I believe it is now possible to write a WCF service that consumes and exposes RSS feeds.

Give it a try and let me know how things work out.

Wednesday, June 4, 2008

Syndication - RSS 2.0 (almost) working !

I have been working in the past few days on getting the basic RSS feed sample from MSDN to work in Mono.

The sample is at the bottom of this page: http://msdn.microsoft.com/en-us/library/bb412174.aspx

I haven't committed all the fixes yet, but the status is that a valid RSS feed is generated. The part that consumes the RSS feed is not working yet.

There is also an additional small bug discovered that I did not fix yet in the following code:
Uri baseAddress = new Uri("http://localhost:8000/BlogService");
WebServiceHost svcHost = new WebServiceHost(typeof(Service), baseAddress);
svcHost.open();

The host does not listen on the base address. The workaround is to add an additional Endpoint before penning the host, like this:
svcHost.AddServiceEndpoint (typeof (IService), new WebHttpBinding (), baseAddress);

I will update when the entire sample is working.

Noam

Serialization of byte[]

Across .NET now also works.

Before it was serialized differently than .NET, so Mono<->Mono worked but .NET<->Mono did not.