Thursday, October 23, 2008

Zinc COMPort Phone Dialer Freezes

Background

A photo of the building directory kiosk and phone handset which uses my application built with Flash and Zinc.The same touch-screen kiosk I previously wrote about requires phone dialing capabilities since the purpose it serves is a Building Directory in the lobby of a government office building.

I used MDM Zinc because I can retain all source code in Actionscript (Flash), yet utilize the computer's modem to dial phone numbers via the Zinc COMPort API (whose phone numbers are retrieved from an MS SQL database via Zinc's ODBC API).

At the start of this project while evaluating Zinc as an option, the first thing I did was create a phone dialer prototype using Flash and Zinc to prove it would work. It worked perfectly. But when integrating it into the system at the tail end of the project and adding some robustness to it, I ran into a hitch that caused the Zinc-compiled application to crash.

Problem

In order to gracefully recover should the modem throw a "No Carrier" or "No Dialtone" error, I wanted to hang-up the line then alert the user of this error. However, when invoking the hang-up immediately when Flash is asynchronously notified, the Zinc-compiled application freezes indefinitely.

Example
Part of the constructor of my PhoneDialer AS3 class
mdm.COMPort.onCOMPortData = function(e:Object)
{
   var data:String = StringUtil.trim(e.data);

   logger.logLine("onCOMPortData() - timeCode: " +
      e.timeCode + ", data: " + data + ".");

   if (data == "NO CARRIER")
   {
      hangUp(); //freezes here

      dispatchEvent(new PhoneDialerEvent(
         PhoneDialerEvent.NO_CARRIER));
   }
   else if (data == "NO DIALTONE")
   {
      hangUp(); //freezes here

      dispatchEvent(new PhoneDialerEvent(
         PhoneDialerEvent.NO_DIALTONE));
   }
   else if (data == "OK")
   {
      //Dial was successful!
      dispatchEvent(new PhoneDialerEvent(
         PhoneDialerEvent.OK));
   }
};

Method in my PhoneDialer class:
public function hangUp()
{
   if (!pickedUp)
      throw new AlreadyHungUpException();

   logger.logLine("Closing COMPort.");

   mdm.COMPort.close(); //actually freezes here

   pickedUp = false;
}


Solution

The solution was to not invoke mdm.COMPort.close() within the onCOMPortData handler. Instead, I alert the user of the error which also instructs him/her to click the Cancel button on the Dialing screen. Then the cancel button invokes hangUp(), which works without a hitch.

