Wednesday, May 09, 2007

I'm a bit of a toolhound, both of the physical variety (like screwdrivers, bitstops, routers and mitre saws) and of the more ethereal (clipboard loggers and macro recorders). Tools make the fun things even more fun, and the wretched things not quite so onerous.

And one really onerous thing for me is backups. They're a pain, and it seems it's always impossible to find what you need when you need it. I've got a pile of QIC-60 and QIC-80 tapes that there's no way I could restore even if I wanted to (note to self, burn them in the next trash fire...)

Anyway, I went on a search some time ago for a decent backup utility. Something free, or close, that was flexible enough for what I needed, simple enough that I'd actually use it, capable enough to make it worthwhile and fast enough to not get in the way.

I believe my search ended with FileBackPC.

It's a nifty little app that does a nice job of the "copy to a floppy" type of backup. Well, ok, maybe not a floppy these days, but plug in a 500gb USB2.0 removeable harddrive and this app is fantastic.

The good points:

  • It backs up specified directories, with wildcards and all sorts of file filters
  • It can compress and retain a specified number of "previous versions"
  • You can specify sets of folders in "jobs" that can be run independently
  • You can set jobs to automatically run, either on a schedule or on "an event" (like plugging in that USB harddrive!)
  • It can reconnect to other machines on your network and back up files from the (great for small home offices with a server and several workstations or laptops).
  • It can even run batch files and scripts to automatically execute processes before backing up the results of those processes. For instance, I have an item that uses the windows "backup" utility to create a single backup file of the critical system components and my Exchange server data, then I backup that file automatically using FileBackPC.

Off hand, I can't even think of any bad points, other than it's not an open source project.

