AQtime Tackles the Problem
In Delphi 2006, Mark recently ran into some very unfamiliar code with a difficult to debug drag-and-drop problem. He had absolutely no idea where or what that code problem was. "I hadn't debugged drag-and-drop code, and I'm sure anyone who has appreciates the challenges of using the debugger to figure out what is going on during a drag operation. The big problem is that if you want to set a breakpoint in the code that executes when the drag operation begins, you won't be able step though all of the code that needs to execute to complete a drop operation because the mouse messages will not be processed properly by the application while it is stopped in the debugger. As soon as the breakpoint hits, your drag operation is basically cancelled."
"The bug I was working on was being unable to rearrange items in the tool palette using the mouse. On certain systems, the tool palette would simply not allow dragged items to be dropped."
"In this situation, the Delphi IDE uses "OLE" drag and drop which means much of the code that executes during a drag operation is invoked by callbacks from the operating system. Since this callback is called indirectly, it is more difficult to identify. It's awfully tough to set a breakpoint on a line of code when you don't know where it is! The problem was further complicated by the fact that code that should have been executing wasn’t getting called, so even if I knew where to put the breakpoint it wouldn't have worked."
"I decided to use AQtime to tackle this problem. Not only is it a powerful code profiler, it is also a very useful debugging tool. The results it generates show which functions are called, how many times they’re called, and how long each call takes. In addition, it provides a call stack that clearly shows which functions call other functions. Another nice thing about the call stack that AQtime provides is its “static” nature. You don’t have to be sitting on a breakpoint with the program running to review it as you normally would with a debugger."
Debugging with AQtime
Mark found a system that was not affected by the bug and profiled the drag and drop operation. "This gave me a "good" set of profiler data. I copied the results to a system that couldn’t perform the drag and drop. Using the same AQtime project with the good results, I executed the same steps, which failed, under the profiler. This gave me a “bad” set of profiler data. I then used a feature in AQtime which allows you to compare these two sets of results. That allowed me to quickly see which methods were not being called on the computer affected by the bug. Finally, I analyzed the call stacks from each profiler run to determine where the execution paths diverged."
At this point, Mark had the information he needed to jump back into the debugger and set some breakpoints and figure out exactly what was going wrong. "This took me just a couple of minutes, now that I had a clear picture of what the expected code path was. From there I made a few code changes to fix the bug. I'm sure there were probably other ways I could have attacked this bug, and had I gone into this exercise with more background in drag-and-drop code I probably would have known right where to look for the problem without any extra help. Fortunately, having AQtime in my toolbox I knew I could get the job done with this approach."
"It's incredibly useful to have a “static” call stack that you can examine after the fact. You can walk up and down the stack and review the associated code in the code editor window and review any part of the profiler results without having to run the program. Another big advantage of the call stack AQtime provides is that it traverses the .net managed/unmanaged code interop boundary showing you a full picture of the code execution. The IDE debugger only allows you to see either .net or Win32 calls in the call stack, not both.