Monthly Archives: August 2007

I fixed that, Dammit!

Filed under Uncategorized

If you’re trying to validate an installation in InstallShield (version 11.5, in case that matters), here’s a little something to be aware of.

First, some background.

InstallShield sucks.

Ok, now that that’s out of the way, if you have to use it, you may find yourself needing to perform a validation on your install. I did when a customer called up telling me that they couldn’t deploy my install using Active Directory Group Policy because when they tried, AD GPO gave them an error that the install wasn’t valid.

Which it most certainly was, because tons of people have used it to install over that past 2 years.

Anyway, the customer happened to have WISE, so they ran a validation on it and got quite a few errors flagged.

So, I run InstallShield validation on it and I see quite a few errors too. Oops.

Well, to be honest, installs aren’t job one, and if the damn thing installs and uninstalls properly under all the test scenarios that we’ve cooked up, why would I even think to validate it?

None-the-less, it had issues. So I start investigating. Come to find out, the errors are things like “Foreign key not found in table blah” and such forth.

Whah?! You mean, InstallShield will actually build an install that contains patently incorrect or missing foreign keys between tables. Hey, if I was using ORCA to build installs, I could see this, but isn’t that what spending all that dough on InstallShield is supposed to buy you?

Fine, so I fix the foreign keys and revalidate. Same damn errors! Not one thing is gone from the validation errors list. WTF!

I puzzle over it for 15 minutes or so and then give ’em a call.

Ah. You have to rebuild your entire installation before rerunning the validation! Oh. That makes sense. And, um, exactly why doesn’t IS simply pop up a msgbox telling me I need to rebuild, or better yet offering to rebuild. It knows I just ran a validation. It knows I just made a few changes. Shouldn’t it know I’m not going to get valid results if I just run the validation without rebuilding?

This just seems like UI 101 to me, not Advanced AI 5.

Living Code

Filed under Uncategorized

I’m sure someone, somewhere, has already done a dissertation on this, but I’ve often thought it would be interesting to look at the code of a project as if it was a living, growing thing.

You’d analyze the changes made over time to a piece of code to visualize how it becomes better, breaks, corrects, expands and ultimately dies or gets recycled refactored, as well as the people making those changes, how long it took to make the changes, the number of changes on any given day, or possibly daily trends. Does more get fixed on a monday? Do more fixes made on friday end up getting reverted and fixed again later (for obvious reasons <g>). How many changes are made on wednesdays after that big fajita lunch?

I have this mental picture of my project visually changing over time, allowing you to see things that you couldn’t see just by looking at tables and metrics. Imagine being able to look at a time-lapse video of the creation of the Grand Canyon, from, oh say 30million years back to the present, in a video of a few minutes. Or a bit like this guy’s video (taking pictures of himself everyday for 6 years or so).

But in my head the picture is a little prettier, may something like this: 

And many, probably too many, projects would be more like this:


Deploying VSTO

Filed under Uncategorized

Just follow these easy steps:

Whatever happened to all that buzz about how great xcopy deployment was with .NET.? I seem to hear it out there…..somewhere….sinking slowly into that morass of the Windows API, calling out for help, meekly, gurgling, and then….

Fun With Word, or When is a Field not a Field

Filed under Uncategorized

I was investigating some strange behavior with respect to fields in Word and when, exactly, do they get “automagically” updated.

In this particular case, I had a document with a table of contents. The TOC looked completely correct, until the doc was “saved” as a PDF file using the Word 2007 PDF/XPS format plugin. In reality, it doesn’t matter whether the doc is saved as a PDF or printed, Word functions in the same way.

During the save to PDF, the TOC entries were all converted to “Error! Bookmark not defined”. In this case, that was correct. The bookmarks used to create the TOC entries had been removed, but, with the “Update fields” options set to false, I was expecting the fields in the TOC to NOT get updated.


As far as I can tell, they really shouldn’t  get updated, but they do anyway. This appears to apply to Word 2000 as well as 2007 (didn’t check all the interim versions).