I think my favorite feature is the backup on an event. I set several jobs up to execute when the X: drive comes online (that's my backup USB drive). So literally all I do now is plug in the USB drive, wait till it finishes the backup, and then unplug it and file it safely away. Slick. And it's got a nice reporting facility too, that makes it easy to see if there were any problems (open files, read errors, whatever).

And, since it's a copy style backup, it's blindingly easy to find that backup file when you need it. Get a couple of USB drives and be doubly safe.

Backup utilities definitely aren't my favorite things, but they're something almost everyone with a PC needs. I know this has probably sounded more like an ad than anything else, but it's not. I'm not getting paid by the FileBack people. This is one of those utilities that I've found so handy, useful and easy to work with, that I just felt like mentioning it.

posted on Wednesday, May 09, 2007 9:21:51 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Tuesday, May 08, 2007

Happened upon a pretty nifty map today.

Here's a sample:

DNSMap

Basically, it's a regular world map with all the DNS country codes imprinted on it.

Makes a decent wallpaper too, as long as you have a pretty big widescreen monitor.

posted on Tuesday, May 08, 2007 8:31:00 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Monday, May 07, 2007

We're switching a major project over to SQL Express 2005 from MSDE 2000, and in the process of doing so, I came to several discoveries.

  • MS Isn't releasing any MSI Merge Modules for 2005. Why? No idea. Appearently, that great MSI technology that they insist everyone else use isn't good enough for their own products.
  • With InstallShield anyway, there is no prerequisite support for Express 2005 in IS 11.5 and earlier. You must move to InstallShield 12. Joy.

I did, however find this article about sqlexpr32 command line switches which should allow you to perform the Express install from within a normal MSI install by just running the exe with the proper switches. Not ideal, but it's something.

posted on Monday, May 07, 2007 4:11:24 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Saturday, May 05, 2007

I've played a bit now with the .NET configuration model and while I can certainly see some elements in there to like, it seems to me that it falls short in a number of different ways.

First off, it doesn't really have any concept of "multi-level configuration." In fact, it's basically a single level XML file (granted, you could create a hierarchical organization within that single xml file, but there's other issues with that). .NET does help a bit with the concept of a machine config file, but from what I can tell that's about as far as it goes.

Second, the default behavior is to locate the application config file in the same path as the application itself. That's great if your user is running as administrator, but not so great in more locked-down situations where users do not have full admin rights. In those cases, configuration that's writable needs to be stored somewhere within the user's profile directory structure. This is just going to get worse with Vista, too.

Ok, sounds good but what, you may be asking, is a multi-level configuration scheme, and why would I want one? Almost every app I've ever worked on, short of the trivial utilities I've built, has required this sort of configuration scheme (or at the very least greatly benefited from having it). It almost always follows along this line:

  • Administrator specified User specific configuration (rarely used, the user cannot change this configuration)
  • User specific configuration (that the user can change dynamically)
  • Group specific configuration (typically set by a system administrator or group admin and read only to users)
  • Machine specific configuration (typically set by a system admin, and rarely used, read only to users)
  • Application global configuration (typically set by the system admin, read only to users)
  • OEM defaults (typically set by the app developers to provide default config values, generally readonly by everyone except the developers)

At each level, the system provides for an essentially unlimited number of name value pairs that can be cordoned off into groups (or sections as they used to be called in INI files). Some may argue that a section-name-value system like this is too limiting and you should always accomodate full hierarchical structures, but I've found the extra functionality rarely necessary.

Of course, the type of value (string, int, date, etc) for a particular setting is defined within the application, but value types might also be defined as OEM default settings. Should sysadmins really be able to change setting X from a string to a date? I'd imagine not usually.

The trick and the real beauty of the system is in the way that setting values are resolved. The resolution logic basically says that if the app can find a setting at a higher level in the hierarchy, it uses that value. Otherwise it searches down the hierarchy till it either finds a value, or till it drops to the OEM defaults. If no setting is specified at the OEM level, the system defaults to blanks, or 0's depending on the data type.

So, for instance, the code might ask for the setting "AskOnExit" from the "Prompts" section. The config handler needs to look first at the "level of most significance" which, in the above list of levels, would be the Administrator specified user specific settings (ie those settings that are set on a per user basis, but that the user himself doesn't have the authority to change.

If the setting isn't found there, the code continues down the hierarchy, looking at each level in turn until eventually in run through them all and returns the default or a blank or 0.

And, of course, you also have to provide a means to retrieving and writing a setting at a specific level in the hierarchy, for those settings that are always application level or machine level or what not.

Obviously, such a scheme requires a little more work up front, but the configuration flexibility (especially when you're talking about major, multi user systems with lots of configuration options, typically off-the-shelf, reseller-friendly applications like accounting systems or CRM packages), is a huge selling point to admins and users alike.

Why, then does configuration handling in .NET seem so archaically primitive?

Could you roll all these levels into that singular .config file? Sure, when where would you put it? In the Application path? No, users won't typically have write rights there. Under the user's Application Data folder in the Profile? No, can't put app wide settings somewhere that only a single user can access it. How about that machine config file. Again, not writable by typical users.

It's funny that Windows already has a rights system that is very stable, quite flexible and easy to work with, both manually and from within code and yet it often goes completely unused by larger apps. I'm talking, of course, of the file system.

These days, though, web apps are de rigueur and you can't go assigning file system rights to web users. There's no way that would fly with most web developers (you weren't really thinking of something like that, right?). So, roll it up into a simple table, with a getSetting and a setSetting stored procedure to simplify the coding. With proper indexing, and a little intelligent caching, it'll be every big as fast as using the .NET configuration functions, and whole lot more flexible.

Long story short. If your sideline utility needs to save a few settings, use the .NET configuration. It's fast, relatively easy and convenient. But for just about everything else, take a little time and do it right.

Your users and their sysadmins will thank you.

posted on Saturday, May 05, 2007 7:18:08 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Thursday, May 03, 2007

I was looking for a particular reference book today and stumbled across a little book I hadn't looked at in ages. It was a favorite way back and it's still pretty funny now.

The book is the "Book of Minims" by Tom Weller. It's appearently out of print now, but Mr. Weller has made the whole thing available online here.

In case you're wondering, Minims are the opposite of Maxims, basically, sayings that sound like they have a deep meaning but in reality are so obvious or specific as to be useless.

One of my favorites: "Money is it's own reward".

Good stuff.

posted on Thursday, May 03, 2007 4:04:21 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Wednesday, May 02, 2007

I've used several different media players over time, but since stumbling across J River's Media Center, I haven't seen the need to use anything else.

It has an fast and flexible database, and it can tag multiple tracks very efficiently. Plus it looks great!

MediaCenter

I really only have two negatives about it.

  • I still can't get it to work right with my Tivo. When it DID work, it was great. But it quit at one point about a year ago, and I've never been able to get it to work since. Galleon, on the other hand, works great with Tivo, and has since I first installed it.
  • The Next and Previous track keys on my MS Comfort Curve keyboard don't actually go to the next and previous tracks like they should when MC is minimized. The volume and pause keys work perfect though.

Ok, scratch that last negative. I posted a question to the MC forums and got some very helpful responses, which led me to the Media Center Wiki with this post about the command line options. Just use:

MC12.EXE /COMMAND /NEXT

or

MC12.EXE /COMMAND /PREVIOUS

and Viola! Next and previous work just fine, no matter whether MC is minimized to the systray or not.

Now, maybe someone has an idea about getting it to work with Tivo again. Anyone?

posted on Wednesday, May 02, 2007 4:24:42 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 

New to the Excel 2007 object model is the Comments property of the Name object.

The Name object itself has been around since Excel 2000 and possibly before, but the Comment property is a handy new development.

I like Comment properties personally. Any object model representing items such as this would benefit from a property where you can stash whatever info is pertinent. Take, for instance, the venerable tag property of VB controls. Of course, these things can be misused, but then, is there anything that can't be misused in the wrong hands?

Anyway, comments like this are great, but they also represent potentially sensitive information that you might not want to reveal to third parties, especially in this case, because the comments themselves are persisted to the workbook. Excel 2007 has a nifty Document Inspector you can use to remove these comments, which is nice. However, when you run the inspector, it simply says that there were comments detected, would you like to delete them? Nice, but not terribly informative.

Retrieving the comments on a Name is not too hard.

cmt = ExcelApp.ActiveWorkbook.Names(1).Comment                                                   

But, when you go to clear the comment:

ExcelApp.ActiveWorkbook.Names(1).Comment = ""

Nothing happens...

Excel, and Word, and PowerPoint for that matter, all seem to be afflicted by this particular "a blank string doesn't really count" malady in one way or another. Setting the Creation Date, for example, or the Username or UserInitials all seem to have similar problems with being set to a null string.

The solution, though not ideal, isn't too terribly bad either, I suppose.

ExcelApp.ActiveWorkbook.Names(1).Comment = " "

Yes, that's right, just set it to a space, instead of a null string.

It'd be interesting to see the code responsible for implementing these properties, just to see how it could be coded such that a null string is ignored like this. It seems like it just couldn't have been intentional.

And just for the record, passing an actual null char doesn't work either, so it doesn't appear to be a "C string/BSTR related" issue.

posted on Wednesday, May 02, 2007 11:36:44 AM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Sunday, April 29, 2007

If you've ever looking closely at Windows applications, you know that Windows Version Numbers are composed of 4 parts:

  • Major version
  • Minor version number
  • Revision number
  • Build number

So a version of 4.8.3.9888 would typically mean Major version 4, Minor version 8, Revision 3, Build 9888.

If you've ever looked at VB's Project properties box, though, you've probably noticed the disconnect.

ProjProps

Obviously, VB directly supports the Major and Minor, and appearently, the Revision number.

But, build a VB6 app with unique values in for each number and then view the app's properties via Windows Explorer:

AppProps

In this particular app's case, Major and Minor are 0, and Revision was set to 49. However, according to the Windows Property panel, the Build number is 49. VB internally makes the Build number what you enter as the Revision number in the VB project property UI.

Now, whether this was just a typo on the part of the VB developers or an intentional "feature", I can't say. But it definitely can cause confusion and make it difficult to identify versions of your app out in the field. Then there's the constant explaining of why your app's revision always seems to be 0, but other applications have something there.

In a previous post on VB and resources, I mention the Microsoft Resource Compiler, a utility that can compile resource files into RES files, which can then be compiled into your application by VB.

This combination works wonders if all you want to do is embed icons, bitmaps, strings or arbitrary files into the resources of your app.

And, if you look at the RC documentation, you'd see info on VERSIONINFO statement that is used to define a Version Info Resource.

So, it would stand to reason that if you created a resource file, say like this:

VersionInfoTest.rc

1 VERSIONINFO
FILEVERSION 1,2,3,4
PRODUCTVERSION 1,2,3,4
FILEOS 0x4
FILETYPE 0x1 //// 2 for dll, 1 for exe
{
BLOCK "StringFileInfo"
{
BLOCK "000004b0"
{
VALUE "CompanyName", "MyCompany"
VALUE "ProductName", "MyProduct"
VALUE "FileDescription", "MyFileDesc"
VALUE "LegalCopyright", "MyLegalCopyright"
VALUE "LegalTrademarks", "MyLegalTrademark"
VALUE "OriginalFilename", "MyOriginalFilename"
VALUE "ProductVersion", "1.2.3.4"
VALUE "FileVersion", "1.2.3.4"
VALUE "Comments", "MyComments"
VALUE "InternalName", "MyInternalName"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0000 0x04B0
}
}

Then, all you should have to do is compile the RC file with RC.EXE, load up VB, add the resulting RES file to your project and you'd be done.

Unfortunately, the path to enlightnment is never straightforward, and neither is the process of getting a proper version number into a VB6 executable.

The problem is that VB post-processes the compiled executable in order to put the version information from the Project properties screen into the VERSIONINFO resource. This means that the nice, correct VERSIONINFO resource that you just compiled into the executable get's stomped on by whatever you happen to have in the Project Properties dialog, and that dialog will always reset the Windows Revision number to 0, and use the VB Revision number as the Windows Build number.

What you have to do is post-post-process your exe and put the correct VERSIONINFO resource back in after VB is completely finished with the file.

And the easiest way to do that is with a handy free utility called Resource Hacker. This utility allows you to easily open, view, and even extract all the resources in any EXE or DLL. If you want to just pull all the icons out of a file's resources, there are definitely better ways. But if you really want to poke around the resources in a file, ResHacker is perfect. Plus, it's got a very handy, if not a little arcane, command line interface that will allow you to automate much of the process via MAKE files or batch scripts.

Make sure the RESHACKER.EXE is on your path, then run:

reshacker -addoverwrite "yourexe.exe", "yourexe.exe", "yourexe-VersionInfo.res", versioninfo, 1 , 1033

I'm assuming your compiled application is called yourexe.exe, and that you've compiled an RC file with a VERSIONINFO resource in it to the file yourexe-VersionInfo.res.

Resource hacker will dutifully wipe out the VB created VERSIONINFO resource and replace it with the one compiled from your RC script.

One important note, though. ResHacker will not merge a single resource, and all of the version information is considered a single resource. That means that you need to specify all the pertinent version info properties in your RC file, because everything specified via the VB Project Properties dialog will get replaced.

"But", you say, "the version numbers themselves appear to be replicated 4 times in the RC file! I'm a lazy programmer and the thought of updating 4 copies of the version number just seems, well, wrong."

And you'd be right.

Fortunately, there is a way to convince RC.EXE to allow you to specify the version number for your app only once. However, doing so is, like the concept of using resources in a VB app, more complicated that you would at first imagine.

I'll discuss that in my next post.

posted on Sunday, April 29, 2007 5:58:03 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Monday, April 23, 2007

I haven't played with Terragen much yet, but I've been thoroughly impressed by some of the work various people are doing with it. If you've never seen Terragen artwork, well, wow! It can generate some of the most photo-realistic scenes I've seen. And it's free. Granted, there's newer, more powerful programs out there now, but in good hands, Terragen can create some amazing stuff (and in the wrong hands, yikes!).

Anyway, check out any one of these sites. They're some of the better ones I've stumbled across:

And, speaking of wrong hands, here's my first shot at a Terragen scene. I call it Grand Pass.

posted on Monday, April 23, 2007 8:04:19 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions;