Wednesday, July 18, 2007

Reload Magellan MobileMapper CE OS Firmware

Where to download MobileMapper CE OS Firmware Image


Some Magellan official documentations have this out-dated information about location of MobileMapper CE OS firmware download location:
"The current version of MobileMapper CE Operating System (OS) firmware can be downloaded from ftp.magellangps.com in the /Mobile Mapping/MM CE/Firmware/OS Firmware/ folder."
This turned out to be out-dated information. The above directory does not exist on the FTP server. After some digging, I found the OS firmware in this zip file: ftp://ftp.magellangps.com/Mobile%20Mapping/MM%20CE/Firmware/MMCE_Receiver_FW.zip
Notice: the above FTP location is accurate as 7/18/2007, may be changed by Magellan.

What Happened


I saw low battery warning on the device. Naturally, I select "Full Shut Down" to allow the system do a proper backup. This turned out to be a mistake. Apparently, battery was out before the device can fully shut-down, and the OS firmware image is corrupted. After this, upon each reboot, I am asked to calibrate stylus, then there are 2 dialogs:
Dialog 1: dialog title: "Warning", Text: "This is a Rescue Image! The
Main Image failed to start. Press "Cancel" to Retry Main Image. Press
"OK" to continue with Rescue Image."
After I press "OK" which is the only button on the dialog, I am lead to
the second dialog:
Dialog 2: dialog title "OS Loader", Text: "Please choose a new image
file. The image file cannot be in the MyDevice directory."
After I press "OK", an "Open File" dialog appears with option to load a
file type: Image Files (*.nbx).

Following the instruction in "Getting Started Guide", page 61 "Updating MobileMapper CE OS Firmware", I was able to load the OS image I downloaded from Magellan. The system seems to be back to proper working order afterwards.

Lesson Learned


When you have low battery warning, rather than to risk corrupt the OS firmware image, it is probably better to wait for the battery to die out or, if possible, recharge the battery immediately.

Friday, July 13, 2007

Invoke CTRL-ALT-DELETE on Remote Desktop

When you are connected to other Windows computer using Remote Desktop Connection, the combination CTRL-ALT-DELETE will invoke the local computer's logon screen or task manager. Use CTRL-ALT-END to invoke it on the remote computer.

Thursday, July 12, 2007

Delay Load DLL and __HrLoadAllImportsForDll

Here are a few tips for delay loaded DLLs based on my experience with Visual Studio 2003 (Visual C++ 7.1)

  1. Delay load can be easily setup using the Visual Studio IDE by the following steps:
    • Open project property page: Linker > Input
    • In Additional Dependencies, add library: delayimp.lib;
    • In Delay Loaded DLLs, add all the DLLs you want to delay load.
      TIP #1: if you have more than one DLLs, the file names must be separated by ";", e.g.: rapi.dll;ceutil.dll. If you forget this, and try something like: rapi.dll ceutil.dll, then the linker will treat the whole string as the file name of a single file and fail to find a file with that name. There will be a subtle warning during build: LINK : warning LNK4199: /DELAYLOAD:rapi.dll ceutil.dll ignored; no imports found from rapi.dll ceutil.dll, which most likely will be ignored.
  2. Detect if the delay loaded DLLs exists on the host computer:
    The whole purpose of delay loaded DLLs is to allow our program to be more flexible. It can be loaded on computers that do not have certain DLLs, and it can choose to use those DLLs when they are present. So, there is always a need to know if we can load the delay loaded DLLs on the host computer. __HrLoadAllImportsForDll is the recommended function by MSDN documentation to do the job.
    TIP #2:Do not use __HrLoadAllImportsForDll because it use memcmp to compare DLL file names byte by byte which is too strict. File names in Windows system is not case sensitive, so the file names can be the same even if memcmp fails. This function will return module not found error code even when the DLL files are installed on host computer. I end up lift the implementation from delayhlp.cpp, and replace memcmp with _tcsicoll which is case insensitive.

Friday, July 06, 2007

Regular Expression Designer

Writing regular expression is always tough for me, not to mention trying to read regular expressions written by other programmers. I found this excellent FREE tool: Regular Expression Designer provided by radsoftware.com.au a Sydney based company.

As you can see from the screen-shot below, it makes it very easy to experiment and visually inspect output of regular expression applied against various text input. You can try MATCH, SEARCH or REPLACE with one click. Match results are displayed in a tree format, so that you can instantly see all the matches and captured groups. An online help of regular expression language elements is provided as a quick reference.


This application only runs on Windows computer with .NET Framework 1.1 or 2.0.

Thursday, July 05, 2007

Boost.Regex with MFC/ATL in Visual Studio 2003 or Above