So, TOC Entry fields appear to not behave by the same rules as other fields. For instance, I embedded an AUTHOR field, save the doc, then changed the Author Document property to something else, then saved as PDF. Lo and behold, the Author Field DID NOT change from it’s original value, meaning that that field type was not “auto updated” before the print/save as PDF.

Then I tried just a plain bookmark. Insert a named bookmark somewhere in the doc, then somewhere else, insert a PAGEREF field (type 37 for those Word VBA masochists) pointing to that bookmark.

The field should take on the value of the page the bookmark is defined on.

Now, delete the bookmark (not the pageref) and print.

Aha! Another “Error! Bookmark not defined”.

It’s not TOC Entries, per se, that have the problem. It’s bookmarks. It appears that even if you tell Word to NOT UPDATE fields at print, any field that references a bookmark, does get updated. And it’s not just that Word checks that the bookmark is defined or not. Word definitely updates the field referring to the bookmark. You can see this if you do the following:

  1. Create 3 HEADING1 lines
  2. Create a TOC, you should see 3 entries in the TOC, one for each heading 1 line, all pointing to page 1.
  3. Put page breaks between each heading 1 line, to force them to separate pages.
  4. Save the doc. The TOC page numbers don’t change.
  5. Now save as PDF. The TOC page number DO change at this point.

Looks like a Word bug, albeit a long standing one.

And the workaround?

You have to decide between:

  • Leaving the field that refer to the bookmark in the document, but deleting the bookmarks themselves, which will result in an Error.
  • Deleting the bookmark AND the field that references it (which would wipe out your TOC)
  • Converting all fields that reference bookmarks to text and then deleting the bookmarks (probably the best of the choices) 

There’s no easy answer to this one, unfortunately. That last option involves quite a bit of scanning through fields and bookmarks. Interestingly, Bookmarks must have a unique name, so they are pretty easy to get back to and track.

Fields, on the other hand, have no unique ID in Words object model. 

They have a “code”, but that can be the same across multiple fields.

They have an “index”, but that can change as you delete fields.

From my vantage, the lack of unique ID’s for many of the elements in the Word Object model is a significant, if not partially understandable, problem.


Filed under .NET, Rants

So, how useful do you find code snippets to be in VS2005? I mean, beyond the “I don’t know how to do something, aha! here’s an example!” use that would be better served up in expanded help file examples.

On the surface, I suppose they could be handy in some circumstances. For instance, setting up TRY CATCH blocks maybe, or….um… ok, having a hard time coming up with other examples. I suspect snippets are one of those gizmos that make you “feel” more productive without actually making anyone truly more productive. They seem like Stephen Colbert‘s answer to developer performance.

My problem with these kinds of macro code “generators” is that they just seem like so much “cut and paste” programming. If you’ve every had to work on code that was built by cut and paste, you know it’s more fun to steam your eyeballs out of their sockets.

If a piece of code warrants being “set up” as a snippet, it probably ought to be encapsulated into its own function/sub/method/whatever, where it can be reused properly.

Here’s a sample snippet for “iterating through a collection”:

      ' Iterate through a collection
        For Each name As String In names


Now maybe I’m just being a curmudgeon here, but that comment, I’d have to redo, and the rest of it, I can type in less time than it’d take to find the snippet, esp with intellisense. Sure, I could also set up a shortcut for it, but even then, does this sort of thing really save time? Or rather, does it save real time?

You might make the argument that the snippets for creating properties can save time, but if I’m creating that many properties, that consistently, I’m guessing I’m going to use something like MyGeneration instead.

And in the end, a snippet might save a few keystrokes here and there, but, when you look at the entire life span of a project, I’d wager that even if you snorted snippets and peed the Quake physics engine, you’d be lucky to save yourself a few thousandths of a percentage point of the total time you spent coding.

Makes me wonder what the Freakonomics guys would say about them.

Creating MSI installs for Vista

Filed under Installations, Vista

Neeru Hundal has a pretty interesting and informative blog at that’s all about MSI issues.

