Author Archives: admin

The Running instance of Windows Media Player

13
Filed under Media, MP3s, Office, Utilities

I’m finishing up my little Signature Enhancement Utility for Outlook and had finally gotten the Media Center 12 “Currently listening to” functions operational (This is just a minor feature I’ve seen popular on website blogs and forums, where the tag line contains not only the author’s name but what they are currently listening to, if anything, nifty and fun, but not in the least practical).

I figured I’d go ahead and try to support Windows Media Player 11 (and hopefully earlier versions) as well.

Basically, the idea is to grab a reference to the running instance, interrogate it as to the “playing” state and, if it’s playing or paused, retrieve the name, album, artist, etc info on the playing track and make it available as replaceable fields in the signature.

With Media Center, it was almost trivial:

Set omc = GetObject(, "MediaJukebox Application")
If not omc is nothing Then
   '---- it's running
   ' if it's not running, they can't be playing any music
   With omc
   Select Case .GetPlayback.State
      Case PLAYSTATE_PAUSED, PLAYSTATE_PLAYING
      '---- Media center info is available
      ps = .GetCurPlaylist.Position
      CurTrackTitle$ = .GetCurPlaylist.GetFile(ps).Name
      etc...

Obviously, if the GETOBJECT fails to return anything, Media Center isn’t currently running so the user can’t be listening to anything.

Three hours of Googling later, plus tons of experimentation and I’m not even an inch closer to getting this working for Media Player.

Using ROTView(the Running Object Table viewer, comes with various installations of Visual Studio), it does appear that WMP registers “something” with the ROT, which I’d think would be accessible by VB’s GetObject().

Alas, “Windows Media Player”, “WindowsMediaPlayer”, “MediaPlayer.MediaPlayer”, and on and on, all came up empty.

I scoured the registry for anything that even remotely looked like the moniker of a WMP registration with the ROT and everything I tried also came up empty. I’m sure it’s another case of knowing the magic password, but so far, it appears to be a tad more involved than Speak, friend, and enter.

So, for now, looks like I’ll have to rely on the FunPack for support of a limited set of attributes of the currently playing song in WMP. Apparently, for ITunes, you can use this plugin to accomplish the same thing, though I don’t use ITunes and probably won’t bother with testing that.

If anyone’s ever had any success with accessing the running instance of Media Player, I’d love to hear about it!

Error Handling Strategies

0
Filed under Software Architecture, VB Feng Shui

I once wrote an article about error handling in VB6 for Visual Basic Programmer’s Journal (Sept 2001, jeez that seems like a long time ago! {edit} and it would appear that that link is long since dead 🙁 ). It was born out of the need for a comprehensive framework for handling errors in an app I was working on at the time.

Since then, I’ve expanded the framework several times and it’s grown into something quite handy. Once I get it cleaned up a bit for public consumption, I’ll make the new and improved version available.

I’ve since been looking at the .NET error handler framework, and while it’s certainly much improved over the VB6 days, it still leaves a lot to be desired.

At the very core of handling errors is the division of error types into two distinct classes:

  • Expected Errors
  • Unexpected Errors

In a perfect world, every possible error is an Expected Error and there are no errors that can occur within your program that the code isn’t written to intelligently deal with.

At the other end of the spectrum, is, of course, where most textbook and magazine article sample code lies; where every error is an Unexpected Error that will crash the program.

Unfortunately, real world limitations on time, money, manpower, etc tend to force all code somewhere south of Nirvana.

The .NET fanclub used to decry VB’s on error goto as antiquated technology, and trumpeted try catch as the silver bullet of the day. And I suppose:

On Error Goto Catch
Try:
...code to try...
Goto EndTry
Catch:
...code to handle any error in the try block...
EndTry:

is quite different from

Try
...code to try... 
Catch ex as exception 
...code to handle any error in the try block... 
End Try

as long as you’re only looking at their checksums<g>.

Sure .NET incorporates a wealth of metadata about the exception. The module, function, line number, etc are all available directly while handling the error. But something’s missing.

Oh, yeah, What about those Unexpected Errors?

.NET does have the Exception Handling Application Block and it looks very promising, although it also looks very involved. And do you really want to be able to configure exception handling policies via config files? I mean, beyond indicating the level of logging you want (verbose, medium, low, off), and the email address to send exception report to (unluckysupporttech@mycompany.com), I’m having a hard time coming up with anything else I’ve ever needed to dynamically configure in my apps for exception handling. But, I won’t say it couldn’t be useful.

