Wednesday, September 30, 2009

Finally Figured Out My Vista Problem

Wow I have found the solution to a problem that I have had intermittently since installing Vista 64. Sometimes after upgrading my computer, my VPN connection would become inaccessible and my Ghost service would quit working (see A Painful Lesson and Fragile Vista). Tonight, I got bit by this again after installing a gigabit network card in my computer.

A natural thing to do when you get errors is to go look in the Windows event log to see if there are any messages. But when I tried to open the Event Viewer, I got this message:

Event log service is unavailable. Verify that the service is running.



Well, in fact, the Windows Event Log service was not running, and attempts to start it gave the error:

Error 4201: The instance name passed was not recognized as valid by a WMI data provider

So, I did some Binging and found a tip to check the permissions on the C:\Windows\System32\LogFiles\WMI\RtBackup folder. It didn't look good. They didn't at all match the permissions on its WMI parent folder. What it had was just my user name, and what the parent had were several system accounts.



I removed my account and added the system accounts to match the parent folder.



After rebooting, everything was back to normal again. I have no idea why certain installs mess up the permissions. Hopefully, this will be useful info for someone experiencing this problem.

Tuesday, September 29, 2009

Automating Excel from C# Pt. 1

Recently, I have wanted to convert Excel spreadsheets to CSV files for further processing. Excel provides a COM Automation model for using its functionality from 3rd party applications.

One of the things about COM Automation is that if you don't close all of the handles you are using in the application being automated, orphaned instances can be left running and they will never quit unless you use Task Manager to kill them or reboot the computer.

So, the automating application needs to be very careful to get rid of everything it is referencing in the automated process to allow it to shut down. The problem is, .NET is a garbage-collected environment, and this means that objects are destroyed, or released, whenever the framework decides that memory should be freed up. Unlike C++ destructors, which are always called immediately when a variable goes out of scope or is delete'd, .NET finalizers are called only when the framework wants to free memory. Exactly when that happens cannot be known with certainty. Oh, objects will be released eventually, but not necessarily when the application might like.

Therefore, the .NET framework provides the IDisposable interface, which allows the non-.NET allocated portions of an object to be immediately freed without the .NET portion being freed. This is what we need to use when automating COM so that COM handles are released in a controlled, dependable, and timely fashion.

In the next part to this series, I will talk about the IDisposable interface.

Tuesday, September 22, 2009

Multiple vs. Single Exit Points

Recently in one of the newsgroups a side discussion came up about the benefits of a single exit point from a function. There was a time when I followed that notion very closely. However, I found that the functions ended up having more nesting and other logic to "jump over" code paths once the return value was determined. In recent years I have found myself pretty much ignoring that idea completely.

Here is an example of some actual code I have somewhere. I have removed the null-checks, comments, and other exception throws to get down to the core of the logic.

In this snippet you can see that once the return value is determined, it immediately returns it.

    1 private int CompareTokens(CommandLineParser commandLineParser)
    2 {
    3     var n = System.Math.Min(this.tokens.Length, commandLineParser.tokens.Length);
    4 
    5     for (var i = 0; i < n; i++)
    6     {
    7         var result = this.tokens[i].CompareTo(commandLineParser.tokens[i]);
    8         if (result != 0)
    9         {
   10             return result;
   11         }
   12     }
   13 
   14     if (this.tokens.Length < commandLineParser.tokens.Length)
   15     {
   16         return -1;
   17     }
   18 
   19     if (this.tokens.Length > commandLineParser.tokens.Length)
   20     {
   21         return +1;
   22     }
   23 
   24     return 0;
   25 }

