Monthly Archives: September 2007

When an InstallShield package code is not a package code

Filed under Installations

Normally, when you want InstallShield to be able to perform a MAJOR UPGRADE on an install package, you have to change both the “package code” and the “product code”, and of course, the product version. However, you’ll normally leave the “Upgrade code” the same.

If you do this, InstallShield will install your new “version” as a new product, but it will also detect the existence of the previous version due to the Upgrade code, and force an uninstall of the previous version. I’ve actually blogged about this before here.

That’s exactly what I was expecting when I started testing the latest version of our package (and the first that was intended to support upgrades), and I was a bit surprised and perplexed when it popped up into maintenance mode  of the previous version!

Somehow, I could start the install by dbl clicking on the MSI of the new version, but the maintenance mode of the previous, installed, version would get started?! What the hell?

I started digging through verbose logs, called Macrovision, the works, and nothing seemed to fix it.

Then, I happened to notice mention of a package code in the logs that I didn’t recognize. I checked my new version’s properties and the package code didn’t match what was in the log.


Where the heck was it getting this other package code from?

So, I did a search through the project and it turned up here, under the releases screen!


Turns out, at some point in the past, this package code had been set, which overrides the package code defined in the Summary Info Stream screen above, when I build this particular release.

Since package codes should normally change with each build, everything was getting screwed up.

I set the “Generate Package Code” option to Yes, and cleared the package code from the releases screen, recompiled and all was well.

I suppose this is an easy mistake to make, but it’s one that left me scratching my head for more than just a few minutes.

Opening a command prompt as Administrator, the easier way

Filed under Uncategorized

Over at Scott Hanselman’s blog, he just posted an interesting bit about hard resetting your network connection.

Good info, though I can’t say I’ve ever had the need to club it quite that hard.

Anyway, one of the comments struck me as FAR more useful, and something I did not know.

When you’re opening a CMD prompt, you can hold down CTRL and SHIFT as your press ENTER to open it as an administrator (after you supply the right password, of course).

This is a very handy little bit if you regularly have to pop onto normal permissioned user’s systems in order to load up the newest bits of some accounting package that can’t be installed without admin credentials, or if you’re insane enough to try developing under Vista with UAC turned on.

It smacks the heck out of:

RUNAS /USER:{machinename}\Administrator cmd

Sadly, it appears to only work under Vista, though.

Grid Wars 2

Filed under Arcade, Games, VB Feng Shui

Ok, nothing to do with Visual Basic, but, you gotta come up for air sometimes!

It’s been a while since a video game really wowed me.

I mean, there’s lots of slick 1st person shooters out there now and with some of the heavy iron running around now, the graphics can make “Toy Story” almost look like “Dragon’ Lair.”

Still, nice graphics only go so far. And 1st person shooters are starting to see a little stale.

Then I stumbled into Grid Wars 2. Holy cow. I mean, seriously.


World of Stuart summed it up thusly in his review; “THIS is a video game.”

Go there for some wicked screenshots (far better than what I’ve put up here) and a link to download. You can’t get it from Marc Incitti’s site anymore <sigh>. Apparently, it’s a bit too much like “Geometry Wars” for the comfort of its creator. Grab your copy while you can.

I’ve never played it’s progenitor, but Grid Wars 2 definitely brings the frenetic back to video games. Plus, some subtle scoring tricks that WOS discusses in his writeup that make it all the more interesting. And there seems to be no end to the unique powerups that pop (get 150 bad guys, 3 black holes, 4 snakes, with quad cannons, side fire, fast fire and bouncing shots going all at once, and you’ll swear your screen is about to catch fire).

And, come to think of it, there is a little bit of VB goodness here, or rather BASIC goodness. It’s opensource, and written in BlitzMax, a pseudo-basic, game programming platform form Blitz Research. Plus, the install is unbelievably sweet. A zip file. Just unzip somewhere and run the EXE. T’would be a blessed day that Office trod down that path.  