In the end, I suppose the thing that bothers me most about the EHAB, and the whole structured exception movement in general, is that it really does nothing to address the Unexpected Errors in an application. You still have to wrap your entire procedure in a TRY block in order to be sure that you catch any exception raised in that procedure. Otherwise, the exception is simply propagated up the call stack to the first point that is covered by an exception handler. The good news about .NET, though, is that at least, in those cases, you can still retrieve a call stack back to the real source of the exception and log it. With VB6, no such luck without some sort of framework.

My other issue is that Try Catch style exception handling forces the declaration of how you intend on handling errors to the END of the function you’re looking at. In this age of declarative programming and metadata-attributed interfaces, that just seems so…yesterday.

Take my above comparison of try catch and on error. What actually happens to the error is stated down at the end of the procedure in both styles. Now. I can understand that approach if you have code dedicated to handling specific errors, but then, those are Expected Errors. For the Unexpected Errors, I’d rather know, declared right up front, how the prodecure intends to handle them.

That was the impetus of my article way back when:

  • Provide a framework that could provide a call stack that VB6 was lacking
  • Provide a means of clearly declaring how the procedure intends on handling Unexpected Errors.

Compare a typical Try Catch structure:

Public Sub Test()
   Try                                          
   .....Lots and lots and lots of code....
   Catch Ex as Exception
   ....how to handle specific exceptions, plus how to handle general exceptions...
   End Try
End Sub

with a prologue style declaration like I use in my error handling framework for VB6:

Public Sub Test()
'############### ERR HANDLING #############
Dim Err As CErr: Set Err = New CErr: On Error GoTo Problem
Problem:
Select Case Err.Handle(EHF_PRESENT or EHF_ALLOWRETRY, MODULE, "Test")
Case EHE_NONE: Case EHE_RETRY: Resume: Case EHE_PASS: Resume Next: Case EHE_RESET: Resume Problem
End Select
'##########################################
   .....Lots and lots and lots of code....
End Sub

The code states right up front how unexpected errors are handled (in this case, EHF_PRESENT or EHF_ALLOWRETRY indicates that the user will be shown a dialog and allowed to retry the operation). There’s a bit more verbiage here because of the requirements of VB6, but that’s not the point.

Personally, I’d prefer it if every routine in .NET could be (or maybe even had to be) attributed as to how unexpected errors are to be handled. Those that need to show a dialog would do so based on one or more “predefined” dialogs that depended on where in the app the error was thrown.

And for those apps that you never want to show an error dialog, you could instead indicated that any unexpected errors should be logged to the Event Log (or somewhere else) and then press on as best as possible.

Unlike the implications in so many magazine articles, error handling is hard. Proper error handling is like a prostate exam; you know you have to do it, but you’d really rather not bother.

InstallShield Upgrade Joyosity

7
Filed under Installations, Software Architecture

I’ve been hunting down an issue with an InstallShield Installation for almost a week now.

Very strange. I have a new installation that is a BASIC MSI install (meaning it contains no funky InstallScript at all, and is this fully MSI compliant).

It is intended to upgrade several previous installations, one of which is also a BASIC MSI, but the others are all InstallScript MSIs.

When I first started testing the upgrade process, I did the install of the old version, followed by an install of the new version. When I went to ADD REMOVE PROGRAMS, the new was there, but the old version was as well. The upgrade didn’t work.

Grrr.

So I start digging. Eventually, I determined that the old version was actually being uninstalled (I paused the install midstream and sure enough, all the old files are one point are completely removed). However, for some reason, the entry in the Add Remove Programs list was not being removed.

More digging.

So I reset my test, installed the old version and at Macrovision’s request, I searched the reg and found a key here:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{F1C8EEFE-8019-44AB-8AA9-D6F13E3BFAF0}]

that contained all the info about the old installation.

There’s a value called NOREMOVE set to 1. Hmm, that sounds suspicious. So I set it to 0 and install my new version.

No joy, the old version is still listed in ARP. However, when I went back to the registry to check that key, it was gone! What the hell!? Ok, the entry in ARP must be coming from somewhere else. A few reg searches later turned up this key:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\InstallShield_{F1C8EEFE-8019-44AB-8AA9-D6F13E3BFAF0}]

Notice that the GUID there is the same as the other GUID, but this one has “InstallShield_” at the front of the key name.

Delete THAT key, and suddenly, the ARP entry is completely gone.

It would appear that upgrading an InstallScript based install with a BASIC MSI install unintentionally leaves behind a key that it shouldn’t. Some searching the KBs with more specific keywords turned up exactly that.