In the next snippet I have refactored the original routine into a single exit point. Note the required variable for the return value in line 3, the break at line 12 and the extra logic at lines 16 and 22 required to jump over the other code paths. Somewhere I know I have a more severe example. I will look for it. In fact, I remember it is an old one that used to have one exit point that I have since converted to multiple.

    1 private int CompareTokens(CommandLineParser commandLineParser)
    2 {
    3     var result = 0;
    4 
    5     var n = System.Math.Min(this.tokens.Length, commandLineParser.tokens.Length);
    6 
    7     for (var i = 0; i < n; i++)
    8     {
    9         result = this.tokens[i].CompareTo(commandLineParser.tokens[i]);
   10         if (result != 0)
   11         {
   12             break;
   13         }
   14     }
   15 
   16     if (result == 0)
   17     {
   18         if (this.tokens.Length < commandLineParser.tokens.Length)
   19         {
   20             result = -1;
   21         }
   22         else if (this.tokens.Length > commandLineParser.tokens.Length)
   23         {
   24             result = +1;
   25         }
   26     }
   27 
   28     return result;
   29 }

So, what's your opinion? I suppose some of you have seen coding horrors where multiple exit points have been abused.

Saturday, September 19, 2009

Consolas Font in Code Snippet Windows

I have the Consolas font issue fixed for my code snippet windows. If you have the Consolas font installed, the snippet windows should now show in that font. I haven't figured out the line ending problem yet, though.

    1 using System;
    2 using System.Collections.Generic;
    3 using System.Linq;
    4 using System.Windows.Forms;
    5 
    6 namespace Test1
    7 {
    8     static class Program
    9     {
   10         /// <summary>
   11         /// The main entry point for the application.
   12         /// </summary>
   13         [STAThread]
   14         static void Main()
   15         {
   16             Application.EnableVisualStyles();
   17             Application.SetCompatibleTextRenderingDefault(false);
   18             Application.Run(new Form1());
   19         }
   20     }
   21 }

The issue with the font was that the  <pre>  tags for the coloring on the fragments weren't inheriting the  font-family:consolas  that was specified in the style for the  <div>. Modifying the Copy Source As HTML utility settings remedied that.

So now my settings for CopyAsHTML are:




Friday, September 18, 2009

Posting Code Snippets to Blogger

I want to be able to post code snippets and I found a little utility that integrates with Visual Studio 2008 called CopySourceAsHtml. This utility lets you select source code in a code window and copy it verbatim to the clipboard, which can then be pasted into the blog.

In this shot, I selected some source code, and right-clicked. I then chose Copy As HTML...



When you do this, the utility's dialog box appears allowing you to choose options. I have set options on two of the tabs.




On the File Style tab, I have added some more style settings for the  <div>  that it creates for the snippet.  The  overflow:auto  setting will add scroll bars as needed, the  white-space:nowrap  setting will turn off word-wrapping, the  height:500px  setting sets the box height to 500 pixels, and the  border:inset silver  sets the box's border style to inset with silver color.

When you press OK the HTML is placed on the clipboard and is ready to paste into the blog post.



For this to work, I also had to make a change to my Blogger template, otherwise the word-wrapping setting was ignored and was always on.



