Category Archives: VB Feng Shui

Damn, I Gotta Get Into .NET

0
Filed under .NET, VB Feng Shui

I’ve been trying to make a point of reading more .NET code lately.

Maybe it’s Scott Hanselman’s Weekly Source Code.

Or maybe it’s that Code Project gadget on my Google home page.

At any rate, I just ran across a project there call LinFU (don’t ask what it stands for), but…wow.

It reminds me of the Black Belt columns by Matt Curland ages ago in Visual Basic Pro (or whatever it was called then, now Visual Studio Magazine). There hasn’t been articles like his in that rag for years. (and btw, if you still do VB6 and don’t have his Advanced Visual Basic 6, I’d highly recommend getting a copy).

Anyway, it’s stuff like Philip Laureano’s LinFU that really is making .NET seem more and more attractive.

True Or False

2
Filed under Code Garage, VB Feng Shui

It seems like such a simple task; check a variable for whether it contains a true value or a false value.

No problem, right? Well, if you’re dealing with numbers, maybe, but when input comes from config files or databases, the truth <ahem> may not be so obviously out there.

As part of my code garage, I thought I’d post two functions I’ve used for ages to do just that; convert a variable, virtually any variable, to a boolean result.

They are especially useful in configuration handling, where you might want to support multiple values that might mean “true” or “false”, like on/off, yes/no, etc. I’ve also found that they can make code clearer by specifying the “assumed” default value if the variable can’t be concretely identified one way or another (is “Bob Thomas” true or false?).

Public Function IsTrue(VarToTest As Variant, Optional ByVal Default As Boolean = True) As Boolean
   '---- Resolve an input variable to a boolean
   '     but convert common "true"/"false" phrases as well
   '     Also, this allows for an easy way to indicate a
   '     "default" value in cases of an undetermined (ie blank)
   '     value
   Dim t$
   Dim s

   Select Case VarType(VarToTest)
      Case vbArray
         Err.Raise 5, "IsTrue", "Can't test an array for true"
      Case vbObject
         IsTrue = ObjPtr(VarToTest) <> 0
      Case vbString
         If Len(VarToTest) = 0 Then
            '---- is true assumes blanks are true
            IsTrue = Default
         Else
            On Error Resume Next
            '---- strip to first space
            t$ = Trim$(Left$(VarToTest, 15))
            s = InStr(t$, " ")
            If s > 0 Then t$ = Left$(t$, s - 1)
            '---- clean out any tabs
            t$ = Replace(t$, Chr$(9), vbNullString)
            '---- accept some synonyms (any other good ones?)
            If InStr(1, t$, "YES", vbTextCompare) = 1 Then
               IsTrue = True
            ElseIf InStr(1, t$, "NO", vbTextCompare) = 1 Then
               IsTrue = False
            ElseIf InStr(1, t$, "ON", vbTextCompare) = 1 Then
               IsTrue = True
            ElseIf InStr(1, t$, "OFF", vbTextCompare) = 1 Then
               IsTrue = False
            ElseIf InStr(1, t$, "TRUE", vbTextCompare) = 1 Then
               IsTrue = True
            ElseIf InStr(1, t$, "FALSE", vbTextCompare) = 1 Then
               IsTrue = False
            Else
               IsTrue = CBool(VarToTest)
               If Err Then
                  IsTrue = Val(VarToTest) <> 0
               End If
               On Error GoTo 0
            End If
         End If
      Case Else
         If IsEmpty(VarToTest) Then
            IsTrue = Default
         Else
            On Error Resume Next
            IsTrue = CBool(VarToTest)
            If Err Then
               IsTrue = Default
            End If
            On Error GoTo 0
         End If
   End Select
End Function


Public Function IsFalse(VarToTest As Variant, Optional ByVal Default As Boolean = False) As Boolean
   '---- basically, the inverse of IsTrue above
   '     mainly for convenience

   IsFalse = Not IsTrue(VarToTest, Default)
End Function

Hey, CBOOL is undoubtedly faster, but:

   If IsFalse(SettingValue) Then 
      '---- handle the negative condition here
   End If

just seems so much clearer.

The optional Default argument allow you to specify what value to return if the value to test can’t be resolved satisfactorily one way or the other. Practically, this allows you to easily specify whether a blank value or a “non-boolean” value should translate to true or false. This is especially important when you’re reading config options from a file or the registry where the option may not exist at all.

