יום שלישי, 25 באוקטובר 2011

Snoop - The WPF Spy Utility





What

A random utility made to simplify visual debugging of WPF applications at runtime. It's basically a collection of things that may have seemed useful at one time or another with the common goal of making it easier to track down bugs in WPF applications.
This is not an official tool, just a utility that was found useful and added to when functionality was needed. It's provided in the hopes of helping others.

Usage

Run Snoop.exe. Once it has started it will display a list of all running WPF applications. If your target app is not running yet, just launch it then refresh the list with the Refresh button or by pressing F5. Snoop will automatically find all WPF processes running on the machine to attach to.
Once the application to be snooped is selected, click the Snoop icon ()to launch Snoop.

Troubleshooting

Recently, there was logging ability added to Snoop to see why Snoop does not attach on certain machines. Currently this is not in the release build, so the latest code will need to be downloaded and built for troubleshooting purposes.
If nothing happens when trying to snoop a program, take these troubleshooting steps (Note that logging is not added in the latest release, so you'll have to download the latest code and build it):
1) Go directly to the folder containing the Snoop.exe program being run.
2)  Look for the file SnoopLog.txt in the directory of Snoop.exe (from step 1), and open it. Make sure that the contents of the file are similar to this:
10/09/2011 19:06:02 : Starting the injection process...
10/09/2011 19:06:02 : GetModuleHandleEx successful
10/09/2011 19:06:02 : Got process id
10/09/2011 19:06:02 : Got process handle
10/09/2011 19:06:02 : VirtualAllocEx successful
10/09/2011 19:06:02 : SetWindowsHookEx successful
10/09/2011 19:06:05 : Successfully injected Snoop for process SnoopTestCase.vshost (PID = 7548)
(Make sure that the file ends with "Successfully injected Snoop for process processname (PID = process id)"
If the test above does not pass, contact one of the developers/coordinators (or post to a Discission), and specify what the results in the file are. If the test above passes, it means that Snoop successfully injected itself into the process being "snooped," and the problem lies in the part after the injection process. After Snoop has successfully injected itself into the process, it's running inside the process, and can write to the output window of the debugger debugging the process. At this point, look at the output window of the WPF application being debugged (and attempted to be snooped). The output window should have contents similar to this:
other messages written to output window
Got WM_GOBABYGO message
other messages written to output window
acmLocal = C:\XXX\Snoop.exe$Snoop.SnoopUI$GoBabyGo
other messages written to output window
About to load assembly C:\XXX\Snoop.exe
other messages written to output window
About to load type Snoop.SnoopUI
other messages written to output window
Just loaded the type Snoop.SnoopUI
other messages written to output window
About to invoke GoBabyGo on type Snoop.SnoopUI
other messages written to output window
Return value of GoBabyGo on type Snoop.SnoopUI is True
If you don't see the messages above, try doing this: right before trying to "snoop" your application, try setting Visual Studio to break on all CLR exceptions.
Here are the steps to doing so:
1) Go to the Debug menu in the Visual Studio instance debugging your application.
2) Choose the "Exceptions" menu. An exceptions dialog box should show up.
3) Check "Common Language Runtime Exceptions" under the "Thrown" column.
4) Now try snooping the application. If the SnoopLog.txt contains the contents mentioned above, Visual Studio will break when there's a problem trying to snoop the application. From there, you can use this information to try to troubleshoot (or you can post the information on a Discussions panel, and a developer/coordinator will get back to you).

Building

Snoop.csproj can be built using VS Express, but the complete solution requires the C++ compiler found in full VS. The C++ portion of the solution is provided pre-built and has no WPF dependencies, so you should not have to rebuild it to run.
If any of the ManagedInjector (orManagedInjectorLauncher) projects fail to build, try unloading them from the solution, and rebuild the solution. Snoop detects the environment at runtime, and depending on the environment, Snoop runs the appropriate ManagedInjectorLauncher program at runtime (which is the one that probably built successfully) depending on the environment. For example, if the application that snoop is trying to snoop is built using the 4.0 framework built for the 64 bit process, snoop will run the ManagedInjectorLauncher64-4.0.exe program to inject Snoop into the application, and start "snooping" it. Therefore, if the other ManagedInjector projects fail to build (probably because of an environmental issue), it won't affect snoop at runtime.

Primary View

Graph of the visual tree on the left, list of properties on the selected element in the center, common events & preview area on the right
The selected element will highlight with a red adorner in the target application. Another way of finding elements in the tree is to hold down Ctrl-Shift and mouse over the target application. This will move the selection to the element under the mouse.

Tree View

Navigate the visual tree using this view, F5 will refresh the list of elements. The text on the left is the element name, in brackets is it's type, and on the right is the number of child elements it contains. Number of child elements is quite useful when focusing on performance and trying to keep the element count to a minimum.
If you're tired of searching through debug spew for binding errors, they can be searched for using the drop down beside the filter box.

Property Grid

Lists all the properties on the currently selected element. Writable properties may be edited in the value area. Also displays where the property was picked up from.
Right click will show options to Delve (inspect the value). If the property is a binding then the binding and expression can also be inspected. Useful for debugging those binding errors.

RoutedEvents View

Preview Area

(off by default, for perf)

Zoom View

(accessed from zoom button in Preview Area)
Use mouse wheel to zoom, double-click to reset zoom.  Slider at the top changes the brightness of the background color. +/- keys may also be used to zoom the view.