Verbose MSI Logging

Filed under Uncategorized

I’ve found that many times when debugging an MSI install, it’s quite handy to get a full verbose log of what the install is doing.

You can turn on verbose logging from within the installation itself, at least when using InstallShield, but that has several drawbacks.

  • It’s implemented as a function of the InstallShield SETUP.EXE front end, so if a user dbl clicks the MSI file directly, it won’t log
  • It doesn’t apply during the UNINSTALL or the REPAIR operations, which are quite common and can also fail and require logging

To get a full MSI activity log, regardless of the activity, you need to modify a registry key:



To turn it back off, just delete or blank the Logging value.

The logs will end up as random .LOG filenames in the user’s TEMP folder. It’s best to clean out your temp folder before running the install so the new LOG files will be easy to find. (or sort by date).


But doing all this manually can be a pain.

So here’s a little BAT file to take the edge off.

Just save it as MSILogging.bat (somewhere on your path for maximum utility), and then run it like so

MSILogging ON

MSILogging OFF

or just

MSILogging (no parm is the same as ON).

echo off
REM Simple batch to turn verbose MSI Logging on or off
REM command line option is ON or OFF (all lower or all UPPER case)

REM Create the reg file
set file=%temp%\$reg.reg
echo Windows Registry Editor Version 5.00>%file%
echo ;>>%file%
echo [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer]>>%file%
if .%1.==.ON. echo "Logging"="voicewarmup">>%file%
if .%1.==.on. echo "Logging"="voicewarmup">>%file%
if .%1.==.. echo "Logging"="voicewarmup">>%file%
if .%1.==.OFF. echo "Logging"="">>%file%
if echo "Logging"="">>%file%

REM for testing purposes
REM type %file%

