Monday, December 24, 2007

C#/Java/C++: Combining a variable assignment and evaluation

Pop Quiz! C#/Java/C++/Javascript/(probably others, too!) programmers, off the top of your head, what's the result of evaluating a variable assignment? In other words, to take a specific example, what is the output of this Java code snippet:

int n;
System.out.println(n = 50);
(Feel free to substitute in Console.Out.WriteLine (C#) or good old printf (C++) for the System.out.println in that snippet, depending on your language of choice.)

The answer is: 50. In Java and the other languages mentioned, the result of the evaluation of a variable assignment is the value being assigned.

I just came across this construct myself for the first time while I recently was doing a code review of a colleague's Java code. Somehow, prior to that code review, I had managed to go for over a decade of developing in these various languages without running across this!

The reason I hasn't run across this before may have to do with code readability. Doing two different things at once (in this case, a combined variable assignment and evaluation) often isn't very good for code readability (and therefore for ease of maintainability); in the general case, then, it probably makes the most sense for the variable assignment and evaluation to just be separated into two separate lines of code.

However, as my colleague's code demonstrated, combining an assignment with an evaluation can be useful when setting up a loop where the same statement is executed to assign a value to the loop variable both before the loop starts, and on each subsequent iteration of the loop. For example, here's a Java example of reading data from an input file a line at a time, using a java.io.BufferedReader:

String inputLine;
while ((inputLine = bufferedReader.readLine()) != null)
{
    // Do something with inputLine...
}

The while statement in this case combines the assignment of the variable inputLine to the line of text read from the BufferedReader, with the check to stop looping when inputLine is null.

In the past, I've written the same logic in this manner:

String inputLine = bufferedReader.readLine();
while (inputLine != null)
{
    // Do something with inputLine...

    inputLine = bufferedReader.readLine();
}

I had always been kind of annoyed over the need to repeat the assignment (inputLine = bufferedReader.readLine()) in two different places.

For writing loops like this in the future, I'll have to think more about whether the gain in code brevity (and debatably, in elegance) from using the former approach (the combined assignment/evaluation in the while statement) is worth the potential cost for future maintainers in the readability of the code.

Wednesday, December 12, 2007

Java: Displaying negative percentage values in red and in parentheses

Recently, I was looking to write some code in Java for a financial application that would output percentage-format numbers, rounded to two decimal places, with negative numbers being displayed in parentheses and in red color. This was an internal application which only needed to work in the US/English locale.

For example, given the values 0.12345 and -0.12345, the formatted output needed to be, respectively:

12.35%
(12.35%)

Since for this application the output only needs to be formatted in the default locale, it can be done with one of the constructors of the Java DecimalFormat class. If the output will be displayed in a web browser (and only in a web browser), the HTML to display the red color for negative values can be embedded in the string passed to the NumberFormat constructors as well:

NumberFormat redNegativePercentTwoDecimalsFormat = new java.text.DecimalFormat(
  "0.00%;'<span style=\"color:#FF0000\">'(0.00%)'</span>'");

The created NumberFormat instance can then be used to output values in our desired format:

System.out.println(redNegativePercentTwoDecimalsFormat.format(0.12345f));
System.out.println(redNegativePercentTwoDecimalsFormat.format(-0.12345f));

Which produces the desired output (when viewed in a web browser):

12.35%
(12.35%)

Monday, December 03, 2007

Finding album art quickly

Here's a quick series of steps that can be taken to find album art for an album (music CD) to paste into Windows Media Player or iTunes:
  • Open up Google Image Search. (Follow that link, or go to the Google.com main homepage and click the "Images" link there.)
  • From Google Image Search, search on the album name. (If the album name is something generic, try entering both the album and artist name in the search field.)
  • Click on one of the image results where the image size is a square and isn't tiny (e.g. 200x200).
  • If the image isn't immediately visible on the page that comes up (or even before the page finishes loading, if you don't want to wait), click the "See full-size image" link that Google puts at the top of the page.
  • Right-click the image and select the Copy option from the context menu that appears to put the image on your clipboard.
I found these steps useful when setting up my small music library in iTunes for the first time recently, having purchased my first iPod. These steps worked for even some of the non-mainstream CDs in my collection, such as Michigan Marching Band CDs and Black Mages CDs.

Friday, November 02, 2007

Fix: ClassCastException in Struts getRequestProcessor under WebLogic 7

At work yesterday, we were having a problem with one of our internal web applications running on BEA WebLogic Server 7 SP 7, Struts 1.1, and Java 1.4, where following an application redeployment, users of the application would get HTTP 500 errors. The WebLogic server output log file showed multiple ClassCastException errors with the following call stack:

java.lang.ClassCastException
at org.apache.struts.action.ActionServlet.getRequestProcessor(ActionServlet.java:871)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1508)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
. . .
at weblogic.servlet.internal.ServletRequestImpl.execute(ServletRequestImpl.java:2642)
at weblogic.kernel.ExecuteThread.execute(ExecuteThread.java:262)
at weblogic.kernel.ExecuteThread.run(ExecuteThread.java:224)

After some troubleshooting, we determined that this error would only occur when the application was under some load (from being hit by multiple users) while it was starting up; the error wouldn't occur if only a single user accessed the application while it was starting.

So, restarting the application while it was not under load (e.g. overnight) turned out to be a viable workaround in our case. Although we were back up and running at this point, I continued to research the issue to get a better understanding of the underlying cause, and to come up with a better solution should we ever need to restart the server during the work day in the future.

Researching the Issue

Some research via Google didn't turn up any obvious solutions on the issue. The exception was being thrown from the Struts class ActionServlet.getRequestProcessor; since Struts is open source, I decided to download the Struts source, and add some additional instrumentation to the getRequestProcessor method to see if that would shed any additional light on the issue.

ActionServlet.java line 871 (from the ClassCastException stack trace) turned out to be the second of these two lines, at the top of the ActionServlet.getRequestProcessor method:

String key = Globals.REQUEST_PROCESSOR_KEY + config.getPrefix();
RequestProcessor processor = (RequestProcessor)getServletContext().getAttribute(key);

So the exception was happening on the attempt to cast the result of getServletContext().getAttribute(key) to type RequestProcessor.

I added some logging to the getRequestProcessor method to log the class name of the result of the getServletContext().getAttribute(key) call to stderr (so that it would be visible in the WebLogic server log), along with the name of the current thread (so I would hopefully be able to get visibility into whether different application threads were getting different results).

Object o = getServletContext().getAttribute(key);
if (o == null)
{ 
  System.err.println("$$$ " + java.lang.Thread.currentThread().getName() + ": " 
    + "getServletContext().getAttribute(key) is null"); 
}
else
{
  System.err.println("$$$ " + java.lang.Thread.currentThread().getName() + ": " 
    + "type=" + o.getClass().toString());
}