A very good article there focuses on issues to look out for when creating MSI’s for Vista (or that might end up on Vista, which means pretty much any MSI, I’m guessing).

One in particular hit me just a few days ago. Neeru indicates you need to set the ALLUSERS property to 1. He emphatically states you need to SET IT (not just leave it blank or not there at all). I’ve found that you definitely need to set it, but you should set it to 2, or you may end up getting UAC and “You don’t have proper permissions” messages, even though you’ve created the install to specifically NOT require admin privileges. Originally, I had ALLUSERS set to 1 and was getting a “requires admin privs” message even though my installation shouldn’t have required administrative privileges.

Another nugget:

  • Custom Actions
    1. Custom Actions in the UI Sequence will run with standard user privileges
    2. For Custom actions requiring admin rights, mark custom action as Deferred – No Impersonate

Anyway, he’s got a few other articles there, too, which make for some good reading.

daBlog’s New Medium Trust Made Me Sad (for a little while, anyway)

Filed under ASP, Blogging, dasBlog

Oops, don’t try this:

      Dim req As System.Net.HttpWebRequest = System.Net.WebRequest.Create(URL)

on an ASP.NET page in a web app marked with MEDIUM trust (as the new dasBlog 2.0 comes configured, as in this web.config file)

<?xml version="1.0" encoding="utf-8" ?>
        <trust originurl="" level="Medium">

Guess that’s one of the no-nos of medium trust.

In my case, the only place I’m doing this is where the incoming URL is a value fixed in code, not something coming from user input, so I don’t believe it can be usurped for unscrupulous uses (I think I just blew my “u” quota for the day<g>) .

If you’re wondering, that code came from the ICQ status request bit I coded up and blogged about here.

To solve it in my case, I went back to normal trust level.

Anyone know how you’d handle doing this in medium trust? 

Strings in a File

Filed under Uncategorized

Working in metadata removal from Office documents, one thing I do almost constantly is dig through files with a hex editor looking for any text that’s readable.

I’d been contemplated writing a string filter utility for some time when I happened to see an offhand mention of something like that from SysInternals.

Now, if you’ve ever played with anything from the guys at Sysinternals (now a part of Microsoft), you know their stuff is gold, so I had to check it out.

The utility is called Strings. It does exactly that, pulls strings (both ANSI and UNICODE) from any file you throw at it and spits em out STDOUT. Pipe it to a file and it’s MONEY, BABY!

Even better, put STRINGS.EXE and this little BAT file somewhere on your path, then setup a shortcut to the BAT file in your SEND TO folder, and you can Right click-Send To on any file and immediately have all the strings loaded up into whatever Text Editor is currently associated with TXT files. And that, as an old boss of mine would say, is “bells, whistles, hell, it’s the whole damn midway!” 

REM Run the strings.exe program to extract all strings from a given file
REM Then load the file into an editor
REM Create a Shortcut to this BAT file in your SENDTO folder to make it even
REM better! Then, you can right click, select SEND TO and immediately get a full
REM list of strings embedded within the file loaded into your editor.

REM Extract the strings to a temp file
strings -q %1 >"%temp%\%~n1-Raw.txt"

REM Sort strings to make it a bit easier to find things
REM This may or may not be something you want to do consistently
REM Either do the sort or the copy
REM sort "%temp%\%~n1-raw.txt" /o "%temp%\%~n1.txt"
copy "%temp%\%~n1-Raw.txt" "%temp%\%~n1.txt"
del "%temp%\%~n1-Raw.txt"

REM -----------
REM Use this to load the file into whatever editor is associated with a TXT file
REM -----------
start "Strings" /I /B "%temp%\%~n1.txt"


REM -----------
REM Use this to load the file into a specific named editor
REM -----------
REM o:\dev\protools\textpad\textpad "%temp%\%~n1.txt"

The VB6 CreateObject Function

Filed under Code Garage

This is one of those often used functions in VB6 that could use a little improvement. The main problem with CreateObject is when it throws an error, it doesn’t report what object it was attempting to create at the time, which would be quite a handy thing to know.