An InstallScript based install created two entries in the Uninstall registry key, but one is ‘hidden’ from the ARP list view.

A Basic MSI install only creates one key. And if you upgrade an InstallScript based installation with a Basic MSI installation, that second key (the visible one) won’t get removed properly.

You have to add an entry to the RemoveRegistry table in the MSI file and connect it to a component that will be installed by your new installation.

Didn’t table-driven programming constructs die back in ’91 with Magic. No, wait. Ack, they’re still alive?!

Well, tried it then and hated it, still hate it today. To each his own.

SQL and Portability

0
Filed under Software Architecture, SQL

There’s an interesting discussion going on at SQL Server Central about applications and database portability.

The question thrown out was “How valuable is portability to your application”.

And by portability, they’re referring to portability across different database backends. Can your app run on Oracle, SQL Server, MySQL, etc, or do you just lock down to a specific vendor, and sell to your apps strengths and not DB portability?

It’s an interesting question and from the responses so far, it would seem that DB portability is a 4 letter word. But I think many of the responses are a little short sighted or limited to the DBA/developer perspective.

There is one comment saying something along the lines that an app this company purchased was DB agnostic and was found to contain no where clauses. Now that may have been an exageration to make a point, but I’d argue that an app like that was poorly architected from the outset. The fact that it performs poorly would seem to have less to do with being DB agnostic and more to do with just poor coding/architecture. My guess is, if you looked past the DB code in that app, you’d find a lot more to dislike as well.

The bottom line in any business is 1) The customer is always right and 2) you have to sell the product you have in order to make the product you want to sell.

Now, as to part 1, I’m not saying you can’t educate the customer, but in the end, if they really want Oracle as their backend, there may be some business reasons for that that you can’t sell around. And if the IT shop of that customer is centered on Oracle, good luck going in with a SQL Server based app.

I suppose it’d be nice if every shop was an IBM sized house that could hire DBAs specifically to design and support the backends for every reasonable DB, but most shops don’t have those kinds of resources.

In small shops, it’s all about leveraging code as much as possible.

VB and Resource Files (Part 3)

1
Filed under Resource Files, Utilities, VB Feng Shui

In case you’ve missed the first 2 posts in this series, I’m discussing the concept of using Resouce files with Visual Basic 6.

In the first part, I talked about how to compile arbitrary information into a resource file and reference it from VB.

In Part 2, I discussed a technique for compiling a VersionInfo resource and writing it into your VB executable, thus replacing the incomplete VB provided VersionInfo resource.

In this installment, I wanted to share a little trick for defining the elements of the “Version number” in a resource (RC) file such that you only have to enter the version number once.

If you recall, I presented a sample RC file the last time, looking like this:

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
}
}

If you’ll notice, there is one thing about this script that no lazy programmer worth a macro recorder would tolerate. The Version Number is duplicated several times, and what’s worse, in several different formats.

First, we have the FILEVERSION and PRODUCTVERSION entries, with comma separated numbers.

But then we also have the stringized version of those two elements, that must be specified as period separated elements within quotes.

I don’t have an alcohol fueled Code Sync 5000 robot to keep those numbers straight so I figured I’d just use macro substitution. Right. Turns out, the Resource compiler (RC.EXE) is a mighty fickel beast.

What I envisioned was a simple block to define the version number:

#define MAJOR          1
#define MINOR          0
#define REVISION       0
#define BUILD          116

and then use those definitions further down in the file, like so

FILEVERSION MAJOR,MINOR,REVISION,BUILD

and similiarly

VALUE “ProductVersion”, “MAJOR.MINOR.REVISION.BUILD”

But obviously, there’s a problem; actually, more than just one.

I won’t dwell on the details, but after much head scratching (polite euphimism), I ended up with this joyous concoction:

#define COMMAVER(mj,mn,rv,bl)        mj,##mn,##rv,##bl
// Commaver yields x,y,z,a  (necessary for the numeric versions)

#define PERIODVERPT2( mj )           #mj ""
#define PERIODVERPT3( mj,mn,rv,bl )  PERIODVERPT2( mj ) "." PERIODVERPT2( mn ) "." PERIODVERPT2( rv ) "." PERIODVERPT2( bl )
#define PERIODVER                    PERIODVERPT3( MAJOR,MINOR,REVISION,BUILD )
// PeriodVer yields x.y.z.a (necessary for the stringized versions)