Searching, parsing, and validating text input is always a big part of contemporary programming. Regular expression is a powerful tool that is available to C#, Java, Perl, ... Unfortunately, it does not come with C++ or MFC library. One of the best regular expression library in C++ is Boost.Regex, which is accepted as part of C++ standard library in the next release of C++ standard. Boost.Regex library provides direct support for MFC/ATL string types, so that integration with MFC/ATL project is very straightforward. However, integrating BOOST library into Visual Studio 6.0 or older is very hard, due to their lack of standard C++ support.

To use Boost.Regex in a MFC/ATL project in Visual Studio 2003 or above is very easy. Just follow these steps:
  1. Download installation package created by Boost Consulting, following the links: Products > Free Downloads, you will find installer for latest BOOST library distribution. Just run the installer, it will automatically download the selected BOOST library source code from a and pre-compiled binaries from a mirror site;
  2. Setup VC++ include and library directories for BOOST libraries, detailed instructions can be found here: BOOST--Getting Started on Windows;
  3. If you are like me, getting very comfortable using MFC/ATL string types like CString, CStringW, TCHAR, _T, ... Please notice BOOST libraries normally only support standard string type. Please read this before you start to write code: Boost.Regex--Working with MFC/ATL String Types. Boost.Regex does provide a set of overloaded functions that use MFC/ATL types, you will need to include a header file: <boost\regex\mfc.hpp> which defines all the overloaded Boost.Regex APIs as shown in the document;
A sample code:
   1://boost regular expression library
2:#include <boost/regex.hpp>
3://support for MFC string types in boost Regular Expression library
4:#include <boost/regex/mfc.hpp>
5:
6://extract string value from XML by given key
7://Example: given the string below, and key="LogFile"
8://<add key="LogFile" value="c:\temp\error.txt" />
9://return will be: c:\temp\error.txt
10:CString GetXMLValue(LPCTSTR xmlContent, LPCTSTR key)
11:{
12: CString strRegEx;
13: strRegEx.Format("<add\\s+key\\s*=\\s*\"%s\"\\s+value\\s*=\\s*\"([^\"]*)\"\\s*/>", key);
14: tregex re(strRegEx);
15: tmatch matches;
16:
17: //we are expecting no more than 1 match in the file
18: if(regex_search(xmlContent, matches, re))
19: {
20: //extract the value from sub-expression
21: return CString(matches[1].first, matches[1].length());
22: }
23: else
24: {
25: return "";
26: }
27:}

Static link to Boost.Regex library for the above sample code, adds about 80K to the compiled binary output.
Official documentation of Boost.Regex library: http://www.boost.org/libs/regex/doc/index.htm.

Tuesday, July 03, 2007

CeCopyFile (RAPI) Requires Both Files on Remote Device

There is no mention of this restriction in MSDN documentation, but be aware that CeCopyFile requires both lpExistingFileName and lpNewFileName refer to files on remote device. If you want to copy files from PC to remote device or from remote device to PC, you can refer to samples: Pget, and Pput provided in Windows Mobile SDK (in Mobile 5.0 SDK, the samples are under: Samples\CPP\Win32\Rapi).

Definition of CeCopyFile:
BOOL CeCopyFile(
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
BOOL bFailIfExists
);

Monday, July 02, 2007

C++ Primer (Recommended Book)

Title: C++ Primer (I own the 3rd Edition)
Authors: Stanley B. Lippman, Josée Lajoie

Bottom Line: A keeper. Highly recommended. With its accurate and complete coverage, concise text and short code samples, this book serves as a good C++ reference book for intermediate or advanced C++ programmers. But definitely not a book for beginners.

Review:
This is the 1st and the only C++ book I have. The books has been on my shelf for 6 years. I was already familiar with C++ when I bought this book, and I find this book very useful through out the years. It covers EVERY fine details of standard C++, and the information is ACCURATE and CLEAR.

At first, I spent a few weeks browse through it. I found it has tremendous amount of new information for me -- an self-taught intermediate level C++ programmer.

But, if you are beginner trying to learn C++ and Object-Oriented programmer, I would recommend you to find another book.For one thing, in many places, there are terms referencing concepts in future chapter that make you having to read the book in two passes to understand it. Then there are too much fine details about C++, and too little practical guides. Even if you manage to read the book, it could easily take you a full year to finish this book and emerge in all the intricacy about C++, then come out not able to write a single program. There is NO full-blown sample program, nor step by step guide to setup development environment.

Due to its sheer volume and broad coverage, I didn't read the book cover to cover. Instead, I kept this book as a C++ standard reference. Whenever I have doubt, I lookup the index and read the related chapters. The books is written in concise and clear language, and has coverage of many minor details that cannot be easily find elsewhere. Having to juggle between C, C++, C#, Javascript, and SQL, I constantly need to refresh my memory about subtle C++ issues. To be honest, even if I work with C++ every day, I do not think I can master the full-depth of C++ language. C++ is a powerful language that provides many opportunities for programmers to express their ideas. This books is the perfect reference tool for me, it provides all the details about a language feature with enough details (but not too long to read) to remind me of the key points very quickly and precisely.