(The "$$$" here is just a poor man's bookmark to let me easily search for my debug logging in the server log file.)

In the WebLogic log file, the type of the object causing the ClassCastException upon the attempt to cast it to type RequestProcessor was of type PIRequestProcessor, a custom type used by my company's application. I was initially confused by this, because PIRequestProcessor is declared to extend RequestProcessor in its class declaration, so casting a PIRequestProcessor to a RequestProcessor should be a valid operation. Yet this operation was definitely causing the ClassCastException.

At this point, I remembered a post on Java class loaders that I had just recently read on Kevin Bourrillion's blog (some slightly NSFW content). From Kevin's post:

But now we're finally getting to the interesting part: every class in memory in your runtime environment can be uniquely identified by the pair of (a) its full name (b) the class loader that loaded it

And also:

You may have heard someone explain, or you may have explained yourself, "see, you can't cast a foo.Bar to a foo.Bar here even though it's the same class, because they came from different class loaders, so there's funny class loader hoodoo going on there."

Aha! I improved my instrumentation on the getRequestProcessor method to include the classloader of the PIRequestProcessor instance, and of the current thread:

System.err.println("$$$ " + java.lang.Thread.currentThread().getName() + ": " 
  + type=" + o.getClass().toString() 
  + " | classloader of o: " + o.getClass().getClassLoader().toString() 
  + " | current thread classloader: " + java.lang.Thread.currentThread().getContextClassLoader());

Sure enough, I got two sets of output in the log. One set like the following, for the first thread that got into the getRequestProcessor method, which looked like this:

$$$ ExecuteThread: '5' for queue: 'default': type=class com.gfs.mps.application.productInquiry.struts.PIRequestProcessor instanceof:true classloader of o: weblogic.utils.classloaders.ChangeAwareClassLoader@4b4b50 finder: weblogic.utils.classloaders.MultiClassFinder@6edffb current thread classloader: weblogic.utils.classloaders.ChangeAwareClassLoader@4b4b50 finder: weblogic.utils.classloaders.MultiClassFinder@6edffb

And another set of logged output, for the subsequent threads that get into getRequestProcessor, like this:

$$$ ExecuteThread: '7' for queue: 'default': type=class com.gfs.mps.application.productInquiry.struts.PIRequestProcessor instanceof:false classloader of o: weblogic.utils.classloaders.ChangeAwareClassLoader@4b4b50 finder: weblogic.utils.classloaders.MultiClassFinder@6edffb current thread classloader: weblogic.utils.classloaders.ChangeAwareClassLoader@dfb821 finder: weblogic.utils.classloaders.MultiClassFinder@1a1569b

(Bolded emphasis added by me; note the different class loader ID in the second log output.) The problem was that WebLogic was using two different class loaders in the different threads. The PIRequestProcessor[4b4b50] instance (i.e. a PIRequestProcessor instance created via the class loader with ID 4b4b50) was created and cached in the first thread in the call to getRequestProcessor. When the cached PIRequestProcessor was retrieved by the second thread in its call to getRequestProcessor, the PIRequestProcessor[4b4b50] instance was returned, and when the attempt was made to cast that to a RequestProcessor[dfb821] (created by the dfb821 class loader rather than the 4b4b50 class loader), the ClassCastException resulted.

Most likely this issue between Struts 1.1 and WebLogic Server 7 SP 7 has been addressed in the current versions of one or both products; both are fairly old versions of their respective products. (A poster in that BEA forum thread claims to have been sent a patch by BEA, CR189815, that resolves this issue in WebLogic 8.1.) But in the meantime, I still wanted to come up with a solution to the issue for our application running in that environment.

The Solution

In my initial research on Google, one of the items I had come across was an article on avoiding unnecessary JSP recompilations under WebLogic 8.1 on the BEA site by Nagesh Susarla. Among other things, the article mentions a WebLogic Server parameter, "servlet-reload-check-secs", which can be set to have WebLogic not monitor during runtime whether any new Java class files have been put into place. I also came across a thread in the BEA forums which mentioned someone else running WebLogic Server having a similar problem with a ClassCastException (not really in similar circumstances my own issue, but with a similar exception call stack) and with one of the replies suggesting that the WebLogic setting to disable to disable servlet reloading at runtime be set.

I decided to give that solution a try. Initially it wasn't obvious to me where the WebLogic 7 equivalent of the servlet-reload-check-secs parameter could be set, or even whether that parameter was supported at all under WebLogic 7; my web searches turned out some documentation on the setting for WebLogic 8.1, but not for earlier versions.

After some poking around in the WebLogic 7 console, I did find the place where the equivalent of "servlet-reload-check-secs" can be set: The setting is called "Reload Period", located in the console at [domain] | Deployments | Web Applications | [app name] | Configuration tab | Files sub-tab. The setting's default is 1; setting the value to -1 and restarting the WebLogic server disables WebLogic's runtime servlet reload checking for the web application where the setting was made. (The underlying WebLogic domain config.xml setting is called "ServletReloadCheckSecs".)

After making that setting change, things started working correctly! In my log, I could see that WebLogic was no longer using different class loaders in calls to the Struts ActionServlet.getRequestProcessor method; therefore, no ClassCastException was occurring, and the application was loading properly.

Sunday, October 21, 2007

Firefox now using colloquialisms?

I just restarted Firefox to install the 2.0.0.8 patch, and got this dialog while Firefox was updating: Progress dialog with text: Firefox is installing your updates and will install in a few

So the Firefox devs are using colloquialisms when displaying messages now? :-)

I imagine that the truncated text is probably a result one of my Windows display settings where I've set several system fonts to display at larger-than-default sizes. I just found the visible portion of the text, taken on its own, to be amusing.

Monday, October 08, 2007

Google Search indexer and Google Groups

About a month ago, I posted about my release of a new Windows Media Player skin. In that post, I noted that at the time of that posting, a standard Google web search for the term 'WMPImage_AlbumArtSmall' (a keyword used for adding album art to a Windows Media Player skin) had only a single result.

I just repeated that search, curious to see whether the Google search indexer had picked up my use of that keyword and added my post to the search results -- indeed it did. Interestingly, though, I noticed a 3rd result now present as well: A Google Groups page with more information on the WMPImage_AlbumArtSmall keyword that I had linked to from my original post.

Apparently, prior to that post, the Google search indexer hadn't indexed Google's own archived newsgroup thread; but when it indexed my blog post, it looks like the Google indexer followed the link to the Google Groups thread and indexed the thread at that point.

So it seems that (at least in this case) Google's search indexer doesn't crawl Google's own Groups discussion threads, but does index such threads when there is a link to the thread from elsewhere on the Web. I wonder why the Google indexer doesn't crawl those threads by default? Perhaps the quality of such discussion threads is presumed to be too low to merit inclusion in standard web search results as far as search results go; but if someone links to a thread's page, that thread's context is then assumed to be good enough to merit indexing? Or there might be a concern that Groups pages would appear too often in standard search results if all Groups pages were indexed by default -- and that's one reason that "Groups" is a separate search option from Google's main web search?

Monday, September 17, 2007

Fix: "Field references in ORDER BY clause must appear in the select list if SELECT DISTINCT is specified."

After upgrading a Java batch application with a Progress/OpenEdge back end to use a new JDBC driver version this morning, while testing the upgraded application to check for any issues with using the new driver, the app generated a SQL error: "[DataDirect][OpenEdge JDBC Driver][OpenEdge] Field references in ORDER BY clause must appear in the select list if SELECT DISTINCT is specified. (13637)".

I googled for that error message and the search didn't come up with any results, so I figured I'd blog the solution briefly here. It turns out the error message in this case is actually pretty good, as SQL datasource error messages go. Given a query that involves a SELECT DISTINCT, a JOIN, and a ORDER BY, like this one:

SELECT DISTINCT a.customer_id
 FROM users a
 INNER JOIN sales b  
 ON a.customer_id = b.customer_id
 ORDER BY b.customer_id 

The problem is that the field reference in the SELECT clause and the reference in the ORDER BY clause don't match. In this case, the SELECT clause references table "a" and the ORDER BY clause references table "b".

The fix is to change the query such that both references are the same:

SELECT DISTINCT a.customer_id
 FROM users a
 INNER JOIN sales b  
 ON a.customer_id = b.customer_id
 ORDER BY a.customer_id 

To double-check my example, I tested the first simple query above briefly in Microsoft Access, and it turns out that Access doesn't like the field mismatch either. The Access error message was "ORDER BY clause (...) conflicts with DISTINCT."

Sunday, September 09, 2007

Schneider's Eleven - New skin for Windows Media Player

Over the past week, I've created a new skin (theme) for Windows Media Player. I call it "Schneider's Eleven" -- more on that below.

For a while now, I've wanted a skin for Windows Media Player that meets the following two criteria:

  1. Unobtrusive. I wanted something that I could leave visible in a corner of the screen all the time which wouldn't draw my eye with scrolling text or other graphical animations while I'm concentrating on other tasks.
  2. Informative. Many "minimal" skins do not display the album, artist, and track name of the currently playing track, or alternate between displaying those values; I wanted a skin where all of those values would be visible at a glance.

None of the default skins included with Windows Media Player meet these criteria, nor does the main Windows Media Player 11 interface in its "compact mode". I'd poked around on several occasions for such a skin, but I couldn't find one on Microsoft's official skins site or elsewhere.

I did a little reading about Windows Media Player skins, and found that WMP skin files -- files with a .wmz extension located in the Program Files\Windows Media Player\Skins folder -- are actually just renamed .zip files. This means that it is possible to inspect the implementation of any existing skin by uncompressing and looking at the files in the skin's archive.

I had previously assumed that skin files were created using some difficult-to-learn proprietary language, but as I found by looking at existing skins on my system, I found that the layout and behavior of WMP skins are defined in standard XML and Javascript code. Once I discovered that, I set out to create my own skin that would have the design and behavior that I wanted.

I was able to implement the new skin by learning by example from the skins already on my system. Between inspection of the source code of the Microsoft skin "9SeriesDefault" (internally named "Corona") and a skin I had previously downloaded in my earlier search for a suitable skin named Basic6, I was able to write 95% of the implementation for my new skin; the remainder I was able to get from Microsoft's skinning reference at MSDN.

The UI layout of the new skin was inspired by the TrackInfo pane of the Basic 6 skin, written by Richard Kohut, which featured display of all of the information I wanted (album, artist, track name), plus display of the album art for the album, a cool touch. For the play controls of the UI, I created a reduced-size version of the standard Windows Media Player 11 interface -- thus the name for the new skin, "Schneider's Eleven".

Schneider's Eleven UI

To my surprise, the technique for displaying the album art in the skin doesn't appear to be documented anywhere in the MSDN online documentation -- or anywhere else on the WWW that I could find! The key is setting the background image property of a subview element in the skin to the constant string value "WMPImage_AlbumArtSmall". At the time of this writing there is only a single result returned in a Google search for WMPImage_AlbumArtSmall (and that result is a long discussion thread in Japanese which I can't read)! As I mentioned, I find this really surprising -- is there another way to put album art into a skin; or else maybe the technique for putting album art in a WMP skin is still little-known, or maybe there just isn't a lot of discussion of WMP skinning out there? I'm not sure at this point. In any event, if you are a skinner looking to put album art into your skin, by all means download a copy of Schneider's Eleven and take a look at the source to see how I did it.

Doing the same search in Google News currently returns 4 results, one of which is a post to microsoft.public.windowsmedia.player.skins by "Stevie BM" describing a technique to work around an issue with album art not being sized properly when displayed in a skin, which I took advantage of in my skin. Thanks Stevie! It's always very cool when someone, having found a solution to a tricky problem, takes the time to follow up and let the community know about the solution, rather than just silently implementing the solution without letting anyone else know about it.