This is the final result:

  296                 else if (path.EndsWith(":"))
  297                 {
  298                     path += @".\";
  299                 }
  300                 else if (!path.EndsWith(@"\"))
  301                 {
  302                     path += @"\";
  303                 }
  304 
  305                 path = System.IO.Path.GetFullPath(path);
  306                 if (path == null)
  307                 {
  308                     throw new System.ApplicationException("GetFullPath() returned NULL unexpectedly.");
  309                 }
  310 
  311                 if (fileType == FileTypes.File)
  312                 {
  313                     // Special cases for when x.txt is truly a FileInfo, this code
  314                     // must come after the GetFullPath() call above:
  315                     //      c:\x.txt\
  316                     //          Path: c:\x.txt\
  317                     //          File: 
  318                     //      c:\x.txt\.
  319                     //          Path: c:\x.txt\
  320                     //          File: .
  321                     //      c:\x.txt\.\.\.\\\.\.\..\x.txt\\\\\.\.\.\..\x.txt\.\
  322                     //          Path: c:\x.txt\
  323                     //          File: 
  324                     //      c:\x.txt\.\.\.\\\.\.\..\x.txt\\\\\.\.\.\..\x.txt\.\.
  325                     //          Path: c:\x.txt\
  326                     //          File: .
  327                     //      c:\x.txt\.\.\.\\\.\.\..\x.txt\\\\\.\.\.\..\x.txt\.\.\\\
  328                     //          Path: c:\x.txt\
  329                     //          File: .
  330                     if (((fileName == string.Empty) || (fileName == ".")) &&
  331                         path.EndsWith(@"\"))
  332                     {
  333                         fileSpec = path.Substring(0, path.Length - 1);  // Make the new filespec be the earlier resolved Path minus the trailing \
  334                         path = System.IO.Path.GetDirectoryName(fileSpec);
  335 
  336                         if (path == null)
  337                         {

One thing I note is that you cannot easily copy text out of this window, because it doesn't have normal line ends. I am looking into how to remedy that. I do plan to post downloadable code when I post snippets. The other thing is that this is displaying with a Courier font, rather than Consolas as in Visual Studio.

Wednesday, September 16, 2009

I Have Perforce Source Control Now

I had been wanting to get source control for my home hobby projects for the last couple of months. I am most familiar with Visual SourceSafe since I first used it 14 years ago (We use Team System now at work). I've been following eBay auctions to try to get VSS cheap, like say $50, but I hadn't had any takers for this price. Thankfully, I gave up on the stupid VSS idea, and after some research decided to give Perforce a try. It is free for up to two users, which is exactly the price I wanted to pay. It also integrates with Visual Studio 2008. Of all of the components on their download page, I only downloaded and installed these three 64-bit ones:
  • P4D: Server
  • P4V: Visual Client
  • P4SCC: SCC Plug-in

The installs went smoothly. It wanted me to reboot, which I did. After rebooting, I went into the Perforce Visual Client P4V utility, then on the Tools / Administration menu I set myself up as a superuser. I accepted all of the defaults for everything, including the Workspace, which ended up being a problem later. I fired up Visual Studio and opened a solution that I wanted to add to source control. After opening the solution, I enabled the Source Control toolbar and selected Change Source Control.



This is where I ran into the only problem I had. When I tried to bind the solution to source control I got this error:

Path 'd:\Source\XLStoCSV/*' is not under client's root 'C:/Users/Alan/Perforce/EMACHINEST6520_1666/Alan_eMachinesT6520'.



I have a root folder where all of my programming projects are and figured that the problem was that I needed to make this be the root in source control. It was a little unclear how to do that though, but after some snooping around in P4V I found that I could edit the Workspace.



Earlier, I had accepted all of the defaults when setting Perforce up. I should have specified d:\source for my root.



After making this change, I went back to Visual Studio and retried binding the solution to source control. This time it worked just fine.



One more dialog came up to ask what to do if the files were already in source control. They weren't, of course, and I just took the default.



At this point, the icons on the project items were marked with the familiar yellow plus signs and could be checked in. Here's a screenshot of everything checked in. Elapsed time from download: 20 min. Very cool!

Saturday, September 12, 2009

StyleCop 4.3.2.1

Just noticed tonight that StyleCop 4.3.2.1 was released a month ago. Bug fixes are always welcome. Plus they've added the ability to suppress warnings on a per-unit basis, like FxCop.

Wednesday, September 9, 2009

Error Updating Norton Ghost

Since I hadn't ever updated Norton Ghost since I originally installed it, I thought it would be a good idea to see if there were any updates for it. Norton Ghost comes with the Norton Live Update utility, which I ran. It told me that there were indeed updates for it, so I told it to go ahead and update it. After the updater ran for awhile, I eventually got this error:



Fatal error during installation.

Nice. How informative. At this point, Ghost is UNINSTALLED, and needs to be reinstalled from the media. You would think that with all the ridicule vendors get from The Daily WTF and similar sites, the developers would know better than to give a message like this. I tried installing several times without any luck.

One day, by accident, I had forgotten and left the original install CD in the drive and ran Live Update again. I noticed that the updater was spinning up the CD drive and reading from it. This time, the updater completed successfully.

Lesson learned: The Norton Ghost updater wants the original media in the drive during the upgrade.