PS
If this book is not a keeper that I feel deeply indebted to, I would not have the urge to write about it. :)

Thursday, March 29, 2007

Escape CSV string in XSLT


To output CSV format, we will need to escape a field if it has quote, or comma or line feed. To escape a CSV string in XSLT is not a straight forward task. After a little search I found the following solution which passed my test. The code is from a thread I found here: http://www.cygwin.com/ml/xsl-list/2001-03/msg00794.html



 48:  <!-- Sample of calling the escape template -->
49: <xsl:template match="*">
50: <xsl:call-template name="display_csv_field">
51: <xsl:with-param name="field" select="myFieldToEscape"/>
52: </xsl:call-template>
53: </xsl:template>
54:
55: <!-- Template to escape csv field -->
56: <xsl:template name="display_csv_field">
57: <xsl:param name="field"/>
58:
59: <xsl:variable name="linefeed">
60: <xsl:text>&#10;</xsl:text>
61: </xsl:variable>
62:
63: <xsl:choose>
64:
65: <xsl:when test="contains( $field, '&quot;' )">
66: <!-- Field contains a quote. We must enclose this field in quotes,
67: and we must escape each of the quotes in the field value.
68: -->
69: <xsl:text>"</xsl:text>
70:
71: <xsl:call-template name="escape_quotes">
72: <xsl:with-param name="string" select="$field" />
73: </xsl:call-template>
74:
75: <xsl:text>"</xsl:text>
76: </xsl:when>
77:
78: <xsl:when test="contains( $field, ',' ) or contains( $field, $linefeed )">
79: <!-- Field contains a comma and/or a linefeed.
80: We must enclose this field in quotes.
81: -->
82: <xsl:text>"</xsl:text>
83: <xsl:value-of select="$field" />
84: <xsl:text>"</xsl:text>
85: </xsl:when>
86:
87: <xsl:otherwise>
88: <!-- No need to enclose this field in quotes.
89: -->
90: <xsl:value-of select="$field" />
91: </xsl:otherwise>
92:
93: </xsl:choose>
94: </xsl:template>
95:
96: <!-- Helper for escaping CSV field -->
97: <xsl:template name="escape_quotes">
98: <xsl:param name="string" />
99:
100: <xsl:value-of select="substring-before( $string, '&quot;' )" />
101: <xsl:text>""</xsl:text>
102:
103: <xsl:variable name="substring_after_first_quote"
104: select="substring-after( $string, '&quot;' )" />
105:
106: <xsl:choose>
107:
108: <xsl:when test="not( contains( $substring_after_first_quote, '&quot;' ) )">
109: <xsl:value-of select="$substring_after_first_quote" />
110: </xsl:when>
111:
112: <xsl:otherwise>
113: <!-- The substring after the first quote contains a quote.
114: So, we call ourself recursively to escape the quotes
115: in the substring after the first quote.
116: -->
117:
118: <xsl:call-template name="escape_quotes">
119: <xsl:with-param name="string" select="$substring_after_first_quote"/>
120: </xsl:call-template>
121: </xsl:otherwise>
122:
123: </xsl:choose>
124:
125: </xsl:template>

By the way, remember to set the XSLT's output like this:

<xsl:output method="text" encoding="iso-8859-1">
</xsl:output>

Reference: http://www.cygwin.com/ml/xsl-list/2001-03/msg00794.html

Wednesday, March 28, 2007

Serialization of UTC DateTime from SQL database is still awkward


Although treatment of UTC DateTime in .NET 2.0 is significantly improved, handling data selected from SQL database is still awkward.


If you try to serialize a DataSet selected freshly from SQL database, value of a DateTime column will look like this:

<starttime>2006-12-19T15:57:13-08:00</starttime>

While, I really want to see something like this:
<starttime>2006-12-19T15:57:13Z</starttime>

This behavior is to keep compatibility with .NET 1.1. However, trying to change this default behavior is awkward. The best I can find is to change DataSet schema before rows are added (after rows are added, you can only change between "Unspecified" and "UnspecifiedLocal"). Anyway, here are a couple of lines of code that eventually helped me to get the desired output:
   1:        /// <summary>