If you'd like to download a copy of the Schneider's Eleven skin, follow that link to my web site for the download link. Feedback on the skin would be welcome!

Tuesday, August 21, 2007

Bounds Test v2.0.3 Released

I just posted a new minor version update, v2.0.3, to Bounds Test, my on-screen measurement utility.

The main new feature in this version is a "Set Size" dialog, that allows the Bounds Test window to quickly be set to any specific size by typing the desired height and width values. (In previous versions, to set the window to a specific size, you would need to carefully drag-resize the window to that size.) The Set Size feature is accessible from the application's right-click menu.

Get it from my Windows Utilities page, or download it directly: Bounds Test 2.0.3 (12k).

Friday, August 17, 2007

Email client usability: Replying to your own sent items

Here’s a scenario that I think is fairly common: I’m having an email conversation with another person (“Melissa” in this example). I reply to Melissa’s email; then, later, before I’ve gotten a new reply back from Melissa, I come across additional information that I want to send to her as part of the same email conversation.

To do this, I could just re-reply the most recent message that I got from Melissa – the one I already replied to earlier -- but in that case, my earlier reply would be dropped from the conversation when Melissa responds and the conversation continues:

What I really want to do instead is to reply to my own latest message in the conversation, so that the entire thread of the conversation will be preserved in the message:

Unfortunately, some modern email clients do not have very good support for this scenario, including (as I write this) the latest versions of Microsoft Outlook and Novell GroupWise.

  • In Outlook (versions 2003 and 2007), if you Reply to a message in your Sent Mail folder, Outlook populates the "To" field with your own address, instead of populating it with the address (or addresses) of the other conversation participants. If you "Reply to All", both your address and the other participants' addresses are populated in the "To" field. In both cases, you need to fix the "To" field manually to make it have only the recipient(s), and not yourself.
  • In GroupWise (version 7), the application doesn't permit to you do a Reply on items in the Sent Items folder at all! (The menu item Actions | Reply is disabled when an email message is selected in Sent Items.) Instead, you are obliged to use the Forward feature instead, and then clean up the header fields of the new message by deleting the "Fwd:" that automatically gets prepended to the subject line, and manually re-entering the address (or addresses) of the other conversation participants.

Gmail does handle doing a reply to a sent item correctly – good job by the usability guys at Google! Some other, older, mail clients may have handled this correctly as well; thinking back to my time at Michigan, I'm fairly sure that the now-venerable Pine email client handled this case properly.

It would be nice if Outlook and other mail clients that behave similarly would put the other conversation participants' addresses in the "To" field (and the "cc:" field when applicable) instead of your own address when you reply to an email message in your own sent items folder.

Thursday, July 26, 2007

Tip: Poor man's text bookmarking

Many IDEs and text editors support a “bookmarking” feature, which will let you set a bookmark at a particular line of code or location in a document (generally through a menu pick or a shortcut key, which will bring up a prompt to enter a name for the bookmark), and then return there later (generally either through a dialog which allows you to pick a bookmark that you set previously, or though a Go To Next Bookmark / Go To Previous Bookmark shortcut key).

However, there currently isn’t any standard convention among Windows applications for the shortcut keys and menu options that are used to set and navigate to bookmarks. Visual Studio 2005, Eclipse 3.2.1, and Word 2003 (to name three applications that support mid-document bookmarking) all use completely different methods for setting and accessing bookmarks.

I’ve come up with my own trick for setting temporary bookmarks in a document. When I’m at a place at a document that I want to easily be able to return to a little bit later, I enter the string $$$ in the document. (If I’m writing code, I’ll enter it as a comment so that the code will still compile.) Then, later, I just use the editor’s Find feature to search for the $$$ to return that spot. When I’m done working with that area of the document, I delete the $$$. It’s also easy to do a multi-file search for “$$$” to find and remove any bookmarks that I might have set and then forgotten to clean up (prior to checking in a set of code changes, for example).

I chose the string “$$$” because it doesn’t tend to appear anywhere else in the types of documents that I work with, so when I go back and search for "$$$" later, my bookmark is the only match. It's also easy to type and easy to remember.

This technique is nice because it can be used in any text editor, regardless of the particular editor’s own convention for accessing bookmarks. As a sort of poor man's bookmark, it can be used even in editors that do not support bookmarking at all.

Wednesday, July 11, 2007

Thinkpad Rescue & Recovery, and free disk space

While researching a "Rescue and Recovery does not have enough disk space to perform the requested operation" error message that has been unexpectedly popping up on my Lenovo Thinkpad T60 from time to time, I found that on at least some Thinkpad laptops, 20 GB or more of “unaccounted for” of hard disk space – space that is reported as “in use” by the Windows, but which apparently no files are actually using -- can be reclaimed by deleting backups made by the Thinkpad “Rescue & Recovery” utility, or by uninstalling the utility altogether. Information on this is available in a post on Charles J. Keeme's blog (which incidentally, as of this morning, was somewhat surprisingly the only Google result for that error message).

Disclaimer: Make sure you have a sound alternative backup strategy in place before you fiddle with the Rescue & Recovery utility! You may also first want to make a set of OS recovery CDs if you haven’t already and you don’t have other means to restore your machine to its factory default state, as the restore data for some Thinkpads is apparently stored as part of the Rescue & Recovery backup data, not on CDs that came with the machine.

The ability to reclaim this disk space that was being used by Rescue & Recovery was a pretty big deal to me, as my current work machine is a Thinkpad T60 that came with only a 50.7 GB hard drive. This morning, despite having relatively few applications installed and very little in the way of multimedia files (music/photos) on the machine, I had only 9.57GB of free space. After uninstalling the Rescue & Recovery utility, I’m up to 29.9 GB of space – Rescue & Recovery was consuming fully 40% of the capacity of my limited hard disk storage!

(In my case, my Thinkpad is my work machine, and my setup is such that my code and work data are backed up on the corporate LAN, and I can rely on the corporate IT department to help me out should the machine experience some kind of hardware failure that would require me to need to reinstall Windows, so I was happy make the tradeoff of tripling my available free disk space in exchange for the (for me) mostly-redundant backup capability that Rescue & Recovery afforded.)

Thursday, June 28, 2007

Howto: Disable auto-insertion of HTML end tags in Eclipse

In Eclipse (version 3.2.1), when editing an HTML page, Eclipse automatically completes HTML end tags that you are in the process of typing for you. For example, if you type:

<td></

Eclipse will immediately automatically add the rest of the tag -- in this case, td> -- for you, so that you end up with (with the part Eclipse added shown here in italics):

<td></td>

However, after years of typing HTML, I'm accustomed to quickly typing the entire HTML end tag myself without thinking about it. Over the last few days, since I've started to use Eclipse to edit HTML, I've frequently ended up with HTML like the following while I'm typing something out:

<td></td>td>

Eclipse adds the second td> automatically, but at the same time I'd typed it out myself without pausing to remember the fact that Eclipse is going to add it for me, and I'd end up with some broken HTML that I would have to either stop what I was doing to fix, or remember to go back and fix later. This got quite aggravating by the time it happened to me for about the 30th time. :-)

I started looking for a way to disable the end tag auto-insertion feature. I searched through the Window | Preferences settings in Eclipse, but couldn't find any setting that was responsible for the end tag auto-insertion. I also searched the Web with Google and Usenet with Google Groups, but couldn't come up with any relevant results even after trying several different variations on my search terms.

Finally, I posted my question to the Eclipse newsgroup eclipse.newcomer (free registration required to browse/post). Nitin Dahyabhai kindly responded and provided the solution:

The HTML end tag auto-insert feature is controlled by the "Smart Insert Mode" setting on the Eclipse Edit menu. You can uncheck the setting there to get Eclipse to stop automatically completing HTML end tags.

Having disabled the "Smart Insert Mode" setting, I'm now much happier while typing HTML into the Eclipse editor. Thanks, Nitin!

Wednesday, June 06, 2007

The Mystery of the Phantom "pbrush.exe" File

For a while now, I've known that you can launch the Paint image editor that is bundled with Windows by typing either one of mspaint or pbrush at the Start | Run dialog. I was recently using my PathFind utility (a which-like command-line utility that shows where a specified file is located on the path) to check on the locations of a few Windows programs, and I used it to find the locations of mspaint.exe and pbrush.exe on my Windows XP machine.

As expected, PathFind.exe showed that mspaint.exe was located at C:\Windows\system32. But when I had PathFind look for pbrush.exe, to my surprise, it reported that the file was not located anywhere on the path.

At this point, I got pretty curious about how running pbrush.exe from Start | Run was launching Paint when pbrush.exe apparently didn't exist on the path, and some brief searching on Google and Google Groups didn't reveal any answers, so I decided to don my Mark Russinovich-style Detective Hat and do some investigation to figure out just what was going on!

I tried using PathFind to search for "pbrush.*" to see if it was running from a filename with some other extension, such as pbrush.com. However, no file named pbrush with any extension existed on the path.

I still wasn't convinced that pbrush.exe didn't exist somewhere on the machine, so I hit Win+F to bring up Windows' built-in search, and searched my entire hard drive for files with "pbrush" in the name. However, even that search turned up 0 results. To all appearances, there simply was no file named pbrush present anywhere on the machine.