// define the two numeric versions
// always make them the same                    
#define FILEVER        COMMAVER(MAJOR,MINOR,REVISION,BUILD)
#define PRODUCTVER     FILEVER

// define the two stringized version numbers, we just make them the same
#define STRFILEVER     PERIODVER
#define STRPRODUCTVER  PERIODVER

Then you can use them like so

....
FILEVERSION FILEVER
PRODUCTVERSION PRODUCTVER
....
VALUE "ProductVersion", STRPRODUCTVER
VALUE "FileVersion", STRFILEVER

Get clever with the #include directive and you can easily keep the version numbers of all the separately compiled VB components of your project synchronized and only have to set the version number in a single place.

If there’s a simpler way, I’d love to hear about it. But this works, and it keeps all my version numbers straight.

FIGlets

0
Filed under Utilities

How about a little fun?

I use batch files, make files, etc. to automate build processes quite often, but they can generate output that is, well, so very boring.

Why not liven it up a bit with FIGlets! This is some seriously old school tech, but it’s quite a nice effect if used in moderation.

Instead of just printing:

Build Starting...

in your output, how about:

      ____          __    ___ _____ __
     / __ )__ __(_)/ /___/ / / ___// /_____ ______/ /_(_)___  ____ 
    / __ // / / / / / __/ /\__ \ / __/ __ `/ ___/  __/ / __ \/ __ `
   / /_/ / /_/ / / / /_/ / ___/ / /_/ /_/ / /   / /_/ / / / / /_/ / _ _
  /_____/\__,_/_/_/\__,_/ /____/\__/\__,_/_/\__/_/_/ /_/ /_ \__, (_/_/_)
                                                           /____/

Makes it much more obvious when things have started or finished.

To generate one-off text snippets like this, go to The Ascii Generator.

or, for real flexibility, just download the original FIGlet command line utility. Be sure to get all the various fonts. Personally, I like the SLANT font the best (the example above is in SLANT).

Then you can just use:

FIGlet -f slant "Build Starting..."
....
FIGlet -f slant "Build Finished..."

in your batch files for some real early 90’s chic!

Microsoft Virtual PC and Shared Folders

2
Filed under Uncategorized

Ok, I admit it. I have a bias towards VMWare. It’s been around forever, and it’s solid as a Bob Seger song. But, the Microsoft offering (Vitual PC) is free and it’s at least usable. But it certainly has it’s share of, shall we say, quirks.

Here’s the latest.

I have 2 VPCs that I use for InstallShield install builds and testing. Both share a folder on the host machine so that I can easily pass installations back and forth between the two.

This morning, a subfolder of the share on one VPC turned up empty. I refreshed the view. Empty. Popped over to the host machine and looked in the folder. It’s there, and has all its files.

I reset permissions. No luck. I unshared and reshared the folder via VPC. Still empty. Rebooted both the VPC and the host machine. Still empty.

At this point, it’s cost me about 30 mins of a Saturday when I’d much rather be anywhere in front of a VPC. I finally just renamed the subfolder, thinking I’ll copy a new set of files down from the network. Lo and behold, the newly renamed subfolder shows up on the VPC, and it now shows its contents! Keep in mind that this folder worked properly yesterday, and that there are other sub-folders in the shared folder that continue to show their contents just fine as well. Just this one folder is at issue.

Hmmm. So I renamed it back to its original name. It goes empty again. Doesn’t show any contents.

Ah, computer voodoo. Or in this case maybe the more appropriate term Microsoft doodoo. At any rate, the install is rebuilt, and I’m off to do something that doesn’t require a plastic rat and 2,304,000 square colored dots.

VB and Lotus Notes

2
Filed under EMail, Software Architecture

Not something that often ends up on a VB developer’s plate I suspect, but I had need to do some investigating of Lotus Notes and possible integration/extension development using VB (classic, v6.0, not .NET).

Come to find out, Notes does have COM support as of 5.0.2b, so appearently, you do not have to dive down into ever joyous C++ in order to take a stroll through Notes-ville. Unfortunately, finding actual documentation for that object model online feels like finding your kid’s matchbox car that fell out of their pocket in the ball pit at Chuck E Cheese. I’ll try to post my results, if any, when I have some.

Now, as to why you’d want to dig into Note, one look here should dissuade all but the foolhardiest of souls. Granted, I know very little of the internals of Notes. From what I understand, internally, it’s actually a quite capable system, and has been for years and years. Still, those screenshots speak volumes.