Fortunately, CreateObject is one of small number of intrinsic functions in VB that can be overridden quite easily.

In other words, you can define your own CreateObject function, and VB will call your version instead of it’s built in version anywhere that you use it. This is quite handy because it means you can use the enhanced version without changing any calling code.

For instance, here’s a CreateObject function I put together that expands on the default error message string if it encounters a problem creating the object asked for. It simply adds in the PROGID of the object you’re trying to create.

Public Function CreateObject(ByVal Class$, Optional ByVal ServerName$) As Object
   '---- override the CreateObject
   '     function in order to register what
   '     object is being created in any error message
   '     that's generated
   Dim Source$, Descr$, ErrNum

   On Error Resume Next
   If Len(ServerName$) Then
      Set CreateObject = VBA.CreateObject(Class$, ServerName$)
      Set CreateObject = VBA.CreateObject(Class$)
   End If

   If VBA.Err Then
      Source$ = VBA.Err.Source
      Descr$ = VBA.Err.Description
      ErrNum = VBA.Err
      Descr$ = Descr$ & " (ProgID: " & Class$
      If Len(ServerName$) Then
         Descr$ = Descr$ & ". Instantiated on Server '" & ServerName$ & "'"
      End If
      Descr$ = Descr$ & ")"
      On Error GoTo 0
      VBA.Err.Raise ErrNum, Source$, Descr$
   End If
   On Error GoTo 0
End Function

Put this function in a normal BAS module, and anywhere that you use CreateObject already, you’ll now be calling this function.

And to answer a few questions:

Q: Why do you use the VBA prefix for CreateObject and the ERR object in this piece of code?

A: In the case of CreateObject, you have to prefix it or this function would end up calling itself instead of the real VB CreateObject function.

In the case of the ERR object, see below.

Q: What other functions can be overridden?

I haven’t done an exhaustive study of it, but I can say that a particularly handy object to override is the built in VB ERR object defined in the VBA library.

Overriding that object allows you to extend error handling functionality in all sorts of ways.

For instance, you could add a LOG method to the ERR class, or a MSGBOX method that automatically formats an error for display in a message box.

But that’s a topic for another post. 

Online Apps, Good or Bad?

Filed under Rants, Software Architecture

John Dvorak wrote a very interesting article for PCMag on 8/14, Google Pulls Plug, Everyone Misses Point.

I’ve been saying web apps were overhyped ever since SalesForce first came out and was getting tons of hype back in the 90’s, and that’s not because I used to work at a competitor (gotta love the wayback machine).

On the surface, it’s a great idea. No installation. No deployment headaches. No massive, multi machine upgrade pains. And with AJAX, and now SilverLight, you can get a user experience approaching a traditional fat client. Plus, with broadband nearing ubiquity, some of the bandwidth issues of the past are no more.

And for many installations, where users can connect to a centralized server within the company’s domain, it often is a very smart architecture.

So what’s the problem?

Dvorak points to the demise of the Google DTO/DTR program as exactly the problem. Imagine if it was YOUR BUSINESS that was running off the DTO program and Google pulled the plug. “Oh, you won’t be able to access your customer records after Aug 8th, but here’s a coupon for 2 bucks at Google Checkout you can use for the next 2 months.”

I doubt SalesForce is going anywhere anytime soon, and they do have a compelling product. I’m not even picking on them, per se. But the whole idea of putting that kind of trust into an app that’s running completely NOT under your control is just a little, eh, bothersome?

In fact, I tend to believe that the absolute BEST thing that could happen for everyone is for a few more biggies, like Google Apps, or SalesForce, or Microsoft MSN Mail, etc, to bite the dust and strand millions of people.

It’d hurt, but people would take a serious look at the implications of relying on ASPs to supply services like that.

There were some big reasons back in the early 80’s that the personal computer and the fat client app, as opposed to the mainframe and the dumb terminal, because so popular. Some of them have been forgotten, and unfortunately, it might take a few tough lessons to remind people.