Friday, September 21, 2007

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.

image

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.  

posted on Friday, September 21, 2007 5:20:56 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Tuesday, September 18, 2007

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:

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\Installer]

Logging=Voicewarmup

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).

image

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 .%1.==.off. 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\:\-\)

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.

posted on Tuesday, September 18, 2007 11:32:27 AM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Sunday, September 16, 2007

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
   Else
      '---- 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)
         Else
            If Var1 > Var2 Then
               CompareVariant = 1
            Else
               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
      Else
         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!

posted on Sunday, September 16, 2007 9:11:51 AM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Monday, September 10, 2007

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:

image

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:

image

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

posted on Monday, September 10, 2007 10:16:41 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 

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\:\-\) ).

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!

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

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

image

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.

posted on Saturday, September 08, 2007 9:11:52 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 

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
   
   'DO YOUR CODE HERE
   rMyProp = NewValue
End Property

Public Property Get MyProp() As Long
   
   'DO YOUR CODE HERE   
   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).

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

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.

posted on Friday, September 07, 2007 9:49:50 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [0] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Thursday, September 06, 2007

Jim Rapoza writes an interesting article in the latest eWeek about the 5 things that Web 2.0 apps need to recognize to be successful. It's called IT Planner - 5 Steps to Next Generation Web Apps

  • Build Rich web apps. Ok pretty general, but a good start, I suppose
  • Remain "Open" minded. Open with your data, open to open-source, etc 
  • Keep Data Dynamic. Basically, allow users to play with it locally instead of only processing on the server. Sounds good, if not a bit like the "open minded" idea above. 
  • Make it available offline. Sure.
  • Be Flexible. Allow your app to be "molded" which ever way a user might like. Interesting idea. Basically, "make it configurable, and easy to import and export data". Hmm, sounds a lot like the 2'nd item also.

All pretty good ideas for.....wait.....what was that? "Available offline"?

Huh? A web app available for offline use. Why, that's just scandalous. Not too mention soooo last decade.

So. If I'm to understand this properly, one of the next great things in web applications is.... drum roll.... the traditional fat client desktop app.

And the circle remains unbroken. <Sigh>

posted on Thursday, September 06, 2007 5:32:49 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [1] • 
Kick it •  Add to del.icio.us •  View blog reactions; 
 Wednesday, September 05, 2007

What's with this?

I've seen this term bandied about, usually referring to some new feature in VB, and usually in a disparaging way.

Why?

I thought pretty much everything about a 3 or 4GL was syntactic sugar. Without that sugar, we'd be coding in assembler or hex opcodes. I mean, an IF THEN ELSE construct is just syntactic sugar for a bunch of JNEs or JEQs, right? Hell, object oriented code is nothing but syntactic sugar for an array of type structures and function calls with an index as their first argument (the hidden ME pointer in all OO compiler code).

Sounds more like just so much L337ism to me.

I say bring it on. As long as it makes sense, expands the language in useful ways, and isn't required to make use of the language, the more the merrier. My only concerns would be:

  • Any additional syntax that's required in order to successfully use the language. That's VB.NET's biggest problem now, with respect to adoption by users of VB.
  • Compatibility breaking changes

Still, I think ANDALSO is a tad corny, nice, but corny. So shoot me.

posted on Wednesday, September 05, 2007 9:44:58 PM (Central Standard Time, UTC-06:00)   •  # •  Comments [5] • 
Kick it •  Add to del.icio.us •  View blog reactions;