I did notice, by bringing up Task Manager, that the actual executable that was being launched was always mspaint.exe, even when I was entering pbrush in the Run dialog to launch the program. I was still curious, though, how running pbrush (which to all appearances did not exist) could cause the mspaint.exe file to be launched.

I started up Filemon and set up a filter to show only references to "pbrush", then launched pbrush.exe from Start | Run.

Interestingly, Filemon showed only a single "not found" error for pbrush.exe. Normally, Filemon will show a "not found" error for every directory in the path when an attempt is made to run a program with a filename that doesn't exist. So in this case, it appeared that Windows was looking in just the C: drive for pbrush.exe, and then doing "something else" which resulted in Paint being launched, before Windows went on to look for pbrush.exe on the path.

I then ran Regmon, again filtering on "pbrush", and ran pbrush.exe once again.

Aha! In line 6 of the Regmon output, I could see some kind of mapping from pbrush.exe to mspaint.exe. I figured that this must be the link between pbrush.exe (which I was running from the Run dialog) and mspaint.exe (the app that was actually getting launched) that I was looking for. So I decided to take a look at the HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths registry key.

I opened up Regedit and navigated to My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths.

At that location, I found a key for pbrush.exe, along with many other keys with names of .exe filenames, many of them familiar. By doing a bit of experimentation, I was able to conclude that the App Paths key acts as a sort of map that Windows uses to find the location of an executable file being run.

For most of the App Paths keys, the (Default) value for the key mapped to the full path to the executable of the same name; for example, on my machine, the Winword.exe key mapped to "C:\PROGRA~1\MICROS~2\OFFICE11\WINWORD.EXE", the actual location of the Microsoft Word executable. (As I discovered, this is why entering winword at the Start | Run dialog successfully launches Word even though the Office11 folder isn't on the path.) In the case of the pbrush.exe key, though, the mapping was to the location of mspaint.exe; thus, running pbrush resulted in mspaint.exe, the Paint program, being launched. Mystery solved!

From some newsgroup posts that I came across while researching this issue, apparently on Windows 9x series machines (e.g. Windows 98), a pbrush.exe file actually was included in the system32 directory that was just a stub which executed mspaint.exe. (In even older Windows versions, pbrush.exe was the 16-bit version of the Paint program; the 32-bit version, mspaint.exe, was apparently introduced with Windows 95.) For the 32-bit Windows NT series, an engineer at Microsoft must have decided to switch the pbrush command from working via the actual pbrush.exe stub file to taking advantage of the HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths registry key.

Friday, June 01, 2007

Tips from TweakUI

Earlier today I was using Microsoft’s TweakUI utility for Windows XP to make some changes to the settings on my new laptop, when I started going through the utility's "Tips" section. I picked up some interesting tricks that can be filed under "things I didn't know Windows could do"! I thought a few of the tips were interesting enough to be called out here, to spread the word about them.

Tip: You can simultaneously select multiple items (running applications) in the Windows Taskbar (at the bottom of the screen) by holding Ctrl and right-clicking them.

There are a couple of interesting uses for this trick:

  • Tile 2 or more specific applications
Holding Ctrl, select 2 or more applications on the Taskbar, then right-click one of them. On the context menu that appears, select Tile Horizontally or Tile Vertically to have the applications' windows be positioned side-by-side on the screen, filling all of the screen's entire viewable area.
  • Close 2 or more applications at once
As above, select the Taskbar buttons for 2 or more applications and right-click to bring up the context menu, and select Close to close all of the applications at once. I haven't played with this a lot yet, but this may be a faster method of closing many applications (right before shutting down a machine, for example) then individually right-clicking the Taskbar button for each app and selecting Close, or clicking the "x" button on each application's window.

Tip: In Internet Explorer's address bar, press Ctrl+Enter to have the browser automatically prepend "www." and append ".com" to the typed address.

I've been using this one for a while now (as I've mentioned previously), but it's enough of a time-saver that it's worth another mention. You can, for example, type google in the Internet Explorer address bar and press Ctrl+Enter to be taken directly to http://www.google.com, instead of having to type out www.google.com. (Credit to Jeremy for originally showing me this!)

This Ctrl+Enter shortcut works in Firefox as well!

Tip: In Internet Explorer, hold Shift while clicking the "Organize Favorites" menu pick to open the Favorites folder in Explorer.

This is a lot nicer than using IE's built-in Organize Favorites dialog -- which is kind of weak from a UI perspective -- which normally gets activated when the "Organize Favorites" menu item is picked.

Tip: In Internet Explorer, hold Shift while scrolling the mouse wheel to go Forward or Back.

You can also go forward/back without using the mouse by using Alt + Left Arrow (back) and Alt + Right Arrow (forward).

(Idle speculation: Are the functionality Alt + Left Arrow and Alt + Right Arrow shortcuts reversed for users of versions of Windows installed with a right-to-left language (as opposed to a left-to-right language like English)?)

You can hold the Ctrl key while scrolling the mouse wheel to increase or decrease the size of the text on the page.

These shortcuts all work in Firefox as well.

Press Win (Windows Key) + L to lock the computer.

