Visual Basic P-Code

[Previous] [Next]

Experienced developers know all about Visual Basic's p-code, but I want to make sure that everyone understands exactly what happens when a Visual Basic application executes. I also want to be sure that you know the ramifications of debugging Visual Basic applications. As with other aspects of debugging, understanding how the debugger operates can help you out tremendously when you're experiencing problems. To help set up your frame of reference, I need to start with a little history lesson.

A P-Code History Lesson

Visual Basic 1, introduced in 1991, was an intriguing advance in programming tools. In the early 1990s, if you did any Microsoft Windows development at all, you had to write your code in C at the SDK level, which was generally a painful experience. Visual Basic promised, and mostly delivered, the ability to draw your user interface (UI) with a What-You-See-Is-What-You-Get (WYSIWYG) tool and an easy way to connect code to user events such as clicking a button. The unusual twist in Visual Basic 1 was that it didn't compile the final applications to native executables but to a form called p-code.

P-code, short for "packed code," was a method of reducing the memory footprint for binary files—p-code is much smaller than regular Intel x86 assembly language. When you "compiled" your applications in Visual Basic 1, you produced a regular executable, but that was just a shell around the p-code. When the "compiled" binary started, the run time started, hunted down the p-code at a specific offset in memory, and started executing the p-code. As everyone knows, the large run-time dynamic-link library (DLL) VBRUN100.DLL, which contained the p-code interpreter, also had to be shipped with your application.

The p-code interpreter is a stack-based engine that translates the special opcodes into operations on the CPU. Microsoft used to offer the ability to generate a different form of p-code as part of C/C++ version 7 back in the days of MS-DOS and 16-bit Windows. In fact, the original 16-bit versions of Microsoft's Word, Excel, and PowerPoint products used the p-code in C/C++ version 7 extensively in their UI code to achieve the size-to-performance trade-offs necessary to make those applications run on the limited memory systems available when Windows 3 and 3.1 were released. You can search MSDN for the "Microsoft P-Code Technology" topic to get an idea of the implementation of p-code in C/C++ version 7, which is probably close to the implementation of p-code in Visual Basic.

All versions of Visual Basic from 1 through 4 generated only p-code. The biggest problem with using p-code was that it was slower than native code. The old joke was that you could tell a Visual Basic application from a mile away because the application was slow and it used three-dimensional text controls for all the buttons. Although Microsoft couldn't do anything about the developers' choice of controls, it did heed the number-one plea of Visual Basic developers: "We want native code generation!"

Starting with Visual Basic 5 in 1997, Microsoft added an option that allowed you to produce native code as part of the compilation process. Microsoft developers also rewrote the Visual Basic run time to make it faster. The result of both changes was a fantastic performance boost for Visual Basic applications. The only hitch was that Microsoft just grafted on the native compilation feature to fulfill a bullet point on the feature chart rather than completely integrating the compilation and debugging with the Visual Basic IDE. After you compiled your application to native code, you were completely on your own to debug it. As I discussed in the section "Debugging Visual Basic CompiledCode" in Chapter 5, Visual Basic binaries don't have sufficient debugging symbols, so you're almost forced to debug raw assembly language.

The biggest hole in the native compilation feature is that the Visual Basic IDE understands only interpreted p-code. Thus, what you're debugging with the Visual Basic debugger, p-code, isn't what you're building, native compiled code. From a debugging and testing perspective, the situation is troublesome—even if you choose to compile to a p-code binary, you're still not debugging the exact bits you're sending to the customers. Unfortunately, other than suffering through debugging your compiled Visual Basic binaries under the Visual C++ debugger, there's nothing you can do about the situation. We can only hope that a future version of Visual Basic or Microsoft Visual Studio will rectify this problem so that we can debug exactly what we're shipping to our customers.

Ramifications of Using P-Code