It allows to do something like so: 

   If IsTrue(SettingValue, False) Then 
      '---- handle positive conditions here, but if the SettingValue is blank, we default to False
   End If

Simple, but handy.

VB and Dirty Laundry

2
Filed under Rants, VB Feng Shui

No, I don’t do Don Henley impersonations. But I was starting a load of laundry the other day and something struck me. Once I’d recovered and put the broom back where it was supposed to be, I realized something.

Take your standard, run of the mill washing machine. It’s essentially a variable speed motor, a few belts and pulleys, a water pump, and big cog timer wheel that sort of looks like the sheet music for a player piano*.

These things will run several times a week, for years on end and only rarely have any issues. Even then, the most likely problems are things like belts wearing out, bearings getting squeaky, or the timer cogs breaking off causing cycles not to start or stop properly. Further, I’d be willing to bet that just about anyone can set one up, plug it it, connect the 2 water hoses and the drain line, and be doing laundry within 30 minutes to an hour, and just about never think about any of that “configuration and setup” again till they move. 

Compare that, then, to the lastest washing machines, with “steam” cleaning, LCD consoles, touchscreens, dozens of “operating modes”, delay start timers, and even internet access.

I love gadgets, but seriously, does being internet-enabled or using an LCD touch screen get my clothes any cleaner, or prevent me from actually having to lug my laundry to the utility room? Do they actually save real people any time whatsoever over a 200$ (or cheaper) model with knobs instead of touchscreens and mechanical timers instead of microchips? Is this really progress?

I gotta stop hitting myself with brooms.

* and yes, that’s an oversimplification, for all you washing machine enthusiasts out there.

Grid Wars 2

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

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.  

Comparing Variants

0
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
   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!

Module Properties?

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

Syntactic Sugar

5
Filed under .NET, Rants, VB Feng Shui

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.

Native or Psuedo-Code VB6?

2
Filed under Code Garage, VB Feng Shui

VB6 has the interesting capacity to compile to either native code or pseudo-code.

Native code is actual Intel machine code. Pseudo-Code is much like the .NET “Intermediate Language” or IL, although, I suspect, a little less refined<G>

Most VB6 programmers I’ve known tend to compile to Native code although pseudo-code can be quite handy in some circumstances. First, it compiles much faster. Second, the generated EXE’s or DLL’s are typically much smaller than Native code EXE’s or DLL’s.

But what if you want, or need, to tell the difference at run time?

You could write up a conditionally compiled constant, but then you have to remember to switch the condition when appropriate. Still, that’s probably the ideal way to go.

But, that’s not really  a runtime solution, now, is it.

I happened upon the solution ages ago when I was researching an article I wrote for VBPJ about implementing TRY CATCH exceptions in VB6.

Essentially, you grab the first byte pointed to by a function pointer and check it. If it’s an &HA1, you’re in the IDE running pseudo-code.

If it’s &HBA, you’re running as compiled pseudo-code.

Anything else means you’re running compiled native code.

As far as I can tell, this technique works regardless of optimization settings, etc.

Yeah, it’s probably a little overkill, but that’s what hacking is all about. Plus, knowing whether you’re in the IDE without scrambling the state of the ERR variable is quite handy in some circumstances. I created a separate function for that purpose.

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)

Private Function pGetAddr(addr As Long) As Long
   '---- utility function for IsNative and IsIDE

   pGetAddr = addr
End Function


Public Function IsNative() As Boolean
   '---- determine whether we're running
   '     a Native code EXE, or a PsuedoCode exe
   '     Also can determine whether we're in
   '     IDE or not
   '
   '     Now this is HardCode!
   '
   Static Inited As Boolean
   Static bIsNative As Boolean
   Dim b As Byte

   If Not Inited Then
      CopyMemory b, ByVal pGetAddr(AddressOf pGetAddr), 1
      Select Case b
         Case &HA1
            '---- In IDE
            bIsNative = False
         Case &HBA
            '---- Psuedocode compiled
            bIsNative = False
         Case Else
            '---- native code Compiled
            '     the actual byte might be any number of things
            '     because of optimizations in use
            '     but will generally be either &H55, &HC7 or &H83
            bIsNative = True
      End Select
   End If
   IsNative = bIsNative
End Function


Public Function IsIDE() As Boolean
   '---- determine if we're running in environment
   Static Inited As Boolean
   Static bIsIDE As Boolean
   Dim b As Byte

   If Not Inited Then
      CopyMemory b, ByVal pGetAddr(AddressOf pGetAddr), 1
      '---- &HA1 means we're in the IDE, else we're not
      bIsIDE = (b = &HA1)
   End If
   IsIDE = bIsIDE