2: /// fills the dataset using the select command.
3: /// In this function, we assume all DateTime in database is UTC, and fixed
4: /// types here.
5: /// </summary>
6: public int FillDataSet(DataSet dataSet)
7: {
8: int numRowAffected = 0;
9: SqlConnection connection;
10: SqlCommand command;
11: //code to initiate connection, command
12:
13: connection.Open();
14: SqlDataAdapter sqlDA = new SqlDataAdapter();
15: sqlDA.SelectCommand = command;
16: sqlDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;
17:
18: //a detour:
19: //it is still awkward to serialize UTC DateTime from database.
20: //fix DateTime type, assuming all are saved in UTC time
21: //we cannot change type after rows are added, so
22: sqlDA.FillSchema(dataSet, SchemaType.Source);
23: Utilities.SetDateTimeMode(dataSet, DataSetDateTime.Utc);
24:
25: numRowAffected = sqlDA.Fill(dataSet);
26: connection.Close();
27: return numRowAffected;
28: }
29:
30: /// <summary>
31: /// Set all the data columns to speicified mode.
32: /// (only Unspecified or UnspecifiedLocal can be set after rows are added.)
33: /// </summary>
34: /// <param name="data"></param>
35: /// <param name="dtMode"></param>
36: public static void SetDateTimeMode(DataSet data, DataSetDateTime dtMode)
37: {
38: foreach (DataTable dt in data.Tables)
39: {
40: SetDateTimeMode(dt, dtMode);
41: }
42: }
43:
44: /// <summary>
45: /// Set all the data columns to speicified mode.
46: /// (only Unspecified or UnspecifiedLocal can be set after rows are added.)
47: /// </summary>
48: /// <param name="dt"></param>
49: /// <param name="dtMode"></param>
50: public static void SetDateTimeMode(DataTable dt, DataSetDateTime dtMode)
51: {
52: foreach (DataColumn col in dt.Columns)
53: {
54: if (col.DataType == typeof(DateTime))
55: {
56: col.DateTimeMode = dtMode;
57: }
58: }
59: }



This newsgroup thread has help me develop the above strategy: How do I set the DateTimeMode property when filling a DataTable. It is posted on microsoft.public.dotnet.framework.adonet

Friday, March 09, 2007

Aptana Perspective Bug

I am now officially a fan of Aptana. With Visual Studio like auto-complete and helpful compatibility information popup, Aptana proved to be a powerful Javascript editor. I even tried to use Aptana HTML editor to edit Javascript embedded in .aspx files with great success.

Here is a bug (or maybe I expected too much?) that caught me off-guard when I am trying to customize Eclipse perspective:

After opening "Aptana" perspective, I selected menu "Window"->"Save Perspective As", and saved perspective as "My Workspace" so that I can make changes without ruining the original Aptana perspective. Then I noticed that after I restart Eclipse "Code Assist Profiles", "Outline" and "Actions" no longer work. It took me a while to figure out the root reason is that I am not using THE "Aptana" perspective. After I select back to "Aptana" perspective, everything works again. In my opinion, this is not how perspective supposed to work. I should be able to make a copy of their perspective and add my own customizations.

I have reported the bug to Aptana: http://www.aptana.com/trac/ticket/3971

Thursday, March 08, 2007

View Generated Source in IE

I have "Web Developer" add-on for Firefox installed for a while. I love the "View Generated Source" function. Recently, I discovered an excellent way to add this functionality to IE by Favelet or Bookmarklet. This approach is inspired by the reference links below. I tried 2 variations of the Favelet, and end up using the first one.