REM Apply it with Regedit (you'll need to have rights)
REM /s makes it silent
regedit /s %file%

REM Could uncomment this to remove the temp file when done
REM del %file%


And no comments about my lame bat file case insensitive batch scripting<g>

Even better, add a line at the end:

copy %temp%\msi*.log .\

and all those log files will end up in your current directory (instead of making you go fishing through Documents and Settings to find them), although this may suit some people more than others.

Comparing Variants

Filed under Code Garage, VB Feng Shui

Here’s another handy bit from my VB6 code shed out back.

If you’ve worked much with databases in VB6, you know that you almost always end up having to deal with database NULLs at some point.

And, in VB6, the only variable type that can actually deal with nulls is the Variant.

For the most part, my code avoids nulls by coercing them to the most appropriate “null value”, either a 0, or a 0 length string, etc, depending on the underlying data type.

However, there are instances where I’ve needed to compare two values directly from the database, and didn’t want to coerce them up front.

That’s where this handy routine comes in.

Public Function CompareVariant(Var1 As Variant, Var2 As Variant, Optional CompareMethod As VbCompareMethod = vbBinaryCompare) As Long
   '---- Compare 2 variants that might contain NULL or empty values

   Dim bVal1Null As Boolean
   Dim bVal2Null As Boolean
   Dim bVal1Empty As Boolean
   Dim bVal2Empty As Boolean
   Dim bSameValues As Boolean

   bVal1Null = IsNull(Var1)
   bVal1Empty = IsEmpty(Var1)
   bVal2Null = IsNull(Var2)
   bVal2Empty = IsEmpty(Var2)

   '---- variants are the same if
   '     1) both are null
   '     2) both are empty
   '     3) they are otherwise equal
   If (bVal1Null And bVal2Null) _
      Or (bVal1Empty And bVal2Empty) Then
      CompareVariant = 0
      '---- you can only check for equal values is if neither of the values is Null or Empty
      If Not (bVal1Null Or bVal1Empty Or bVal2Null Or bVal2Empty) Then
         If CompareMethod = vbTextCompare Then
            CompareVariant = StrComp(CStr(Var1), CStr(Var2), vbTextCompare)
            If Var1 > Var2 Then
               CompareVariant = 1
               CompareVariant = (Var1 < Var2)
            End If
         End If
      ElseIf bVal1Null Then
         '---- This is arbitrary, I'm determining that NULL is < empty
         '     this might not be universally appropriate, though
         CompareVariant = -1
         CompareVariant = 1
      End If
   End If
End Function

Basically, the idea is similar to the built-in VB function StrComp, but it intelligently deals with potentially NULL or empty variants as well.

Are there faster ways to do this? Probably. But I find I need the functionality so infrequently, it hasn’t been a priority to optimize.

Still, if you need it, coding this up each time would be a complete pain in the ass (and unfortunately, I’ve seen that tack taken more than a few times).

If anyone can improve on this, please let me know!

Designing an Arcade Control Panel

Filed under Arcade, Hardware

I’ve been looking for a good template to build an arcade control panel from (you know, joysticks, buttons, trackball, etc, using real, arcade quality components).

My goals are pretty lofty:

  • a 4 player panel
  • Spinner, Flight stick, etc
  • 2 trackballs
  • Diagonal stick
  • USB and/or PS2 compatible
  • Gotta have a little real wood somewhere (but not the top, that just doesn’t seem to look right)
  • Able to “plug into” a full-on cabinet one day (though I may never get there)
  • Preferably one piece (seems more stable and resilient to the beating it’s likely to get)
  • But not one big flat vast prairie of formica, like the SlickStick:


There are a lot of designs out there, including:

However, to me, Jeff Allen’s is hands down the most interesting.

He came up with a split level panel that puts the most often used sticks and buttons, plus the trackball on the lower level, and the lesser used controls, like the spinner, flight stick, etc slightly elevated so you’re not constantly banging into the other controls. This is Jeff’s picture:


I think I’ll pass on the red t-mold, but other than that this seems like very flexible and usable, yet clean and simple, design. Plus, I could easily see that top panel being “hot swappable”, if I ever decided to go for a real driving wheel or yoke, etc

Don’t forget those ancient SPs!

Filed under Uncategorized

I had started doing a little regression testing on a product I work on recently. I’d been doing my dev under Vista with Office 2007, so I thought it’d be good to go back to Office 2000 for a bit.

I uninstalled 2007, installed Office 2k, then reinstalled Office 2007, rebooting along the way as is the norm (geez and here I thought it was 2007!).

Anyway, I fired up Word 2000, loaded a few doc files, closed it and did the same with Word 07. Everything looked good, so I fired up my app from within Word 2k. As Bob Kane might say, BOFF – BIFF – BLAMMO – KERPOWEE!

Hmmm. I actually crashed Word. That doesn’t happen too often (at least not anymore<g>).

So I started looking back through the relatively few changes I’d made to the code since the last time I knew it DID work under Word 2k. Nothing popped out.

So I stubbed out most of my code and discovered the problem was that when I was closing the Word document, via Application.Documents(x).Close, the document wasn’t actually being closed. Word still had it open. Which screwed up everything there after. Plus, virtually all my code dealing with Range locations (ie where things like fields and pictures are located in a document) was crashing Word left and right.

Now I’m starting to get a little panicky. I couldn’t have screwed things that badly.

So I’m staring at it blankly for a few minutes when it dawns on my. I don’t think I installed any service packs for Office 2k!

Hmm, check versions, sure enough, I hadn’t.

Ok, so do I have to uninstall Office 2007 again, just to get the old SPs on for 2k? I decide to throw caution to the wind and just start up the Office SP1 install, followed immediately by the Office SP3 install (SP3 didn’t roll up SP1 back in the day, wouldn’t you know).

Viola! My app’s running just fine, no crashes, documents close properly, etc.

Moral of the story. With those old apps (and OS’s, what with VMs being all the rage for testing), don’t forget the SPs!

Voyager still going

Filed under Uncategorized

Just happened upon this page about the current status of Voyager 1 and 2.


Those bots are still going, some 9.5 billion miles from here.

The page is pretty boring stuff, till you realize, these are commands and responses sent to robot spacecraft launched 30 years ago, which are now outside our solar system!

With any luck, my kid’s kid’s kids will get to take a day trip out to check out their progress and be back in time for dinner.

Module Properties?

Filed under Code Garage, VB Feng Shui

I’m thinking of starting an ongoing series of posts highlighting some of the more “interesting” things you can do with VB6 that are not, at least to my knowledge, particularly well known. I figure, VB6 has started on that long slow road into SNOBOL-dom, the land where old languages go, not necessarily to die, but to continue living, just with very few people paying any attention. We can only hope C and C++ will head there eventually.

Anyway, might as well collect a few of my favorite hacks, tweaks, and WTF?! bits before they all end up only in the depths of the WayBack machine

Here’s one that you don’t see often. If I remember correctly, there is a bit of a performance hit with it, but it’s pretty minor.

Did you know a VB module can actually contain properties?

Huh, you say. Interesting, but so what?

Well, since public elements of modules are public project-wide, you can create some pretty handy functions this way.

For instance, say you have a function to read an entire text file in at one shot, and one to write a whole text file. You could have two subs to do the dirty work. Or you could do something like this (put this code in a BAS module, not a class):

Public Property Let FileTextContent(ByVal FileName$, ByRef NewValue$)
   '---- Block write the entire file's content in one shot
   Dim fh
   On Error Resume Next
   fh = FreeFile
   Open FileName$ For Output As fh Len = 2048
   Print #fh, NewValue$;
   Close #fh
End Property

Public Property Get FileTextContent(ByVal FileName$) As String
   '---- Block read the entire file's content in one shot
   Dim buf$
   Dim fh
   On Error Resume Next
   fh = FreeFile
   Open FileName$ For Binary Access Read As fh Len = 2048
   buf$ = Space$(LOF(fh))
   Get #fh, , buf$
   Close #fh
   FileTextContent = buf$
End Property

With a property like this in place, you can then read a file’s content with Just:

x$ = FileTextContent(MyFile$)

Which looks exactly like a function call, granted. But you can write a file’s content with:

FileTextContent(MyFile$) = x$

It’s a minor syntactic difference from just using two subs, or maybe a sub and a function. But personally, I think it reads a little nicer.

Of course, you can also use this technique to provide for global scope properties, ie properties that don’t belong to any particular class. This is sometimes handy when you need to expose a value globally, nut you also want to perform some processing on it during an assignment or a retrieval.

You could define the global property via a GLOBAL variable definition, but that gives you no “hook” to do your processing on the value when code retrieves it or sets it. Instead, use something like this in a BAS module:

Private rMyProp as long
Public Property Let MyProp(Byval NewValue as long)
   '---- Block write the entire file's content in one shot
   rMyProp = NewValue
End Property

Public Property Get MyProp() As Long
   MyProp = rMyProp
End Property

Now, you have a convenient way to get and set the value from everywhere in your project, AND you have point at which you can hook in to preprocess or post-process the value as necessary.

And, if you name the module something short and sweet, say, like UTILITY, then you’ll get handy intellisense as well (just type “UTILITY.” to get the props and functions available on it).

Handy Context Menu Stuff

Filed under Uncategorized

I put together a little REG script ages ago that added context menus for DLLs, and EXE’s for registering and unregistering them.

I use it all the time. So much easier than invoking regsvr32 manually all the time.

Anyway, I just stumbled upon Chris Sells’ version of this script, which one-up’s mine in that he uses REGTLIB.EXE, which comes with VS6, to also register and unregister TLB and OLB files. 

And who knew that utility even CAME with VS6? I somehow have completely missed it all these years.