Last time, we started sneaking around the object viewer in the debugger. We learned neat tricks like the ability to switch how we view integer data, as well as seeing that the object viewer shows you more than just intrinsic data.
Today we're going to see some more of the powerful object viewers. And we'll start out with the one which lets you see everything. Take out our scratch program and hit Run. Before clicking the pushbutton, let's learn a new quick trick. Let's say your application is running in a loop somewhere, and you want to know where it's running without having to hunt around (this trick works great when you get stuck in infinite loops, I might add). Then you can use the Pause toolbar button! Go back into the IDE and click the toolbar button that says Pause. You'll now see that the stack viewer says we're in the "event loop" -- this means that your user code isn't running, the framework code is. Go ahead and hit Resume.
Now click the PushButton -- your breakpoint should still be set on the MsgBox line in the Foobar method (if it's not, you can go into the IDE and set it now). We're back to the old, familar debugger window. The very first link in the object viewer is the one we're after -- it's called Globals. If you click it, you're in the Globals viewer, which shows you the state of everything in your current application. It shows you things like threads, sockets, windows, and even modules. Basically, it shows you everything that your application can possibly access. So let's do a little exploring.
If you click the Runtime link, you'll see the Runtime object viewer. If you remember, the Runtime object is an intrinsic module which shows you information about everything in the running application. If you look at the ObjectCount property, you'll see that the Runtime has 23 active objects right now.
Clicking the Contents link will show you the "contents" of the Runtime object. Before I continue on, I want to go off on a tangent at this point. You should get used to seeing "Contents" links and make good use of them. Many objects will have a contents link and a lot of the power of a software debugger is in the ability to get the most information from objects. We'll check out some useful ones in a while. In any event, let's get back to the contents of the Runtime object. You'll notice that there are a bunch of items that the framework has active which you may not be aware of: a Screen object, an MDIWindow, etc. You shouldn't worry too much about what items are in here (there's a reason behind every single one) -- but you should notice that some very important objects are in here such as Window1, the PushButton instance, etc. From this one viewer, you can get to any "live" object in your application. However, as your application gets more complex, this viewer becomes harder and harder to navigate. Imagine an application with 30 windows (many of which are hopefully hidden) and dozens of controls on each -- pretty scary eh?
Let's check out an easier way to get information about specific window instances. Click back on the viewer switcher and go to Globals again. Now click on the disclosure widget for Windows. Now you can see a list of all the windows that are active in your application. The only object you'll see is the reference to Window1 -- however, when you've got 30 windows in the application, it's nice because you can see only the windows and not any of the extra stuff (like the controls on the window). But if you want to see the controls on the window, never fear -- the Contents link is there to help you out!
So let's modify our scratch program a bit to see some more Contents goodness. Stop the debugger, and add the following method to the window:[rbcode]
Sub Awesome()
dim mb as new MemoryBlock( 8 )
mb.Long( 0 ) = &h12AB34CD
mb.Short( 4 ) = 12
mb.Byte( 6 ) = 255
mb.Byte( 7 ) = 127
Break
End Sub[/rbcode]
Then call Awesome before calling the Foobar method in the PushButton1.Action event. Now run the application and press the PushButton. The first thing you will notice is that we used a new keyword called Break -- and it's entire purpose in life is to break into the debugger. In a built application, it does nothing -- this call only matters in debug applications.
Now let's click on the MemoryBlock variable in the object viewer. You'll see that it tells you a small amount of information about the data block -- it tells you what the endianess of the block is as well as the size. That's not too helpful, what you really need to know is the information that the MemoryBlock contains. So let's click on the contents link and see it! Ta da -- you're presented with a typical hex canvas that shows you more information. The far left-hand part of the pane is the "address" or offset that the data is at. The middle of the pane displays the data in hexidecimal form (each colum represents a single byte). The far right-hand side of the pane is displaying the "text" of the hex data, which oftentimes can be non-sense, as in the case of our data.
Let's take a look at one more data viewer before we move on to other areas of the debugger. At this point, you should download the new scratch project and check out the Awesome method -- it now has a "complex" array that contains multiple types of objects. It's a contrived array, but it'll demonstrate what we're after -- the array viewer.
Run the project and click the PushButton to drop into the debugger again. You'll notice the woot array in the object viewer, so click on that. What you should see now is a list of all the controls in the array. You'll notice that it shows you the actual type of the object, not RectControl (which the array is declared as). and that you can view the contents of the items in the array. But there's also a neat new feature -- the view property selector. This lets you view any properties common to all the items in the array within the array viewer itself. So if you're looping over all the entries in an array to check a specific value, you don't have to click on each item -- you can just select the property you want to view in the selector and it'll be displayed. Let's try it -- select Handle from the view property selector and you'll see the second column fill up with the various Handle property values (you may need to refresh the list by scrolling it -- this is a bug). What's even more neat is that the debugger is smart about these little touches and will remember that the local variable named woot has this option set -- so if you stop debugging and restart it following the same steps, you'll see Handle selected when you view woot.
So I think we've seen enough about the various object viewers, and the lesson you should have learned from this is that the Contents link is your friend, and you're able to see the state of your entire application just by delving through the various links in the debugger. Next time we'll take a look at applying this knowledge to tracking down a bug and eliminating it.
That memory block debugger came in very useful when I was writing the code to handle NTLM proxies. I finally finished it after tracking down several tricky bugs, thereby getting a 100% RB native implementation of the NTLM HTTP proxying protocol.
Aaron, if you ever have spare time and want to implement NTLM in REALbasic's HTTPSocket, let me know and I'll send the source and a whitepaper. NTLM is used quite a bit in schools, big companies, etc. where Microsoft servers are common and security is important. It would be a great addition to REALbasic.
Yeah, I've been pushing for some other MemoryBlock viewer improvements (like the ability to view arbitrary memory, like memory returned from a declare). So hopefully it'll only get better!
NTLM support would be a very interesting thing to support in RB -- how does it work with the HTTPSocket though (you can email me off-list to discuss it); what sort of API would it use?