Problems with Flash-content in the WebBrowser control


A recent case I worked on involved the following scenario.

Problem description

The client was building a kiosk-like application. I.e. a WinForms application with the WebBrowser control slapped onto it. The application worked fine for the most part, but they’d found that when viewing video via facebook they were only able to view the video the first time. Any additional attempt to view the video would fail with a custom error from the facebook application stating that the video was either restricted or no longer available.

This only happened when viewing the page via the WinForms application. Using IE directly worked just fine. We also found that this problem occurred with both IE7 and IE8 installed, so it seemed not to be related to the browser version.

Other sites using the Adobe Flash player to display video, such as MSN or Youtube worked just fine.

Troubleshooting

Using the Developer tools included in IE8 I found that the facebook application displays a placeholder image with a play-button. Once that button is clicked the .swf player is loaded via client-side script. The .swf player then downloads the .mp4 that is to be displayed and divides it into suitable chunks.

Fiddler traces revealed that the mp4 was downloaded when using IE but not when using the WinForms application. No errors were reported, instead the request was simply never made.

We removed all code behind. All that remained was the On_Load event that set a starting page for the WebBrowser control, still we were unable to successfully load the movie.

Adding facebook to the trusted zone changed nothing.

Using the COM-version of the WebBrowser control still reproduced the problem.

I then suspected restrictions in cross-domain access or similar, (facebook uses a lot of different domains,) but couldn’t find anything conclusive.

Finally I stumbled upon the root cause.

Cause

The problem is due to a bug within the Adobe Flash-player: http://bugs.adobe.com/jira/browse/FP-256

The problem occurs when dynamically trying to display a cached .swf application with an external interface through script. So, another quick repro would be the following (Copied from the Adobe bug report):

  1. Create a C# application with an embedded WebBrowser control.
  2. Load a HTML page with no content.
  3. Via JavaScript, add a SWF with external interface to the page via an object tag. (At this point I see server traffic, requesting the SWF.)
  4. From JavaScript, access the external interface of the SWF. Works OK.
  5. Browse to a second web page.
  6. Browse back to the empty one.
  7. Via JavaScript, add the SWF again. Cannot contact the external interface. (There is no server traffic, indicating that the SWF is already being cached.)

Solution

While waiting for a fix from Adobe the only way to circumvent this is to manually remove the cached .swf. Article 262110 describes in detail how you can do this. Unfortunately this can be a bit tricky some times. In the sample repro above you’d resolve it by simply removing all .swf items from the cache upon page-load, but this wouldn’t work in the facebook situation, since it might use the same control repeatedly without refreshing the page in between. Depending on your level of control over the target platform it might be easier to simply turn of caching.

/ Johan

Comments (8)

  1. Becky says:

    Any idea whether Adobe is going to fix this issue?

  2. JohanSt says:

    Actually I don’t.

    Looking at the link (http://bugs.adobe.com/jira/browse/FP-256) you’ll find that others have asked Adobe the same question without response.

    / Johan

  3. Bob Miller says:

    This also seems to work most of the time when placed at strategic locations, like OnBeforeNavigate2 (for top frame), OnFileDownload, and before calling Refresh.

    InternetSetOption(NULL, INTERNET_OPTION_RESET_URLCACHE_SESSION, NULL, 0);

    Bob

  4. Stephen says:

    I run into the same issue as well. However, I believe the problem only happens when the flash object is attempting to load data from a different domain. If the data it's trying to load is from the same domain as the swf itself, everything is working fine based on my test result.

    So it is the combination of two problems: caching and cross-domain data access. Since it works fine in IE itself, I am not sure whether Adobe is going to fix it at all. They could say it is a bug with web browser control.

    I also confirm that clearing the cache or restarting the application will solve the problem. But this is really not the ideal solution I am looking for.

    Do you have any update on this, Johan?

  5. Bob says:

    Stephen,

    I've not heard of any update to this problem. Here is my code for flushing the cache – it just flushes the appropriate type – seems to work OK – I've not found any flash videos that don't play…

    Bob

    // The purpose of this method is to prevent a bug with Adobe Flash player

    // not playing movies the second time.

    void

    CBrowserWindow::FlushSWFFilesFromCache()

    {

     DWORD MAX_CACHE_ENTRY_INFO_SIZE = 4096;

     DWORD dwEntrySize = MAX_CACHE_ENTRY_INFO_SIZE;

     LPINTERNET_CACHE_ENTRY_INFO lpCacheEntry;

     //InternetSetOption(NULL, INTERNET_OPTION_RESET_URLCACHE_SESSION, NULL, 0);

     lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];

     lpCacheEntry->dwStructSize = dwEntrySize;

    again:

     HANDLE hCacheDir = FindFirstUrlCacheEntryEx(NULL, 0, NORMAL_CACHE_ENTRY, 0, lpCacheEntry, &dwEntrySize, NULL, NULL, NULL);

     if (hCacheDir == NULL)

     {

       switch (GetLastError())

       {

       case ERROR_NO_MORE_ITEMS:

         delete[] (char*)lpCacheEntry;

         return;

       case ERROR_INSUFFICIENT_BUFFER:

         delete[] (char*)lpCacheEntry;

         lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];

         lpCacheEntry->dwStructSize = dwEntrySize;

         goto again;

       default:

         delete[] (char*)lpCacheEntry;

         return;

       }

     }

     do

     {

       if (lpCacheEntry->lpHeaderInfo)

       {

         TCHAR *p = _tcsstr(lpCacheEntry->lpHeaderInfo, _T("Content-Type: "));

         if (p)

         {

           p += 14;

           if (!_tcsnicmp(p, _T("application/x-shockwave-flash"), 29))

             DeleteUrlCacheEntry(lpCacheEntry->lpszSourceUrlName);

         }

       }

       // Reset entry size to the allocated size

       dwEntrySize = max(MAX_CACHE_ENTRY_INFO_SIZE, lpCacheEntry->dwStructSize);

       // and update the struct size

       lpCacheEntry->dwStructSize = dwEntrySize;

    retry:

       if (!FindNextUrlCacheEntry(hCacheDir, lpCacheEntry, &dwEntrySize))

       {      

         switch (GetLastError())

         {

         case ERROR_NO_MORE_ITEMS:

           FindCloseUrlCache(hCacheDir);

           delete[] (char*)lpCacheEntry;

           return;

         case ERROR_INSUFFICIENT_BUFFER:

           delete[] (char*)lpCacheEntry;

           lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFO) new char[dwEntrySize];

           lpCacheEntry->dwStructSize = dwEntrySize;

           goto retry;

         default:

           FindCloseUrlCache(hCacheDir);

           delete[] (char*)lpCacheEntry;

           return;

         }

       }

     } while (true);  

    }

  6. Stephen says:

    I found one more clue to this issue. The web page which has problem is accessing the flash swf file via a query paramater:

    var obj=new SWFObject("http://*.*.com/flash/player.swf?v=3", … )

    If I remove the v=3 from the source url, the problem will be gone. That is, if I refresh the page, or navigate to another one and go back, the flash keeps playing.

  7. Bob says:

    Stephen, I guess that's helpful then if you are authoring the web page. Otherwise searching the DOM after download for such links and modifing the link could be an option? Is that how you see it?

    Bob

  8. Lee J says:

    Hi, is there a way of flushing the cache, but leaving the cookies, as I need to keep the cookie info stored.. this stops the using cookies messages etc

    thanks