Recall that in the section "MinDBG: A Simple Win32Debugger" in Chapter 4, I talked about how much more stable debugging is under Win32 systems than it was in 16-bit versions of Windows because in Win32 systems the debuggee is outside the debugger's address space. Because the Visual Basic debugger understands only interpreted p-code, the upshot is that your Visual Basic debuggee runs in the same address space as the debugger. As most developers who have used Visual Basic have found out, although Visual Basic doesn't have the pointer problems you can encounter in C, an errant component your application loads can crash the Visual Basic IDE, causing you to lose parts of your project.

The following three concrete rules have helped me maintain my sanity when using the Visual Basic debugger:

  • Be very, very careful when subclassing or using AddressOf.
  • In general, treat source code as read-only when debugging.
  • Don't use the rest of the IDE when debugging.

Be Very, Very Careful When Subclassing or Using AddressOf

Most Visual Basic applications run fine under the debugger. However, if your application is subclassing Windows controls or you're otherwise using the AddressOf operator to pass one of your routines as a hook callback or timer procedure, you must be extremely cautious because your application runs in the same address space as the Visual Basic debugger. You can still debug your application, but you must be aware that callbacks and timers can still execute after you've stopped your application, causing the IDE to crash.

If you're subclassing a window procedure and you're in break mode inside the Visual Basic debugger, when the window you've subclassed receives a message, the IDE will crash. Fortunately, because subclassing windows is such a common operation, Microsoft provides a solution with a utility DLL named DBGWPROC.DLL. This DLL allows you to subclass windows at will and still debug your application using the Visual Basic debugger. You can download DBGWPROC.DLL from http://msdn.microsoft.com/vbasic/downloads/controls.asp.

If you're using the AddressOf operator to pass one of your application's routines to any hook, callback, or timer functions in the operating system, there's nothing like DBGWPROC.DLL to help you out. If you do want to debug your application with the Visual Basic debugger, you can. However, you should always run your application to completion so that any hooks and callbacks can be undone. If you use the End command on the Run menu or Ctrl+Break to stop your application, you can encounter situations in which your procedure is no longer in memory, so the IDE crashes.

Another technique I've used to circumvent the AddressOf problem is to have a debug function that cleans up any hooks, callbacks, or timers that I can call either from a special button in my application or through the Immediate window. With such a function, I stand a better chance of avoiding errant calls into my application that could crash the IDE.

In General, Treat Source Code as Read-Only When Debugging

The Visual Basic IDE is set up to make it easy to edit your source code and continue execution during your debugging sessions, and many Visual Basic developers feel that this capability is one of the debugger's best features. As great a perk as being able to edit code during a debugging session might be, however, you still must proceed with utmost care when you do it.

You should set the IDE option to save all your source files automatically when you start your applications in the debugger by checking Save Changes on the Environment tab of the Options dialog box. If you're revising your source code on the fly, you should frequently save your changes in case the Visual Basic debugger crashes. Personally, I don't make any changes while my application is running in the debugger, and I advise you not to either. I believe that when you're in the debugger you should be debugging, not editing. With this feature, it's just as easy to add a bug as it is to remove one, so you should avoid the temptation to debug and edit simultaneously so you don't work at cross purposes.

Don't Use the Rest of the IDE When Debugging

Because the IDE is doing all the work to run your application when you're debugging, you can cause some problems for your application if you try to access nondebugging features in the IDE. For example, if your application uses a timer notification for background processing, you can stop the timer messages from getting through to your timer procedure if you bring up a modal window such as the Open Project dialog box or the Options dialog box.

When debugging in the Visual Basic debugger, just use the debugging windows supplied. If you have specialized code such as timers or modeless dialog boxes, any additional interaction that you have with the IDE can result in predicaments in which your application is receiving messages that aren't a normal part of the application process. Additionally, because your application's windows are part of the same thread message queue as the IDE, in certain cases you can't easily debug with the debugger because of the tight interaction between debugger and debuggee. The worst of those cases is if you need to debug a key down or a mouse down message. In those situations, you can use only Debug.Print statements to debug your code.



Debugging Applications
Debugging Applications for MicrosoftВ® .NET and Microsoft WindowsВ® (Pro-Developer)
ISBN: 0735615365
EAN: 2147483647
Year: 2000
Pages: 122
Authors: John Robbins

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net