Native or Psuedo-Code VB6?

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


  1. Ralf says:

    Whoa. [/Neo] Very very cool. Thanks!

    Re: Native or non-Native Compiling

    For large projects I *always* use p-code. Not just because of the reasons you cite (all true) but because at some mysterious point the compiled code stops acting 100% the same as the IDE. Makes troubleshooting surreal. The native compiler does an impressive job of duplicating the p-code, but at some stage of size / complexity the illusion breaks down a bit.

    Also, some things run wayyy faster in p-code than native. Gosub/Return structures are one example. And unless you’re really crunching some numbers, most of the VB primitives are already compiled & optimized, so does it really matter if the code invoking them is native or pseudo? I think not.

    Oh, and here’s the code I use to detect the IDE, exploiting the fact that Debug.Assert is stripped from the runtime:

    Function InDesign() As Boolean

    On Error Goto Error1
    Debug.Assert 1 / 0
    Exit Function

    InDesign = True

    End Function

  2. Darin says:

    I used a technique almost exactly like that for years, until it bit me once.

    That approach clears the err variable, which, in some cases can cause error handling code elsewhere to fail in very subtle (and difficult to track down) ways.

    You’re right about the speed differences, for most apps, p-code or native won’t matter that much. To truly get high perf out of native code, you need to apply optimizations in the right way to the right code. Way more work than it’s generally worth, when much of the UI and crunching code is in libraries anyway.

    I don’t recall ever running into any serious diffs between native and p-code when debugging, but I can easily imagine it.

    I’ll have to keep my eye out for that.

Post a Comment

Your email is never published nor shared. Required fields are marked *