Also one other item of interest: even though Zinc was designed to support Actionscirpt 3, the first line of code above, mdm.COMPort.onCOMPortData = fuction(... triggers a warning when compiling to SWF - "Warning: 1072: Migration issue: Class is not a dynamic class. Instances cannot have members added to them dynamically." Since this is just a warning, it does not cause any problems during run-time, but it's interesting that they did not switch to use the standard addEventListener method of event-handling that has been implemented as a standard across AS3 components.

Conclusion

In a perfect world, this error would never happen if the kiosk were always connected to the phone line and the phone line were to always provide a dial tone. But since those are possibilities, the application is now robust because it properly recovers from those scenarios instead of crashes.

Thursday, October 16, 2008

SharedObjects - "Cookies" that Don't Go Away

Flash SharedObjects are an easy way to preserve application state on the client-side between sessions.

I have used them for Flash CD-ROM applications that need to persist data on the user's local machine and for Flash web applications that needed a "cheap local database".

But Flash SharedObjects pose a serious privacy problem for anyone who may have access to your computer.

Privacy Problem

The default Flash Player settings give 100KB of local data storage to any SWF from any web site or Flash application.

One may expect that since Flash Player runs in the context of a web browser, that when you tell your web browser to clear its cache, cookies, or other private data, that it will also remove the Flash Player SharedObject data - at least the ones added via your active web browser.

Unfortunately, that is not the case - Flash Player keeps all of your SharedObjects until you explicitly remove them.

See for yourself - on a Windows XP machine browse to this folder (Folder #1):

C:\Documents and Settings\<Your Username>\Application Data\Macromedia\Flash Player\#SharedObjects\<Random Letters and Numbers>\

You may be surprised to see that folder is filled with the domain-names of every web site you have ever visited that contained a Flash file that persisted some data.

There is also another folder that houses more SharedObject data (Folder #2):

C:\Documents and Settings\<Your Username>\Application Data\Macromedia\Flash Player\macromedia.com\support\flashplayer\sys\


So how do you remove these SharedObjects and how do you prevent them from getting there in the first place?

Solutions

To remove your existing Shared Objects, follow these steps:
  1. Delete existing SharedObjects

    Go to the Website Storage Settings Panel of the Flash Player Settings Manager (yes, the manager is on a website, not within software). Move the slider down to "None".

    This removes all files from the Folder #1 (above), but for some reason does not remove from the second folder.

  2. Delete Contents of Folder #2

    Since the previous step did not empty Folder #2 (above), you need to manually delete the contents of that folder.
To prevent future SharedObjects from being saved on your system in the future, you can do this globally for all web sites using the Global Storage Settings manager.

Or set your SharedObject storage settings on a site-by-site basis by doing this:
  1. Right-click on a visible Flash object in a web page.
  2. Click settings.
  3. Click on the tab with the "folder" icon - Local Storage.
  4. Use the slider to change the data limits for that particular web site.

    Wednesday, October 15, 2008

    Zinc Crashes on Select from Database

    Background

    I'm using Zinc 3 as a wrapper around a Flash 9 / ActionScript 3 application for a touch-screen kiosk that requires database and comport access.

    Problem

    The Zinc application crashes when calling mdm.Database.ADO.getData() to obtain the results of a query (either SELECT or stored procedure) executed by mdm.Database.ADO.select() IF the query produces an empty result set. I'm connecting to a MS SQL Server 2005 database, but this issue probably happens with any ADO connection.

    Example
    mdm.Database.ADO.select(sql); //if this results in 0 records...

    if (mdm.Database.ADO.error())
       throw("handle error here");
    else
       arr = mdm.Database.ADO.getData(); //crashes here

    Solution

    The undocumented but simple way to prevent the crash is: prior to calling getData(), you must first check ensure that getRecordCount() is not zero.

    Example
    mdm.Database.ADO.select(sql);

    if (mdm.Database.ADO.error())
       throw("handle error here");
    else if (mdm.Database.ADO.getRecordCount() == 0)
       arr = [];

    else
       arr = mdm.Database.ADO.getData();

    Conclusion

    Ideally Zinc would just return an empty array if no records were found, but since it doesn't, it's nice to know there is an easy fix. I am content with minor problems like this because the benefits Zinc offers - including access to databases and the comport directly from Actionscript - far outweighs the bugs it has.

    trace("Hello World!");

    I finally decided to start a blog to record lessons learned from the trials & tribulations along my journey of coding for a living, with the hope that these solutions will save even just one headache for one fellow coder.

    This blog will focus mainly on Flash ActionScript 2 and ActionScript 3 but will cover anything related such as Zinc, JavaScript, SQL, XML, or anything else that causes me grief but results in a helpful solution.

    About the Author
    My name is Ricky Blaha. I am a senior programmer for ICS Learning Group in Severna Park, Maryland, USA, as well as a freelance programmer doing business as Interstellar Multimedia -- both concentrating in the multimedia, web-development, and e-learning arenas.

    Coding professionally since 1999, my journey started with ColdFusion 4.5 with Oracle and XHTML, CSS and JavaScript. It later evolved into ASP3 development with SQL Server, then some PHP with mySQL. Then in 2002 the opportunity arrived to learn and use Flash 5 and Actionscript 1, and ever since, developing CD-ROMs, touch-screen kiosks, e-learning applications, and web applications with Flash have been my major focus and greatest source of enjoyment.

    In 2008 I decided to back up my experience to become an Adobe Certified Flash MX 2004 Developer. In Fall 2009 I will finally complete my BS in Computer Science with a minor in Strategic and Entrepreneurial Management from UMUC.