End Function

They Killed the Web! The Bastards!

1
Filed under Software Architecture, VB Feng Shui

The web as we know it is in its death throws.

Um, right.

I just read the Guest Opinion in the latest Visual Studio Magazine. It’s by Rockford Lhotka, who I have a lot of respect for. But this piece was a little off.

He basically claims that “the web as we know it is finally coming to an end”. Why, you may ask?

  • Is it the impending rollout of IPV6?
  • Maybe some new 3d “navigator” (as in the-chess-set-on-the-millenium-falcon 3d, not yet-another-2d-window-into-a-virtual-3d-space 3d)?
  • Or maybe there’s a new “brain driven” interface I hadn’t heard of?

No.

It’s Silverlight. and Atlas.

Sigh.

According to Rockford, AJAX is the “last gasp of a dying technology”. He argues that at some point, “either the browser transforms into a full blown programming platform or we find another answer”, and that answer, apparently is SilverLight.

Now, don’t get me wrong. SilverLight is pretty slick, as long as you don’t try to find any examples of actual web apps written in it. You know, the kind that people would use as opposed to just play with for 5 seconds. There’s tons of nice animated displays synched to music and pretty graphics of pages flipping, but where’s the data driven samples, or the reporting grids, or the company dashboards, etc?

Not only that, but hasn’t the web already got a “launch point to load something that is a programming platform”. I thought it was called Flash? And flash has certainly not brought the end of the Web nigh. Hell, it’s harder and harder to find sites that even bother with it anymore.

And SilverLight is from Microsoft, so you can bet that, even if they initially support a plethora of browsers and systems, eventually, it’ll get whittled down to Windows Voyeur (or whatever they’ll be calling the new version in 5 years).

Rockford makes a good point about technologies lasting upwards of around 10 years before being replaced by newer, better concepts. Things like COM, Win32, and CORBA. Things like ISA, the serial and parallel port, and ATA IDE. Things like hard drives, mice, qwerty keyboards, text files and relational DBMSs…. Oh wait.

I’d lay money that the next “big thing,” the thing that “kills the web as we know it” and ushers in a new era similar to the internet age of the 90’s, will not come from a big house like Microsoft, or IBM, or even Xerox. It’ll come from some dedicated hacker like Marc Andreeson or Bram Cohen. It’ll start off small. Hardly anyone will use it, kinda like Google back in, oh, 1999. And it’ll probably have a goofy name, nothing as cleanly futuristic as “SilverLight”.

Until then, I’d say the odds are long on HTML, Javascript, Ajax, etc, going poof.

Nullable Types in VS2008

3
Filed under .NET, VB Feng Shui

The VS 2008 VB will support nullable types.

Simply put, a nullable type is a standard type, like, say, integer or string that can ALSO contain a null.

This can become very important in database work, because a null value in a field means that no value has been assigned to that field vs a common case where you might use 0 in a numeric field to indicate no value, or you might use a null string (ie a string with no length) in a string field.

Obviously, using 0 to indicate no value works much of the time, but, there often comes a point when you actually do need to use a 0 value for that field.  There’s a number of other, more arcane reasons that using one of the values from the range of possible values of a type to indicate null is usually not a good idea.

Hence, nullable types. With a nullable type, I can have an integer variable that can be a 31bit positive or negative number, or 0, and STILL have yet another “state” of that variable that indicates it’s null.

This will likely be incredibly handy for many many uses when working with database data.

But the syntax?

Dim a As Integer?

or

Dim a? As Integer

No, I’m not making that up.

What the hell? A question mark?

Why not just:

Dim a As Nullable Integer

I find this to be an unbelievably hypocritical decision given the almost overwhelming philosophical rants delivered by Microsoft about not using the traditional VB type specifier characters in .NET anymore (you know, $ for strings, % for integers, those bad boys). Heck, check page 42 of “Framework Design Guidelines” by Krzysztof Cwalina and Brad Abrams of Microsoft:

DO NOT use Hungarian notation (their bold, not mine)

Now, to be fair, the authors in this particular instance are discussing publicly available interfaces, but I’ve seen the same directive applied to internal coding as well. So, we’re not suppose to use hungarian, and we’re not supposed to use type characters, so we’re left to simply scan the code to information about how a variable is used or what it likely contains. Jeez. How convenient.