javascript:void(window.open("javascript:'<xmp>' +
opener.window.document.documentElement.outerHTML + '</xmp>'"));

Good: HTML source is shown in new window.
Bad: Only works for pages served from localhost, due to IE's policy against cross domain access. However, this is not a concern for me, because the main reason I want to see "generated source" is for web development on local computer.

javascript:document.write("<xmp>"+document.documentElement.innerHTML+
"</xmp>");


To make this function easily accessible, I added it to IE bookmark "Link" folder (see screenshot below). Now, I can see the generated source (including generated HTML and Javascript) with just one click on the link named "source".



Related Links:
http://www.eggheadcafe.com/tutorials/aspnet/a4a16033-9811-45dc-8c6b-15d093c0c3ea/javascript-debugging-tool.aspx
http://ajaxian.com/archives/ie-tip-cheeky-way-to-see-the-current-state-of-the-page#comment-3928

Monday, March 05, 2007

JSON.JS and ASP.NET AJAX Extension

JSON.JS was always an important part of my JavaScript library. But, after I start using ASP.NET AJAX extension, I found out that there is a conflict between JSON.JS and AJAX extension.

What is wrong:
On one web page with both AJAX extension control "Accordion" and JSON.JS. I get these error message during page load:
  • Sys.Res has no properties
  • Sys.Application has no properties
  • Sys.UI.DomEvent has no properties

If I edit web.config, change debug="true" to debug="false", these loading errors disappear. But, I found Accordion's performance is very bad. The whole page is held up for at least 10 seconds after each click.

Now "Firebug" comes for the rescue. The "profile" tool in Firebug is very easy to use. It only took me 2 minutes to find out the offender. Just switch to "Console" tab, and click on "Profile", then start clicking on the page. After I am done, I click on "Profile" button again to stop profiling and see the report of activities. Not surprisingly, "toJSONString" is number 1 CPU consumer (see screen shot below). So, the conclusion is obvious, JSON.JS cannot live in the same space as AJAX extension.




Work around:
Now that AJAX extension does not like JSON.JS, and they DO have an alternative to JSON.JS. A reasonable work around is to stop using JSON.JS, and start use the functions provided in Microsoft AJAX library. So here are the alternatives: Sys.Serialization.JavaScriptSerializer.serialize
Sys.Serialization.JavaScriptSerializer.deserialize

By doing this, did I fell into one of Microsoft's secret agenda?

Wednesday, February 21, 2007

The Best of Both Worlds (Visual Studio + Eclipse)

I use Visual Studio 6.0, 2003 and 2005 every day. But when it comes to write Javascript code, Visual Studio left a lot to be desired.

The emerge of Aptana plug-in make me seriously consider install Eclipse on my development computer. Here is what I do to take advantage of Aptana's superior JS edit functions in my Visual Studio web project.
1. add a simple eclipse project under my web application development folder (this will only add one file to my project: .project);
2. associate "*.aspx" to "Aptana HTML Editor", "*.css" to "Aptana CSS Editor", "*.js" to "Aptana JS Editor";
3. add my JS library to "Code Assistant Profiles";

From now on, no matter I am writing javascript in a .js file or .aspx file, I can use Eclipse. When I am working on C# code and ASP.NET controls, I go back to VS2005.

Please look at the screen-shot to see what Aptana can do: code auto-complete with documentation of parameters, tree structured outline of code file, code refactor, code snippets, to name a few. (a side note: also get "Firebug" for JS and CSS debugging in Firefox.)

Tuesday, January 30, 2007

SQL Nightmare

I maintain a web site that allows user to self register. I got a call from one user complaining that she got an error message: "User already exists." But, she is pretty sure there is no such user in our system.

So, I open up SQL Management Studio, try to query the user table. She is right, there is no duplicated user name. I look at the stored procedure, it is very clear that it found a duplicated user name and spit out this error message. What is going on?

It took me at least 20 minutes to suddenly realize that the stored procedure is wrapped in a big transaction. It is possible, a user with the same name is inserted during the transaction, before the complaining code. But, the insertion is canceled when the transaction is rolled back due to the error. I checked the stored procedure again, and did find something like this:


BEGIN TRAN
insert user A
...
... do lot of other things
...
if not exists user A
insert user A
COMMIT TRAN
else
@error="User already exists."
ROLLBACK TRAN
end


Lesson learned: transactional database can be a strange beast. What you see may not be what you think it is. Be aware!

Monday, January 29, 2007

Windows Media Player Automatically Show Full-Screen on Second Monitor

I have dual monitor setup on my laptop. If I open Windows Media Player on one monitor, it will automatically show videos on the other monitor full screen, always on top. I have no option to turn that off. This is annoying because I typically do not want to watch video full-screen. Sometimes, the little ad movie embedded on web pages will suddenly pop-out to my monitor full-screen, and I cannot close it in any way except closing the web page. To make things even worse, one of my monitor is setup to rotate 90 degrees (so that I can see more lines of code on one screen). The full-screen video will show-up on that screen in its original orientation (i.e. I have rotate my monitor back to watch it).

So, I want to turn off the feature, but cannot find anything in Windows Media options. After some googling, I found out this was a problem ever since people starting to use dual monitor configurations. I finally found a solution by adjusting my video card's settings.
http://groups.google.com/group/microsoft.public.windowsmedia.player/browse_frm/thread/2c41fd0cfe87b281/1aa491098343db1e?lnk=st&q=windows+media+player+dual+monitor+full+screen&rnum=9#1aa491098343db1e

Below is screenshot of the settings on my computer:

Wednesday, January 24, 2007

Bookmarklet (aka Favelet)

Only recently did I notice how powerful a bookmark could be. For a nice demo of what you could accomplish, follow this link: http://slayeroffice.com/tools/modi/v2.0/modi_help.html. This is definitely NOT what you would expect from adding a link to bookmark. Huge javascript code can be executed on the page you are currently browsing, by clicking on the bookmark.

There should be some security concerns here. To Microsoft's credit, IE7 did show me a warning dialog when I tried to add the bookmark. Although the warning message is rather vague about what is wrong. There is no warning when I add it to Firefox.

Tuesday, January 23, 2007

ASP.NET AJAX 1.0 released

From Atlas to ASP.NET AJAX, this nice development tool is finally released, and it is free. For ASP.NET developers, this is the time to seriously check it out. It is a huge enhancement to ASP.NET in Visual Studio 2005.

The official web site for this product: http://ajax.asp.net/default.aspx

Also check this blog for more behind scene information: http://weblogs.asp.net/scottgu/archive/2007/01/23/asp-net-ajax-1-0-released.aspx
(Scott is a Microsoft employee. His blog is one of the few I subscribe to. It has latest news about ASP.NET, IIS, and lots of tutorials.)

Friday, December 29, 2006

Lost in Space

While using XmlSerializer in .NET 2.0, I found that spaces in my string values are lost during a round-trip of serialization and de-serialization. Looking at the serialized XML string, I can find that space is preserved during serialization. The XML looks like this:
<Text> </Text>


But after de-serialization the string variable Text only has value string.Empty. After a little research, I found that using the following code segment to de-serialize can avoid the above problem:

//variable xmlString contains the XML string to be de-serialized.
//varialbe result of type T is to be de-serialized from the string
T result;
XmlSerializer s = new XmlSerializer(typeof(T));
StringReader r = new StringReader(xmlString);
XmlReaderSettings settings = new XmlReaderSettings();
//white space are especially important for string types
//if "IgnoreWhitespace" is true, a string value equal to " "
//may be lost during serialization and deserialization.
//the line below is the key of this posting
settings.IgnoreWhitespace = false;
XmlReader reader = XmlReader.Create(r, settings);
result = (T)s.Deserialize(reader);


For comparison, below is my old de-serialization code that causes lost of space:

//variable xmlString contains the XML string to be de-serialized.
//varialbe result of type T is to be de-serialized from the string
T result;
XmlSerializer s = new XmlSerializer(typeof(T));
StringReader r = new StringReader(xmlString);
result = (T)s.Deserialize(r);

Tuesday, December 19, 2006

KB909095 Patch for Windows XP hibernate problem

Bought a new souped up computer or upgraded your computer recently. Did you notice that hibernate no longer works on your computer?

That is what happened to my new DELL Precision Laptop. I get a mysterious error message: "Insufficient System Resources Exist to Complete the API." Long story short, if your computer has more than 1 GB memory, Microsoft KB909095 is here for the rescue. Install it, the problem goes away instantly. Does not seem to have any side effects.

Friday, December 01, 2006

Bug in YUI 0.12.0 causing "secure and nonsecure items" warning in IE6

Just when I am about to have a rest after I happily cleared the "secure and nonsecure" warning in IE7. Today, I test my web application in IE6. I got the "secure and nonsecure" warning again.

Here come the nightmare again, having to test your application in X different browsers on Y different Operating Systems. You fumble to fix bugs for one specific platform and seeing your fixes screwed up totally in another platform.

Fortunately, this time, "I'm Feeling Lucky". I tried keyword "yui secure nonsecure" in google, and found an answer on the first page 3rd item, titled: "Bug in iframe shim code in 0.12.0 container.js?". It is only a one line change in container.js. But, I know it could take me a couple of days to narrow down to it. Thanks to Arun, it only took me 10 minutes to fix the problem this time.

Thursday, November 30, 2006

Loading Indicator in Animated GIF

http://www.ajaxload.info/
This web site provides more than 20 different styles for free (foreground and background colors are configurable).
  • Very easy to use.
  • Seems like no string attached.
  • Nice Graphics

Wednesday, November 29, 2006

IE7 Warning: "This page contains both secure and nonsecure items."

IE 7 come with much enhanced security features and tabbed viewing. But along with the enhancements, we (programmers) also see some new problems to work on. The one I will present below is especially hard, because it is not consistently repeatable.

Problem: serving page through HTTPS, IE7 shows the warning: "This page contains both secure and nonsecure items. Do you want to display the nonsecure items?".

According to past experience, there are 2 main reasons for this warning:
  1. There are content on the web page from non-secure source. You should remove any link to nonsecure content in order to get rid of this warning;
  2. An "IFrame" does not specify source, or specify "about:blank" as the source. IE consider this as nonsecure. You have to point the IFrame to "Javascript:false" to make IE happy;
But the one I am facing has a new twist: the warning does not show up consistently. If I refresh the page by pressing "F5", only 2 out of 10 times, I get the warning.

Findings:
After some painful experiments, I found that the the source of the problem came from my use of YUI panel. I added a background image to the panel like this:
<div class="bd" style="background-image: url(images/back.gif);">
</div>
Guess what, this combined with JavaScript in YUI constitutes the new offense for IE7. According to MSDN Knowledge Base, Article 925014 , using "removeChild()" method to delete a DIV element that references a background image is considered "nonsecure itme". I suppose somewhere in YUI library my DIV is detached and wrapped into something else than attached to the HTML document again.

Solution:
There are 2 workarounds recommended in MSDN KB 925014. The second method meets my need very well. I just moved the specification of background image to CSS. This seems to solve the problem.


More:
It still puzzles me, as why this warning only appears 2 out of 10 times. Following "Workaround" in the article did fix the warning permanently.

Although I finally fixed the problem. I wish IE7 could have provided a little more hint in why it complains about the nonsecure content or the source of the nonsecure content. Better yet, IE7 should give developer's a way to see the rendered HTML content. As far as I know, the only thing I can do is to remove elements on my page one by one, until the warning is gone.

Reference:
MSDN KB 925014 http://support.microsoft.com/kb/925014

Friday, March 24, 2006

A Welcoming Breaking-Change in .Net Framework 2.0

Finally, after a few years waiting, Microsoft admits its implementation of DateTime serialization in web service is flawed, and made a breaking change to it. See the last item on this page: http://msdn.microsoft.com/netframework/programming/breakingchanges/runtime/xmlserial.aspx

In one sentence, under the old framework, only local time can be transmitted correctly by web service. If you save UTC time in database, and try to transmit using web service, bad luck. You will have to convert all the time in to your web server's local time, then send it out. And, on the other end, the receiving computer will have to convert again the date time to UTC time. And, under the hood the web server and receiving computer both did some conversion during XML serialization and de-serialization too. That is about 4 times CPU time wasted on the conversion that leads you back to where you started!!! Even worse, this behavior is not well documented in MSDN, and causes big confusion for developers.

I had to send an internal memo to all developers in my company to raise the awarness of this issue back in 2004. Really glad it finally gets attention and being resolved.

srand() and threads in MFC

This is an old problem I only run into recently: You should call srand() for each and every thread that calls rand().

In its multi-thread version, the CRT implemenation in VC++6.0 will save seed to thread local storage. So, it is necessary to seed the rand() function in every new thread your program created. Otherwise, the random number sequence is same as if seeded by 1. This poses 2 serious questions:
  1. How can I write a class that is thread safe, and caller won't have to worry about calling srand() whenever they create a new thread? I do not have a solution yet. The best I can think of is to ask callers, when not sure, always call srand() whenever a new thread is created;
  2. A second question is what if user creates multiple threads in a batch, this will make the recommended intialization code: srand( (unsigned) time(NULL)); fail, because the threads are created within 1 second, and you will get the same sequence in all your threads. After some searching, I found this discussion thread to be quite helpful: It proposed to multiply time by the thread ID to seed rand().

Using Transition Channel in Macromedia Director

I tried the transition channel in Macromedia Director MX 2004 recently. It
turns out to be quite tricky to use it correctly. At first, I just double clicked
in the score and selected a transition effect. And it works immediately. What
a relief, it is as easy as PowerPoint. Soon, I realized that I was wrong.

The first problems showed up after I tried to add some Lingo scripts to the
frame with transition effect.

First, I want the movie to loop on the frame until user clicks some
button. I find that the movie becomes extremely slow on this frame, and the movie takes about
50% CPU time. Then, in the "Using Director" online help, I found this
warning:
  • Avoid looping on a frame that contains a transition. Playing a transition continuously
    might cause performance issues.
So, I have made a well-documented mistake here. That is the first
tricky issue I have with transition channel.

However, it took me longer than it should be to fingure out the above problem, because
I used the "Dissolve Patterns" transition effect. It won't show any visual changes
when I am looping the frame, although it still takes 50% CPU time to calculate
the transition effect. This fooled me into believing it only did the transition
once and stopped, and was not suspecious of the transition being the source
of performance problem on that frame. If I had used the "Cover Up"
transition, I should have seen the screen repeatedly rolling up, and discover
the problem in the first test run.

The second issue appears when I am trying to add a sprite to show me the current
frame number. I first added a text
member to the lower left corner of the stage like this:



Then I added this behavior to the
sprite:

on prepareFrame me
frameString = "" && _movie.frame
if(frameString <> member("FrameNumber").text) then
member("FrameNumber").text = frameString
end if
end

Again, the transition stopped working, the screen just freeze for 2 seconds (the default
duration used by the transition) then move on. I have not found any document
about this problem yet. But, my investigation showed that the offending code
is the highlighted line above. If I run the same code in enterFrame event handler, it won't be a problem. Or if I remove the line from prepareFrame handler, the transition will showup normally. I am not sure why is this a problem. For now, I will just avoid doing anything like this on a transition frame.

The lessons:

  1. Never loop on a frame that contains a transition;

  2. Do not change a text member's text property in "prepareFrame"
    event of the transition frame (there may be a more general description about this problem);

Tuesday, February 07, 2006

Permission of "Network Configuration Operators" group

The permission for the "Network Configuration Operators" group is documented in Microsoft's knowledge base 297938.
But, there is no language specifically about wireless network configuration
in the KB. So I set out to do a little test. It turns out "Network Configuration Operators" can:

  • Disable, enable wireless adapter and configure wireless connection properties.

  • Change IP filter setting of TCP/IP protocol.


But, can NOT: change firewall settings.


For the sake of completeness, I include Microsoft's list below.


  • Modify the Transmission Control Protocol/Internet Protocol (TCP/IP) properties
    for a local area network (LAN) connection, which includes the IP address,
    the subnet mask, the default gateway, and the name servers.

  • Rename the LAN connections or remote access connections that are available
    to all of the users.

  • Enable or disable a LAN connection.

  • Modify the properties of all of the remote access connections of the user.

  • Delete all of the remote access connections of the user.

  • Rename all of the remote access connections of the user.

  • Issue ipconfig, release, or renew commands.

Wednesday, January 25, 2006

HTML Validator (Firefox Extension)

Recently, I discovered this tool. And it soon becomes the "must-have" tool for me. I develop web pages using ASP.NET. I always call HtmlEncode function before I insert any text from database to web page. But, there is one problem this function call won't solve. And I didn't notice this problem until I used the "HTML Validator" tool to inspect all the web pages I created.

In this case, I grabbed a piece of text from database and inserted it into the web page as tooltip. I called HtmlEncode function before inserting the text to the "title" attribute. Guess what, I forgot one thing: replace the single quote "'"! So, HTML like this can be generated.
<span title="'blogger's">space<font>

Of course it is wrong. You will only see this tooltip: "blogger". But, no web browsers have complained about this. And no users complained about this (well, they just don't know what they should see). I bet it won't be noticed by anybody not for this wonderful extension.

Link to this extension:
https://addons.mozilla.org/extensions/moreinfo.php?id=249&application=firefox

Tuesday, January 17, 2006

FlashBlock (Firefox extension)

I only have 3 Firefox extensions installed. FlashBlock is one of them.

Pros: It replaces flash animation with a button which user can click to start the flash content. Since 99% of flash contents on the web are Ads that just distract your attention from reading and slow down the CPU, this extension is a big saver. It also has a white list option to allow some customization.

Cons: Uninstall is not as easy as install. There are other known problems.

Thursday, January 12, 2006

Dialog Data Validation for MFC

Problem: Data validation in MFC is a bit difficult. We only get
a couple of DDV functions that left a lot to be desired. For example, there is
no easy way to make sure a “Dropdown Combo Box” is not empty.


Solution: After some searching in MSDN documents and
googling, I cannot find a good clean solution. But, I am inspired by the MFC
source code and found the following solution.


In the "DoDataExchange" function of your dialog, you only need to add a few
lines of code (highlighted below) to validate an empty combo box.
Following this logic, you can easily add more sophiscate validation logic, and
make sure the focus will be set to the control that you want user to change.


void CMyDlg::DoDataExchange(CDataExchange* pDX)
{
CMyDlg::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTaskMTTPage)
DDX_CBString(pDX, IDC_COMBOFILENAME, m_strFilename);
//}}AFX_DATA_MAP

//customized data verification
if(pDX->m_bSaveAndValidate)
{
//we will only check data during validation
if(m_strFilename.IsEmpty())
{
CString errorMessage = "The file name field cannot be empty.";
AfxMessageBox(errorMessage, MB_ICONEXCLAMATION);
errorMessage.Empty();

pDX->PrepareCtrl(IDC_COMBOFILENAME); //make sure pDX will focus to this control
pDX->Fail();
}
}

}

Extra: In the process of searching for the solution mentioned
above, I found this interesting problem: VC7 and VC98 have slightly different
definition of public members of CDataExchange class (notice the highlighted
code segment below). Why should Microsoft change definition of public member of
their library? Isn't public member supposed to be some sort of binding
contract?


Another interesting discovery is that Visual Studio intell-sense won't show "m_hWndLastControl"
although it is public member of the class. Did I miss something here?


Why do I care about this obscure member of CDataExchange? Well, I
am trying to find a way to make sure the dialog will set focus on the correct
control after an error condition occurs. My first intent was to manipulate the
m_hWndLastControl
or m_idLastControl member, thus lead
to the discovery. Eventually, I found out calling function PrepareCtrl
is a much better solution.


Definition of class CDataExchange in VC98 include:

// CDataExchange - for data exchange and validation
class CDataExchange
{
// Attributes
public:
BOOL m_bSaveAndValidate; // TRUE => save and validate data
CWnd* m_pDlgWnd; // container usually a dialog

// Operations (for implementors of DDX and DDV procs)
HWND PrepareCtrl(int nIDC); // return HWND of control
HWND PrepareEditCtrl(int nIDC); // return HWND of control
void Fail(); // will throw exception

#ifndef _AFX_NO_OCC_SUPPORT
CWnd* PrepareOleCtrl(int nIDC); // for OLE controls in dialog
#endif

// Implementation
CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate);

HWND m_hWndLastControl; // last control used (for validation)
BOOL m_bEditLastControl; // last control was an edit item
};


Definition of class CDataExchange in VC7 include:

// CDataExchange - for data exchange and validation
class CDataExchange
{
// Attributes
public:
BOOL m_bSaveAndValidate; // TRUE => save and validate data
CWnd* m_pDlgWnd; // container usually a dialog

// Operations (for implementors of DDX and DDV procs)
HWND PrepareCtrl(int nIDC);
HWND PrepareEditCtrl(int nIDC);
void Fail(); // will throw exception

CDataExchange(CWnd* pDlgWnd, BOOL bSaveAndValidate);

#ifndef _AFX_NO_OCC_SUPPORT
COleControlSite* PrepareOleCtrl(int nIDC); // for OLE controls in dialog
#endif

// Implementation
UINT m_idLastControl; // last control used (for validation)
BOOL m_bEditLastControl; // last control was an edit item
};