Me? Well, I have a foot and here’s a Smith and Wesson. With any luck, the obvious won’t happen next.

InstallShield, Product Codes, Package Codes, and Upgrade Codes, Oh my!

16
Filed under Installations

So you’ve created an upgrade item with InstallShield (mine is 11.5), you’ve set everything up right as far as you can tell, and when you run in to upgrade a previous version, the installer pops up the “Modify/Repair/Uninstall” screen of the old version

Aha! You say. Forgot to change the Package code. So a GUID Generate and rebuild later, you try again and this time get this:

Another version of this product is already installed. Installation of this version cannot continue.

You got the Package Code different, Upgrade and Product Code the same in the two versions, and you’ve got a Major Upgrade item setup and configured to recognize the proper Old version number range.

What’s up?

Come to find out, the IS help is a little confused on this topic. When you create a MAJOR UPGRADE to your installation (which, if my experience is any indication, almost EVERY upgrade is a major upgrade), you need to change both the Product Code and the Package Code! But here’s the trick, the Upgrade Code stays the same.

Why? Because appearently, a Major Upgrade is considered an entirely new Product, even though it’s not, because you intend it to upgrade older versions of the product.

But MSI doesn’t use the Product Code for that, it uses the Upgrade Code for that purpose.

So, basic rule is:

When you create a new Version of your app’s installation with InstallShield (or any MSI based Installer, I suspect), be sure to:

  1. Make sure you have an Upgrade Item setup to recognize the proper version range
  2. Make sure you generate a NEW PACKAGE CODE guid
  3. Make sure you generate a NEW PRODUCT CODE guid
  4. Make sure you DO NOT modify the UPGRADE CODE guid (basically, you almost never modify the Upgrade Code guid)
  5. Kneel before the holy altar and make an offering to the MSI gods.

Here’s a handy table from a Macrovision support site article that also might help. Basically, it illustrates when a particular code needs to be changed (the X’s), based on what kind of upgrade the new version of your install is.

Update Type Package Code Product Version Product Code Upgrade Code
Minor Upgrade without Patching X
Minor Upgrade with Patch X X
Major Upgrade X X X

You know, I whipped out an install in InnoSetup in, like, 5 minutes. And it’s free.

Fun with the Word Object Model

0
Filed under Office

Ran into something very interesting with Word, Templates and the Word Object Model today.

I have a Word Addin that creates a Word Template on the fly and loads it when Word is loading up.

The template is used to save any modifications (via the Application.CustomizationContext property) to the Word Toolbar that I have to make while running, which is pretty standard stuff for a Word COM Addin.

Under normal circumstances, this arrangement works quite well. But today, I had a client report a problem where when they’d close Word, they’d get a pop up message that Word failed to save my template, because some other process has it open. Further investigation showed that 2 or more instances of Word were being loaded (in the background by another application), and the multiple instances of Word appeared to be what was causing the issue.

Now, most anyone who’s had to mess with supporting Word as a programmability platform knows it’s not a good scene to encourage multiple instances of Word. It just doesn’t work out all that well. But here I was, and the other app was a necessary one for this client, so uninstalling it was not an option.

After quite a bit of poking around, it turns out that Word appears to have a problem, or at the very least, an oversight.

The Word Object Model supports an Application.DisplayAlerts property, that is supposed to turn off message boxes, but it fails to do so in the case when you obtain a Template object and then use the Save method on it.

So even if you’re trapping errors on the save, intending to handle them through your code, and even if you’ve turned off alerts, using the above property, Word will still pop up that warning box. Since my template is a completely background piece of functionality, the last thing I want users seeing is warnings about Word being unable to save it.

And here’s the kicker. Since you can’t necessarily know whether Word will be successful at saving the template beforehand, there is no way you can determine whether or not you should even attempt to save the template. A classic catch-22.

In the end, I was able to work around this, er, unique, behavior by:

  • during the Word/Addin startup process…
  • Check if my template exists
  • If it doesn’t, create it and set a flag indicating that it’s safe to save (usually during the Word shutdown process)
  • If the template does exist, check if the file is writable (by attempting to open it with write access)
  • If that fails, the template is already opened (likely by another copy of Word) so set the flag indicating to NOT attempt to save the template from this instance of Word.
  • If the file writable check succeeds, the template is writable, indicating that nothing else has it open, so set the flag to indicate that it should be safe to save the template.

It’s not ideal, because, under some very peculiar circumstances, it still might be possible for Word to fail to save the template, and subsequently pop up that warning box. But such is the joy of the Word Object Model!