This is useful to do when stepping away from your desk at work. (I'm not sure what, if anything, this shortcut does when Windows is configured not to prompt for credentials at startup.)

Thanks to the folks behind TweakUI at Microsoft for these great tips!

Thursday, May 24, 2007

Fix: Firefox tries to navigate to "www.localhost.com"

I was having a problem at work last week where when I would point Firefox to http://localhost/, it would instead try to navigate to http://www.localhost.com/.

The problem ended up being related to the settings for my proxy server. I was able to fix the problem on my machine by adding "localhost" to the list of hosts for which Firefox bypasses the proxy server.

In Firefox 2.0, you can do this by going to Tools | Options | Advanced | Network tab and clicking the "Settings..." button in the "Connection" section on the dialog. Then, in the Connection Settings dialog, in the "No Proxy For" field, type localhost. (The new value should be separated from other host names that are already present in the field, if there are any, by a comma.)

Note that this solution is most likely only applicable if you are using a proxy server to connect to the Internet (i.e. if the "Manual proxy configuration" radio button on the Connection Settings dialog is checked).

Tuesday, May 15, 2007

PathFind.exe 2.0 released

I've updated my PathFind utility to version 2.0. PathFind.exe is a command-line utility which shows you all of the copies of a particular file that are present on your path (per the PATH environment variable). The functionality is similar to the which command for Unix/Linux.

PathFind.exe is useful to check which version of a particular program (such as ildasm.exe) will run when you run the program from the command line. (The first copy of the program present on the path will be the one that runs, assuming a copy of the program isn't also present in the current working directory.)

Version 2.0 of the utility supports use of the cmd.exe * and ? wildcards for searching. For example, pathfind java*.exe would return all instances of java.exe and javac.exe (among others) on the path, whereas pathfind ????? would return all files with 5-character filenames on the path.

2.0 continues to support automatic extension searching based on the PATHEXT environment variable when no "." character or wildcard characters are specified, so pathfind iisreset will show you where iisreset.exe is located.

You can download it directly from this link: PathFind 2.0 (5k). Requires the .Net Framework 2.0 or higher to be installed.

Wednesday, May 02, 2007

Congratulations, Jeremy!

My younger brother Jeremy has been named to the 2007 Crain's Detroit Business "20 in their 20s", a group of young movers and shakers in Detroit-area business, for his role as founder and president of RentLinx, a free online apartment listings service!

Congratulations, Jeremy!

Friday, April 27, 2007

Windows Forms Controls in IE Troubleshooting Guide

This post covers troubleshooting information for issues with loading .Net Windows Forms Usercontrols in Internet Explorer. IE in many cases does not provide clear error reporting when something goes wrong with loading a Windows Forms control embedded in a web page; the information here is presented to hopefully act as an aid in troubleshooting such issues.

For information on the general technique of embedding Windows Forms controls in web pages via <object> tags for viewing in Internet Explorer, take a look at these tutorials:

Tip: Viewing Fusion Bind errors from Internet Explorer

When a Windows Forms control fails to initially load properly, one or more "fusion bind errors" with information that may be helpful in diagnosing the problem may be logged.

Viewing fusion bind errors generated from errors loading .Net controls in Internet Explorer:

  • Open the Temporary Internet Files folder in an Explorer window. (One way to do this is from Internet Explorer, select Tools | Options; on the Internet Options dialog, on the General tab, next to "Browsing History", click Settings; on the Temporary Internet Files and History Settings dialog, click "View files".)
  • In the Temporary Internet Files explorer folder, sort by the Last Modified column to bring recent fusion bind error files to the top.
  • Look for files named "?FusionBindError ...". You can't double-click these files to view them; instead, open a new Internet Explorer window, and drag one of the Fusion Bind Error files to the new window to view the contents.

Setting up .Net framework trust to allow Windows Forms controls hosted in a web page on a remote web server to run

For .Net controls embedded in web pages that perform certain types of operations, .Net framework code access security trust must be set up to allow the control to load and run; if this is not done, the security policy of the .Net framework on the client machine will prevent the control from loading.

If a .Net control does fail to load due to load due to .Net trust not being set up properly, the symptom will be an empty rectangle with a "colorful icon" present in the top-left corner displayed on the web page in place of the control. (See the FAQ section below.)

In an internal corporate / LAN environment, trust can be granted to the web server hosting the web page that includes the .Net control. This can be done from the client machine by using the Microsoft .Net Framework Configuration tool (if it is installed), or from the command line by using the caspol.exe utility.

Granting .Net trust to a specific web server with the Microsoft .Net Framework Configuration tool

This tool is not installed on all machines. (I'm not sure when/how the tool does get installed on machines where it is present.) On machines where the tool is present, it can be found in the Administrative Tools folder as "Microsoft .NET 2.0 Configuration", where "2.0" is the actual installed version of the .Net framework.

Be sure to set up trust using the version of the tool that matches the .Net version which Internet Explorer will be using to load and run .Net controls. (In most cases, this will be newest version of the .Net framework installed on the machine.)

Setting up .Net framework trust on a single client machine for controls running on a particular web server:

  • Drill to .NET Framework Configuration | My Computer | Runtime Security Policy | Machine | Code Groups | All_Code.
  • Right-click All_Code and choose New from the context menu.
  • In the Create Code Group dialog that appears, enter a name for the new code group, then click Next. (The name can be anything, but I suggest using the name of the web server machine for which trust is to be established.)
  • In step 2 ("Choose a condition type"), select URL from the dropdown; in the URL field that appears, enter "http://mywebserver/*", where mywebserver is the actual name of the web server to trust. (If you use SSL to connect to the web server, enter "https" instead of "http".)
  • In step 3 ("Assign a Permission Set to the Code Group"), check the "Use existing permission set" radio button and select "FullTrust" from the dropdown. Click Next.
  • Click Finish on the final step of the Wizard.

Granting .Net trust to a specific web server with the caspol.exe command-line utility

Caspol.exe is a command-line code access security policy tool that is installed with the .Net framework. Caspol.exe is located at:

%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\caspol.exe

Where 2.0.50727 is the version number of the .Net framework installed on the client machine that IE is using to load the control. (2.0.50727 is the version number of the commercial release of the 2.0 .Net framework.)

Run the following command to establish .Net framework trust for a web server named serverName:

caspol -machine -addgroup 1 -url http://serverName/* FullTrust -name "http://serverName"

To view existing trust group settings set up on the local client machine, use:

caspol -lg

Regardless of which method is used to establish trust, after setting up trust for the web server, you'll need to close and re-open Internet Explorer to get it to pick up new trust setting.

The remainder of this document takes a FAQ format, with problems/issues in boldface and possible resolutions in plain type.

The "Colorful Icon" Issue

When attempting to load a Windows Forms control, the control does not appear; instead, a white box with a thin black outline appears in place of the control, with a colorful icon in the top-left corner.

A Windows Forms control that has failed to load, showing the "colorful icon"

Q: A Fusion Bind error is logged with this text: "System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.VerificationException: Operation could destabilize the runtime."

A: The most common cause of this problem is that the control requires .Net Framework trust to run, but trust has not been granted to the server hosting the control, or to the control itself, by the client machine (the computer where Internet Explorer is running). See "Setting up .Net framework trust" above.

Other general things to check for a control failing to load with the "colorful icon" symptom:

A: The client machine might be configured to not trust unsigned .Net or ActiveX controls in IE | Tools menu | Internet Options | Security tab. (Not sure about the exact setting.) Adding the web server to "Trusted Sites" on the client will generally fix this. (This seems particularly common when the client is Windows 2003 Server.)

A: If the class constructor of the .Net control is throwing an uncaught exception, this behavior will occur. Try stepping through the constructor in a debugger (assuming the control is one you are developing).

A: Try clearing the Temporary Internet Files on the client machine (especially if some .Net components in the browser are working, but not others).

A: If the same browser window was previously used to bring up the same .Net control from a different virtual directory on the server machine, close the browser window and use a new one.

A: There could be something invalid or malformed in the client machine's machine.config file.

A: There could be an invalid or malformed iexplore.exe.config file present in the same folder as the Internet Explorer executable (typically C:\Program Files\Internet Explorer\). Try temporarily renaming the iexplore.exe.config file to something else.

More specific symptoms and resolutions for situations where IE is showing the "colorful icon" in place of the .Net control after the control has failed to load:

Q: Client is connecting to server using SSL (https://...). Connecting to the server using a normal (non-SSL, http://...) connection does load controls correctly (if the server permits non-SSL connections).

A: Ensure that .Net framework trust is set up on the client machine for the web server machine with both the "https://" and "http://" prefixes (2 separate trust entries).

A: In Internet Explorer | Tools | Options | Advanced tab, uncheck "Do not save encrypted pages to disk".

Q: On the server machine, the most recent event in the IIS log is a 401 error trying to load a config file linked from the web page where the .Net control is located using a <LINK REL='Configuration' HREF='/configFile.conf'> tag. No Fusion Bind error is logged on the client.

A: Check the Windows filesystem permissions on the .conf file. Try giving the "Everyone" group full permissions on the file to establish whether or not this is the problem. (If applying "Everyone" permissions does work to resolve the issue, you will probably then wish to remove "Everyone," and apply more fine-grained permissions, to allow IIS to serve the control, but without compromising security.)

A: On the server, in IIS Manager, under File Security for the config file (for that specific file, not the parent virtual directory security), if Anonymous access is checked, ensure that "Allow IIS to control password" is also checked.

Q: Server OS is Windows 2003 Server. Navigating in the browser directly to the config file referenced in the .Net control's web page results in a 404 error (even though the file really is there on the server).

A: In the Internet Information Services Manager utility, open the Properties dialog for the config file's parent virtual directory. In the HTTP Headers tab, click the Mime Types... button, and add the config file's extension (.conf).

Q: A new .Net framework version was recently installed on the client, after which the control started failing to load.

A: Set up trust for the web server machine under the new .Net framework version (as described above).

Q: A Fusion Bind error shows a FileLoadException and error message text that talks about a DLL file version incompatibility. The control may load properly from a different client machine, or when a different user is logged into the OS.

A: Clear the Shadow Cache for the user on the machine where the problem is occurring. (The Shadow Cache is typically located at "C:\Documents and Settings\username\Local Settings\Application Data\assembly\dl?", where ? is a numeral. Delete the entire directory tree under the "dl?" folder to clear the cache. It may be necessary to enable viewing of hidden files/folders to see the cache.)

Q: When using compressed .cab files referenced from a .conf file on the server to deliver the .dll file(s) for the Windows Forms control, a fusion bind error shows "System.IO.FileNotFoundException: File or assembly name ControlType, or one of its dependencies, was not found.

A: This may indicate some problem on the server or client with loading .cab files. One possible cause: The MIME type associated with cabinet files (.cab) is incorrectly set in IIS (HTTP Headers | File Types) to a content type of "application/x-compressed"; the MIME type associated with a .cab file must be "application/octet-stream" for .Net to load the controls from the cab file. In inetmgr, in the HTTP headers tab, click File Types... and fix the setting.

Q: The Fusion Bind Error shows something like "System.TypeLoadException: Could not load type 'Typename' from assembly 'TypeName'"

A: The class name specified in the object tag needs to have correct casing (uppercase/lowercase). In the example above, you would need to change "Typename" to "TypeName".

"Vertical Scrollbar" issues

Q: When attempting to load a Windows Forms control, the control does not appear; instead, a white box with a thin black outline appears in place of the control, with a colorful icon in the top-left corner.

A Windows Forms control that has failed to load, showing the "disabled vertical scrollbar"

A: Check the classid parameter of the control's <object> tag to be sure it is pointing at a valid virtual directory.

A: Make sure that the DLL file referenced in the classid is present in the virtual directory.

A: Rarely, I've seen this issue happen when in on the server, IIS settings (inetmgr), Execute Permissions for the virtual directory is set to "Scripts and Executables". Try setting Execute Permissions to "Scripts only".

A: When debugging an ASP.NET page through Visual Studio 2005, apparently the "ASP.NET Development Server" that Visual Studio 2005 provides for debugging ASP.NET 2.0 apps doesn't support display of Windows Forms controls in the browser. Use the real IIS server on the machine instead. (You can debug the ASP.NET page running in IIS by manually attaching the Visual Studio debugger to the aspnet_wp.exe process once the ASP.NET site has been initially opened in the browser.)

"X" Icon Issues

Q: When attempting to load a .Net control, the control does not appear; instead, a white box with a thin black outline appears in place of the control, with an "X" icon in the top-left corner.

A Windows Forms control that has failed to load, showing the "X" icon

A: Make sure that the .Net framework has been installed on the client machine.

A: Check that a classid parameter is present in the <object> tag in the HTML source of the web page where the control is located.

A: Check the primary DLL file of the assembly that the control is attempting to load. (I've seen this happen in a contrived case when a control was trying to use a .dll file with file size 0.)

Other Issues

Q: When attempting to load a .Net control, an error dialog appears: "Your current security settings prohibit running ActiveX controls on this page. As a result, the page may not display correctly." After the dialog is dismissed, the control does not appear on the page at all.

A: In Internet Explorer, go to Tools | Internet Options | Security tab. Running signed ActiveX controls needs to be allowed for the "zone" that the web server is in; the zone settings can be changed to "Medium", or the web server can be added to a more trusted zone ("Local intranet" or "Trusted sites").

Q: After a .Net control loads, it appears correctly, but the user needs to click the control before it can be interacted with. Before the control is "activated", a tooltip appears when the mouse is hovered over the control with text "Press SPACEBAR or ENTER to activate and use this control" or text "Click to activate and use this control".

A: This issue is caused by a change that Microsoft was forced to introduce in Internet Explorer due to patent litigation between Microsoft and Eolas. For details and workarounds, see the article Activating ActiveX Controls on MSDN.

Q: When attempting to load a .Net control, the control does not appear; instead, a solid gray box with no error message text appears.

A: Check the syntax of the <object> tag in the HTML source. IE is probably not recognizing it as an attempt to show a Windows Forms control.

Scripting Issues

Q: When calling a public API method on a .Net control from Javascript running on the web page, the Javascript error "Object doesn't support this property or method" occurs.

A: The .Net control probably didn't load successfully. (This may be non-obvious if the control is hidden on the page.)

Q: A script call to a .Net control fails with the Javascript error message "Unexpected call to method or property access."

A: Apparently IE doesn't support child windows directly calling methods in Windows Forms controls located in a browser parent window (using syntax like "window.opener.document.ControlID.Method()") . As a workaround, rewrite the script to call a Javascript function on the parent page, then have the new function make the actual call to the .Net control.

Q: A script call to a .Net control fails with the Javascript error message "Invalid procedure call or argument."

A: The script code may be calling the method with an incorrect number of method parameters.

Debugging Issues

Q: After making a code change to the .Net Usercontrol and rebuilding, the changes made are not reflected in the browser window, even after refreshing the page.

A: Close the current browser window, and reopen the web page in a new one.

Q: Can't hit breakpoints in the Visual Studio debugger when debugging a .NET Windows Forms object in the browser.

A: If launching the browser directly from Visual Studio, in Project Properties, on the Debug tab, make sure "Start external program" (pointing to iexplore.exe) is checked, not "Start browser with URL".

A: Make sure the DLL files used in the page being debugged are debug (not release) versions.

Q: When the Visual Studio 2003 .Net debugger is attached to an iexplore.exe instance, as soon as a .Net control starts loading, the browser closes and debugging ends. Both .Net 1.1 and 2.0 (or a later version) are installed on the machine. Q: Can't attach the VS.NET 2003 debugger to an iexplore.exe instance which is already running a .NET control.

A: Visual Studio 2003 can only debug .Net version 1.1 (not 2.0 or later versions), so you need to force IE to load controls using the 1.1 .Net framework. Create a new file named iexplore.exe.config in the Internet Explorer folder (the folder where iexplore.exe is located) with the following content:

<configuration>
 <startup>
   <requiredRuntime version="v1.1.4322"/>
   <supportedRuntime version="v1.1.4322"/>
 </startup>
</configuration>

This will force Internet Explorer to load any .Net controls that it encounters in web pages in the 1.1 version of the .Net framework, beginning with the next time a fresh instance of Internet Explorer is opened.

When finished debugging in Visual Studio .Net 2003, remove the iexplore.exe.config file to permit .Net controls (and possibly also Internet Explorer extensions) which require .Net 2.0 to run properly once again.

The information in this post is current as of Internet Explorer 7 and the .Net framework 2.0.

Please note that this is not a comprehensive guide to all possible issues that may occur with running .Net Usercontrols in Internet Explorer; also, the troubleshooting suggestions here may not work to resolve a given issue in all cases. Please use caution when making configuration changes to your system (particularly security-related changes)!

Thursday, April 26, 2007

Workaround: Foxit Reader Find feature not working

I was just using the basic Find feature of the lightweight .pdf document reader Foxit Reader to search for some text in a particular .pdf document. Inexplicably, the Find dialog kept reporting no results found, even though I was sure that the word I was searching on was present in the document.

I tried searching on other words in the document (even common words that I could see in the visible portion of the document on the screen right in front of me, such as "the"), but Foxit kept insisting on finding no results. Finally, out of frustration, I tried searching on a single letter ("a") -- and surprisingly, that did work correctly!

I subsequently figured out that the problem was that Foxit Reader was for whatever reason apparently rendering a tiny space between each pair of letters in each word of the document. So searching on "options" produced no results, but searching on "o p t i o n s" (with a space inserted between each letter) did successfully find each instance of the word "options" in the document.

I'm not sure why Foxit Reader (version 2.0 build 1606) was behaving this way, but at least using this workaround I was able to find what I was searching for. I did try opening the same .pdf document in Adobe Acrobat Reader 7, and I was able to successfully perform searches in the normal manner, without needing to insert spaces between each letter in the word I was searching on.

Friday, April 20, 2007

Strict mode IE6 bug with CSS "Bottom" style on img tags

While working on part of a new ASP.Net site at work recently, I came across a weird behavior when viewing the page in Internet Explorer 6 where a particular image on the page wasn't staying aligned with the surrounding elements on the page when the browser window was resized. I was able to boil the problem down to a very simple repro case on a basic html page. Here's the source code for the repro page:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
  <img src="AnyKey.gif" style="position:absolute;bottom:20px">
</body>
</html>

It turns out that the problem is that for whatever reason, IE6 only recalculates the position of the image relative to the bottom of the browser window when the browser window is resized horizontally -- but not when the browser window is resized vertically! So on IE6, if you resize the browser window to be vertically, the image stays fixed in place, not moving to follow the bottom edge of the window. But when you resize the browser window horizontally, the image immediately pops back into its proper place relative to the bottom edge of the window.

I went ahead and put the repro page up on my website, here -- feel free to take a look if you happen to be using IE6.

Oddly enough, this issue only affects IE6 when in CSS standards-compliance mode; if the page is put into the IE6 quirks mode by deleting the !DOCTYPE tag from the top of the html source, the image does correctly move to follow the bottom edge of the browser window when the window is resized vertically in IE6.

The workaround I found for this issue is simple; just enclose the img tag in a div tag, and put the style attribute on the div tag instead of the img tag:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
 "http://www.w3.org/TR/html4/strict.dtd">
<html>
<body>
  <div style="position:absolute;bottom:20px">
    <img src="AnyKey.gif">
  </div>
</body>
</html>

This odd behavior doesn't happen in the other browsers I tested (IE7 and Firefox 2.0).

I am looking forward to the day when IE6 has been phased out enough that needing to code around its occasional quirky behavior is no longer necessary -- but that day is most likely years away yet!

Wednesday, April 18, 2007

Fix: "Networking is not installed or properly configured"

I was running into a problem earlier today on a secondary Windows XP SP2 machine of mine at work where although the machine could browse the Internet successfully and could ping other machines on the local network, it could not connect to any file shares (shared folders) on other machines on the local domain. Other machines on the network could still browse file shares with no problem.

On the machine experiencing the problem, in the Computer Name tab of the System Properties dialog (brought up from Control Panel | System), the "Network ID" and "Change" buttons were disabled (grayed out). A message at the bottom of the dialog indicated that the reason for this was that "networking is not installed or properly configured".

I was able to fix the problem by removing and re-installing the machine's Client for Microsoft Networks, as follows:

  • From the Control Panel, open Network Connections.
  • Right-click on my active Local Area Network connection and choose Properties.
  • In the Local Area Connection Properties dialog, select Client for Microsoft Networks, then click Uninstall. Close the dialog and reboot when prompted.
  • After rebooting, bring up the Local Area Connection Properties again.
  • Re-install the Client for Microsoft Networks by clicking the Install button, selecting Client from the Select Network Component Type dialog, then selecting Client for Microsoft Networks from the Select Network Client dialog. Click OK all the way back out, then reboot the machine once more when prompted.

I don't know enough about the internals of Windows networking to understand *why* this solution worked to fix this problem in my case -- only that it did work! I share the steps I took here in hopes that they might be helpful to others as well (as a possible alternative to more extreme solutions such as re-installing Windows!).

(Please do consider carefully before following these steps; Client for Microsoft Networks is a critical Windows networking component, and removing it -- even with the intention of subsequently re-installing it -- could possibly have other adverse affects on a system. For example, if the re-install of the Client for Microsoft Networks were to fail for whatever reason, the machine could be left in a state where the machine's network connectivity is even further adversely affected.)

Monday, April 02, 2007

Using both "left" and "right" properties in a CSS style

I recently was working on a web page where I needed to draw a rectangle that would always be 50 pixels from the left edge of the browser window and 100 pixels from the right edge of the browser window, and which would stretch/shrink to maintain these criteria as the browser window was resized by the user. (Essentially, the rectangle would be "anchored" to both the left and right edges of the browser window.)

This rectangle would otherwise always appear on the same place on the page, and thus could be set to use the position:absolute style. Anchored Rectangle I decided to use a simple <div> tag set with a background-color CSS property to render the rectangle on the page.

To accomplish this, at first I was thinking I would need to catch the browser's window resize event, and call a Javascript function that would check the browser window's new width, subtract from that width the right "padding" for the rectangle (100 pixels in this case), and set the resulting figure as the new width for the rectangle.

Then I hit upon an alternative solution which wouldn't involve any scripting at all: I could simply set both the left and right CSS properties of the rectangle. The browser would be responsible for maintaining the rectangle's distance from the left edge of the browser window as well as the rectangle's distance from the right edge of the window, and thus script to resize the rectangle would not be necessary. The width property would not need to be specified at all, since the browser itself would calculate the width required to keep the rectangle the specified distances from the left and right browser window edges.

This works great in IE7 and Firefox 2. Unfortunately, it doesn't work in IE6. Apparently IE6 just does not support the specification of both left and right properties, or both top and bottom properties, of a CSS element. Instead, you need to specify one or the other plus width or height (as appropriate).

I did end up finding an approach that would work with IE6 and still only need a single line of CSS (at least for IE support). For IE, the CSS width property can be set using IE's proprietary "expression" syntax as in this snippet of CSS:

left:50px; width:expression((this.parentNode.offsetWidth - 150) + 'px')
This sets the width of the element to which the style is applied to the width of the parent element (the browser window, in the case of top-level elements), minus the specified value (150 in the above example), which should be set to the sum of the left property value and the effective value for the right property. In the above example, the style would cause the element to be offset 50px from the left edge of the browser window and 100px (150 - 50 = 100) from the right edge of the window. The width of the element gets recalculated on-the-fly as the browser window is resized.

Note that the "expression" syntax is IE-only, so as far as I know, it won't work in Firefox or other browsers. It does work ok in both IE6 and IE7.

Also, use of "expression" relies on Javascript being enabled; in the example above, if Javascript is disabled, the rectangle doesn't render on the screen at all.

Wednesday, March 28, 2007

Fix: Regsvr32 error "The specified module could not be found"

This morning, a tester to whom I had provided a COM .dll file with some extra logging to drop into his installation of one of our products reported to me that he was getting this error when trying to register the .dll on his machine using regsvr32: LoadLibrary([Filename.dll]) failed - The specified module could not be found. I re-checked, and the .dll file I had sent did register properly with regsvr32 on my own machine.

I investigated, and Google Groups helped me find the solution in a microsoft.public.win32.programmer.ole thread. The problem was the .dll file I had built was built in Visual C++ 6 in "debug" mode .dll; the "debug".dll (unbeknownst to me at thetime) had extra .dll dependencies which were present on my machine, but not on the tester's machine.

The solution was to build the .dll in "release" mode instead.

Google also turned up a helpful cryer.co.uk article which lists (1) "The name of the COM object is wrong" and (2) "The COM object requires another library which is missing" as possible causes of the "The specified module could not be found" regsvr32 error. The article suggests using the Sysinternals Filemon utility to determine which .dll file(s) are missing.

Tuesday, March 20, 2007

At Wit's End with Wii Wireless

A couple of weeks ago, I snagged a Nintendo Wii on a Sunday morning from a Target in my area that had gotten a shipment during the week and had released them for sale as their new ad flyer featuring the Wii came out that Sunday.

As I've previously posted, I have a Linksys BEFW11S4 wireless router, hardware revision version 4.

When I initially set up the Wii for wireless connectivity with the router, it worked like a charm. I was able to connect, and the various online functionality -- the store, news, weather, web browsing, and the "Everybody Votes" application -- all worked just fine.

However, the next day, the Wii reported that it was unable to connect to the Internet. I reset the router (by disconnecting it from wall power for a couple of seconds and then plugging it back in), and the Wii was once again able to connect successfully.

I knew to try resetting the router because I recognized the behavior as the same as what my TiVo has been exhibiting -- the TiVo will work normally for about a week, but then report that TV program data is low because it hasn't been able to successfully connect to the server, and I'll need to reset the router to get it to connect successfully again.

This problem hadn't been terribly annoying when just the TiVo was affected, since it wasn't too bad to just briefly pull the plug on the router once a week or so (since the TiVo is able to get TV program data for about a week in advance each time it connects). With the Wii, though, it will usually only go about half a day or so before it will lose the wireless connection and be unable to reconnect; this means that pretty much any time I want to use any of the online functionality of the Wii, I need to run upstairs to my office and pull the plug on the router first. And even then, the Wii takes longer than it should to display the news, since it didn't have a chance to download it in the background earlier while the system was idle via the "WiiConnect24" feature, and instead needs to download it on-the-fly. Annoying!

My desktop PCs, which are connected to the router via wired connections, aren't affected by this issue. Further, although I use my PDA's wireless connection functionality at home only infrequently, I've also never observed it be affected by the issue; the PDA seems to be able to connect with no trouble, even at times when the Wii won't connect.

The problem does seem to be with the router as opposed to with the Wii, since the TiVo is affected by the same problem.

It's a frustrating problem to troubleshoot, since each time I change a setting on my router to try and address the problem, I need to wait at least half a day before the Wii's connection will fail again (and thus establish that the attempted fix didn't work).

I've tried the following steps so far to fix the problem, one at a time; none have been successful so far:

  • Assigned the Wii a fixed IP address (and DHCP server IPs) rather than having it pick up an IP via DHCP.
  • Changed the broadcast channel of the router. (Tried channels 1, 2, 6, and 11).
  • Disabled the WEP security on the router. (Turned it back on afterwards after this didn't help.)
  • Disabled restriction of clients permitted to connect based on the client MAC address. (Re-enabled this after it didn't help.)
  • Reverted the firmware from 1.52.02 (the latest version) back to 1.50.14, after reading online about people having (unrelated) problems with the 1.52.02 firmware.
  • Changed the router's "Internet Connection Type" setting from "Connect on Demand" to "Keep Alive", thinking that maybe if my router's DHCP IP address lease from my ISP had expired, then the wireless connection from the Wii wasn't for whatever reason triggering the router to request a new IP, and that this setting change might trigger the router to always make sure that it had a current IP.
Unfortunately, none of these attempted solutions have had any impact on the problematic behavior. (After I applied the firmware version downgrade, I thought that might have done the trick since the Wii behaved itself for a little over a day after that, but the problem subsequently returned, just as before.)

I also haven't been able to find anything about this specific problem by searching around online. I've seen lots of posts about problems where people can't get the wireless connection to work at all, or where specific areas of functionality (like the online store) won't work, but no posts about this type of problem where the connection just seems to expire or time out after several hours.

At this point I feel like my best option to address the problem is to just pick up a new router, but I hesitate to throw $50 at the problem to fix it, since it really is just an annoyance.

If anyone knows of a fix for this issue, or even just has a suggestion for something else to try that might fix the problem, by all means please let me know! I'll update this post if I ever do come up with a solution for this issue.

Update 5/4/2007: Everything is working once again now! The Wii and the Tivo are now able to connect to the Internet over the wireless connection on a daily basis with no problem. So what did I change?

Nothing!... except that I left the BEFW11S4 router powered off for about 9 days straight while my family and I were away from home on vacation! When I returned and powered the router back up, everything started working fine. Prior to that, I had always had the router plugged in around the clock (except when I'd unplug it for a few seconds at a time to get the Wii and Tivo connectivity temporarily working again).

So if you're having this problem and have tried everything else, you could try unplugging your router for a while, perhaps overnight, or longer if you can get away with it. I'm not sure why this solution worked in my case -- maybe some hardware component in the router had overheated and needed some time unplugged to cool down? -- but I'm happy that things are working once again!

Thursday, March 01, 2007

Possible fix: IE7 won't show Favicon

I ran into a problem this morning where my install of Internet Explorer 7 was refusing to show the new favicon that I had dropped into the root directory of the website on my local IIS 5 installation for web pages hosted on the server. (Previously, the site had been running without any favicon.)

(A "favicon" is the icon image that gets displayed in the browser's address bar and as the bookmark icon, among other places, for websites that are designed to take advantage of that functionality. For example, the University of Michigan site uses a maize-and-blue "M" icon as the favicon. Note that in IE6, you need to bookmark a site and load that site back from the bookmark before the favicon will display in the address bar.)

Although all the reading I had done suggested that IE7 has full support for favicons, the new icon wasn't being displayed for any of the pages on my site; IE7 would instead just show the generic "IE document" icon. The icon did display correctly in Firefox, and also in another copy of IE on a different machine. Looking at the web server's IIS log, I could see that IE7 wasn't even attempting to request the favicon.ico file from the server.

I tried some simple workarounds to try and trigger IE7 to request the new icon, such as clearing IE's temporary internet files and re-bookmarking the web site, but didn't have any luck. And I could see that my IE7's support for favicons wasn't totally broken, as other sites in my bookmarks (favorites) list did still correctly display their favicons.

After spending a fair amount of time researching the problem across various websites and newsgroup postings, I finally came across a suggested workaround/solution at Wickham's XHTML & CSS tutorial (thanks Wickham!) that ended up fixing the problem for me. The workaround was to clear my IE7 browsing history. (Ctrl+H to bring up the History panel, then select each of the top-level items and delete them with the Delete key).

After clearing my IE history and closing and reopening the browser window, the favicon finally did display properly.

I'm unable to reproduce the issue now; my copy of IE7 is now correctly immediately picking up changes when I remove the favicon.ico file or drop a different favicon.ico into place, so I can't be certain that deleting the IE7 history (which admittedly seems like an odd solution) was what actually fixed the problem. Still, I'm posting this here in hopes that the workaround of clearing IE7's browsing history might be helpful to anyone else who is having a similar problem getting IE7 to properly show a particular website's favicon.

Update 3/7/2007: Jeff Davis ("jeffdav") from the Microsoft Internet Explorer team has posted to his blog a troubleshooting guide for favicons in IE7. It actually does mention clearing browsing history as a possible fix for favicons not showing up as expected. Go check it out if you're having trouble with favicons in IE7! (Thanks for the info, Jeff!)

Wednesday, February 21, 2007

My 60-second RSS primer

If you're already reading this and other technical blogs, there's a good chance that you're already familiar with RSS feeds. I wrote this 60-second primer to explain RSS for a co-worker today, and I thought I'd share it here as well for any other RSS beginners out there. Everyone was a beginner once!

RSS stands for Really Simple Syndication. It's a way for you to "subscribe" to frequently-updated web sites such as blogs, and be notified any time there is new content available on each site. Further, you can use an "RSS Reader" application to manage all of your subscriptions, and to read all of the new content from within the reader application.

Why bother with using an RSS reader instead of just directly visiting the website of each individual blog that you like to read? Here are two pretty good reasons:

(1) You don't have to spend time visiting a site only to find that it hasn't been updated since your last visit.

(2) It's faster to skim/read all of the new content from the sites that have been updated from a single centralized location, instead of having to visit them all individually.

How do you know if a site provides an RSS feed of its content? Such sites will generally display a small orange RSS icon somewhere on the page: RSS In Firefox, the RSS icon be displayed at the right end of the browser's address bar when you're at a site that provides an RSS feed. You can generally copy-and-paste the site URL into your RSS reader to subscribe to the site's RSS feed. In Firefox 2 you can just click on the orange icon in the address bar, and it will automatically handle the subscription for you, if you already have an RSS reader program set up.

Here are a couple of links for you to get started with. The RSS reader I use is a free web-based application called Bloglines, located at http://www.bloglines.com One of my favorite blogs to read is Jeff Atwood's "Coding Horror" technology issues blog at http://www.codinghorror.com/blog/.

Thursday, February 15, 2007

Windows Forms in IE don't load properly in ASP.NET AJAX 1.0

I'm currently running into a problem where Windows Forms .NET controls embedded in a web page, when included in an ASP.NET AJAX UpdatePanel, fail to load properly after the UpdatePanel is updated. An "x" icon is displayed where the control should be.

For a simple UserControl that would normally appear like this:

This is displayed instead after the AJAX update:

Unfortunately, I haven't been able to figure out the root cause of this issue yet. I took a look at the post-update HTML (using a trick from Rumen Stankov -- thanks Rumen!) generated by ASP.NET AJAX, and the HTML looks to be ok.

The problem can be reproduced using a simple .aspx page:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title>ASP.NET AJAX and Windows Forms</title>
</head>
<body>
 <form id="form1" runat="server">
   <asp:ScriptManager ID="ScriptManager1" runat="server" />
   <asp:UpdatePanel ID="_gaugesUpdatePanel" UpdateMode="Conditional" runat="server" >
     <Triggers>
       <asp:AsyncPostBackTrigger ControlID="_updateButton" />
     </Triggers>
     <ContentTemplate>
       <object id="TestControl" name="TestControl"
         classid="TestControl.dll#TestControl.SimpleUserControl"
         height="100" width="200">
       </object>
     </ContentTemplate>
   </asp:UpdatePanel>
   <asp:Button ID="_updateButton" Text="Update" runat="server" />
 </form>
</body>
</html>

When this page initially loads, the Windows Forms control displays correctly. After the "Update" button is clicked (triggering the UpdatePanel to be updated), the control fails to load and the "x" icon is displayed.

For this sample, the "Default.aspx.cs" codebehind page is just the default empty page generated by Visual Studio, and the TestControl.dll is a .Net library with a single simple UserControl, "SimpleUserControl", which just displays itself with a gray background and the "SimpleUserControl" label (as shown above).

The issue is reproducible on both Internet Explorer 6 and Internet Explorer 7.

When the issue occurs, I don't see any warnings or errors recorded in the Fusion Bind log, the web server's IIS log, or the client's Application Event log. (IE is generally pretty bad about providing any detailed error information when something goes wrong with loading a .Net control embedded in a web page, but there is usually at least some information recorded in one or more of these logs.)

My dev group is opening an incident with Microsoft Support for this issue. If we end up getting a workaround from them, or if I am able to come up with a workaround on my own, I'll update this post with the new information.

Update 3/6/2007: I've now discussed this issue over email and phone with Adam S., a member of Microsoft's ASP.NET developer support team.

Adam put together a simplified repro case for this issue with a simple .html (rather than .aspx) page showing that the problem isn't directly with the ASP.NET AJAX controls, but rather with Internet Explorer's implementation of displaying a Windows Forms .Net control that has been placed on a page by setting the innerHTML property of a <div> element with HTML that includes the control's <object> tag. (ASP.NET AJAX leverages the innerHTML property to do its content refresh of UpdatePanel controls, which is why I saw the problem happening with ASP.NET AJAX.)

Adam let me know that this IE bug with setting an element's innerHTML property with HTML that includes an <object> tag is tentatively scheduled to be fixed in Internet Explorer 8.

Of course, while a future IE8 fix for this issue would be nice, it isn't especially helpful to me right now, since I need to have my web application working on IE6 and IE7! For now, I'm going to rewrite my web app to use standard full-page postbacks to update the set of Windows Forms controls displayed on a page, instead of being able to update just a particular portion of the page using AJAX.

Wednesday, January 24, 2007

Partial Fix: "Address Bar [Url] is currently unavailable" in IE7

I previously posted about an issue in Internet Explorer 7 (IE7) where when an IE window is first opened, it hangs for a few seconds with a "Connecting..." message, and if the user tries to navigate to a new page while that message is still being displayed (generally by pasting an URL from the clipboard into the Address Bar and pressing Enter), the navigation fails with the error "[Url] is currently unavailable."

Based on several posts to the microsoft.public.internetexplorer.general newsgroup I looked at this morning, I've found a partial solution to this issue. One possible cause of the long "Connecting..." time in IE7 is the load time of the browser's add-ons.

I took a look at the active add-ons in my copy of IE7 (at Tools | Options | Programs tab | "Manage add-ons" button).

Somewhat to my surprise, I had as many as 30 or 40 add-ons enabled (among the 4 add-on categories shown in the dialog). Probably 80% of the add-ons were labeled as being from Microsoft and which I didn't remember installing; the other 20% were 3rd-party add-ons that I did remember installing -- things like Sun's Java plug-in, Google Toolbar, Macromedia Flash Player, and Adobe Acrobat Reader.

As an experiment, I tried disabling all of the enabled add-ons. I didn't know whether disabling the Microsoft add-ons would break my IE7 and result in it being unable to display web pages correctly, but I figured that in the event that it broke, I could always go back into the Options menu and re-enable extensions until IE7 was working again.

The experiment was a success! IE7 now initially starts up a lot faster, and I can immediately paste in and navigate to an URL via keyboard (Alt+d to focus the address bar, Ctrl+v to paste, Enter to navigate) as soon as the IE7 window appears.

Further, even with all add-ons disabled, I haven't run into any problems with displaying web pages in my brief testing so far. IE7 even displays XML documents correctly despite my having disabled many Microsoft add-ons with names like "XML Document".

I would imagine that I might need to re-enable at least some 3rd-party add-ons to view certain websites (like the Flash add-on for sites that use Flash), but for now, I am happy to use IE7 extension-free -- the delay in startup time was a significant annoyance for me. On the other hand, I could just use Firefox to view Flash sites and other sites requiring similar 3rd-party extensions; my copy of Firefox doesn't have any issues with startup time despite loading several extensions at startup.

I'm not sure why IE7 has this addon-related issue with startup time when IE6 did not. Perhaps one or more of my add-ons which were optimized to run in IE6 just perform really badly under the new IE7 engine, and future versions of the affected add-on(s) will address this.

One of the newsgroup posts I looked at also pointed to a built-in shortcut which runs an instance IE7 with all extensions automatically disabled for that instance; this is accessed (in Windows XP) from Start | All Programs | Accessories | System Tools | "Internet Explorer (No Add-ons)". Interestingly, when I launch IE7 from that shortcut, it is still affected by the "[Url] is currently unavailable" issue that my original copy of IE7 was affected by when attempting to immediately navigate to an URL when the window opens. This may be because opening IE with that shortcut brings up a window with a special "Internet Explorer is currently running without add-ons" homepage (including a yellow "information bar" at the top of the screen), whereas my normal IE homepage is a simple, quick-loading .html page hosted on my local machine.

If your copy of IE7 is starting up slowly with the "Connecting..." message, you may wish to examine the IE add-ons that you have running (Tools | Options | Programs tab | "Manage add-ons" button) to see whether one or more of them might be the culprit.

Update 2/3/2007: In the course of the past several days, I've had to re-enable several of the IE7 add-ons that I'd disabled to get various websites to work properly. Unfortunately, this has caused IE7 to mostly revert to the slow startup behavior, even though the majority of the add-ons that I had disabled remain disabled.

I've updated the title of this post to read "Partial Fix" instead of "Fix", as it seems just disabling all available IE7 add-ons to address the slow startup problem isn't a very good solution (since many web pages need one or more add-ons to work properly).

This issue is enough to make me hesitant to recommend upgrading to IE7 for any power users running Windows XP who hasn't yet upgraded from IE6. I say "power users" here because typical users are probably less likely be bothered by the extra startup delay -- it could easily be attributed to a part of the load time for the user's homepage if they don't attempt to immediately navigate to a different page, as I was doing when I first ran across this issue. And power users are likely to be already running Firefox or another alternative browser, and thus don't need to install IE7 to gain access to features like tabbed browsing and PNG alpha transparency support.