An Ode to wfSpy

As I’ve mentioned before, I love user interface spying utilities and often find myself championing their use.

Today, I got a message from someone requesting the modifications we made to wfSpy. I’ve always wanted to publish them back to the community and tried to do so by contacting the original author. However, I never got any response.

wfSpy stands for Windows Forms Spy and so it is a spying utility for Windows Forms applications (and specifically for .NET 2.0 and forward). It is similar to Hawkeye, but is easier to use … and doesn’t have quite as much functionality.

We made several modifications to it but the notable two are as follows.

First off, a colleague (Don Kackman) of mine added the crosshairs ability. Take a look at the main window that comes up when you launch it.


If you click on the magnifying glass, drag it on top of a Windows Forms control, and release … the wfSpy properties window will then come up.


The wfSpy properties window shows all the properties on the control that you just selected … and not only can you view them … but you can also modify them (at runtime) as well!

The second notable change that we added was synchronizing the tree view (on the wfSpy’s main window) such that the control you selected … is the active ‘window’ selected.

This is extremely useful in the case where you have controls that are hiding other controls … and there is no way to select those hidden (or covered) controls with the crosshairs. In this case, you use the crosshairs to select the control you can select, and then you close the properties window and use the tree view to select the control you want. I would often turn the Visible property of a control on and off … to help me navigate through the tree of controls.

When utilizing the tree view synchronization feature … make sure you have a refreshed version of the current controls in the tree view … by clicking the ‘Refresh’ button on wfSpy’s main window. Otherwise, the synchronization logic might not be able to find the control (in the tree view) you selected.

So, without further adieu … here is the source code.

Hope it helps!


Leave a comment if it does help you … I always enjoy hearing that my efforts have actually paid dividends. 🙂


I have just (May 15th, 2012) pushed the sourced code to GitHub after receiving yet another request for the .NET 4.0 version.

It is at the following location:

39 thoughts on “An Ode to wfSpy”

  1. Hi,

    I need help about wfSpy. I already talked to you via CodeProject, in the same thread that leads to your wfSpy changes that you are making available through your blog.

    I’m wondering about just one thing:
    Why does wfSpy not work when you target the .NET 2.0 Framework like the source code in your blog? When running the application directly in Visual Studio, everything works fine … but if you click on the wfSpy.exe outside VS you always get:
    Access is denied (Exception from HRESULT:0x80070005(E_ACCESSDENIED)
    and you can’t get any properties at all! 🙁

    Note: I’m logged in as the computer administrator on Windows XP. The original version (.NET 1.1) from CodeProject is working correctly and stops working as soon as you change the framework from 1.0 to 2.0.

    Do you know why this is the case? Do you know how this can be fixed?

    This is a critical issue for my project. We use an heavily modified version of wfSpy and we can’t deploy it. The project has turned into a nightmare after days of trying to find a solution.


  2. @lsdisciples:
    It sounds like you are trying to spy an application that has been built with the .NET 1.0/1.1 Framework.

    The 2.0 version (the one that targets .NET 2.0) is unable to spy 1.0/1.1 applications. At least, I have never gotten it working … but then I haven’t tried too hard.

    I would suggest (if you want to use my version) that you retarget back to 1.0.

    Good luck!

    wfSpy is a debugging utility that was released on CodeProject. I do not know why you are ‘deploying’ it or what you even mean by that … but I’m sure this utility hasn’t gone through any extensive testing/quality assurance. Be careful about relying on it too much. It is only meant to aid software engineers.

  3. @cplotts:

    Sorry, more explanation is needed:
    First, I know almost any single line of code in wfSpy. I built a huge application based on the wfSpy example.

    I’m just wondering why we get an access denied error when we run the application (yours and mine) outside Visual Studio.

    – Simply double click on the .exe and try to spy any 2.0 application (SAME .NET VERSION) with the details button.
    – Access denied, nothing works!
    – Replace the hooking .dll in the bin directory with the one from CodeProject (version 1.0).
    – It works now!

    The problem is that upgrading the C++ hooking .dll from 1.0 to 2.0 causes the access denied error.

    My post was just to let you know that your version is not working in any way when you run it outside Visual Studio, and I’m wondering if you know why the upgrade of the hooking dll causes this problem.

    Anyway, for now, I am going to simply replace the dll so that it works.

    By the way, I’m now working on an injected library (targeting the .NET 3.5 Framework and forward) to support WPF control details displayed in a WPF property grid. Once injected in the process … this can be easily done, right?

  4. @lsdisciples:
    I don’t know why you are having problems … I don’t recall that I’ve ever had a problem spying .NET 2.0 applications with the .NET 2.0 version of wfSpy. I _have_ had problems trying to spy .NET 1.0/1.1 applications with the 2.0 version of wfSpy, though.

    So, again, it seems like it is working for me … however, given your experience, I will try again.

    What does your application do? The one you’ve built based on wfSpy?

  5. @lsdisciples:
    I don’t know if you are aware of Snoop ( … but this is the utility I use to spy WPF applications. It rocks!

    Of course, one application to spy all along the .NET Framework (1.0, 2.0, 3.5, 4.0 and all along the different technologies (Windows Forms & WPF) would be awesome!

  6. So, you confirmed it works for you, IF you double-click the application instead of running the application in Visual Studio?

    Very very strange. I can’t see any logical reason for having an access denied error on my side just because the C++ dll was built with VS2005+.

    My application is a kind of spy tool in a software testing tool suite.

    I’m aware of Snoop, Woodstock and other projects but I need to learn more about these since I have to add WPF capabilities into my own application (in the injected code … in order to get the PresentationSource from the handle).

  7. @lsdisciples:
    I just checked (as I said I would) and successfully spied a .NET 2.0 application with wfSpy (running it outside of Visual Studio).

    So, it works as I said it does … and yes, it works even if I run the application outside of Visual Studio.

    Is this software testing tool going to be available for sale? Or are you building it for internal use somewhere?

  8. @lsdisciples:
    Ok, I just tried spying a vanilla .NET 2.0 application (with my .NET 2.0 version of wfSpy). It didn’t work!

    A coworker reminded me that it might be an issue with 64-bit … and it was. Let me explain.

    When you create a simple Windows Forms application with Visual Studio, the default project template … builds that application with the ‘Any CPU’ build configuration. On a 64-bit operating system, this application runs as a 64-bit application (and on a 32-bit operating system it runs as a 32-bit application).

    wfSpy, however, has not been updated to work with 64-bit applications (it simply might be an exercise in building the hook dll for x64).

    All of this … is to suggest to you … that your problem might also be a 64-bit issue. Are you compiling the application you want to spy as ‘Any CPU’ and then running it on a 64-bit operating system? If so, wfSpy won’t be able to spy it (at least out of the box).

  9. @cplotts:
    THANKS, I really appreciate your help.

    Yes, my application will be available for sale … I’ve been working on this since 2007. I’m hoping the year 2010 is my last year before finally releasing.

    Hmm … lots of questions come to my mind now:

    Question 1: Can the original wfSpy can be run on 64-bit? Can your modified wfSpy (Any CPU) be run on 64-bit?

    (I’m currently using XP … so I haven’t even tried my application with Vista or Windows 7.)

    Question 2: According to your comments, the hooking dll must be built for x64. Where do you set that on a C++ project? The only option I see is “Detect 64-bit portability issues” but must be something else. I suppose the entire project (wfspy, lib and hooking dll) must be built for x64 in order to run it on 64-bit machine?

    About my problem with the hooking dll … x64 is not involved in my case. The only thing I know is that the original dll (built in Visual Studio 2002-2003) works perfectly while the same dll built in VS 2005+ never works. If that dll must be built for x64, then this will be a MAJOR issue since I haven’t been able to do that … without creating an unusable dll (the access denied error).

    Sounds like I’m in big trouble. Can you at least confirm if wfSpy can spy on 64-bit operating systems and if it can run on Windows7? If not, specify the configuration changes needed if possible.

    Thanks for your time!

  10. @lsdisciples:
    In regards to question 1: yes, the original wfSpy should work just fine on 64-bit operating systems. It will run as a 32-bit application and will be able to spy 32-bit applications only, but it will work. And of course, the same thing applies to my version of wfSpy.

    However, you ask about wfSpy (Any CPU). This is an important point. The C++ hooking dlls (and all C++ projects) can only run as x86 or as x64. There isn’t a Any CPU build configuration for them. Thus … you need to build all the projects for x86 or x64 in order to get it to work reliably. If you don’t, then then Any CPU projects will run differently depending upon which operating system (32-bit or 64-bit) you are running on … and you will have a potential mismatch.

    In regards to question 2: you need to go into the Build menu and select Configuration Manager. It is in this dialog that you are able to create a completely separate ‘Solution Olatform’ for x64 … where you build the projects for x64.

    wfSpy can definitely run on 64-bit operating systems. It can also spy applications that are running as 64-bit applications … however, in order to do so, you will need to build a separate version for 64-bit and use that version to do the spying. You can not hook a 64-bit application with the 32-bit hooking dll.

    Finally, wfSpy works on XP, Vista, and Windows 7. I have not seen any issues where it doesn’t work due to what operating system you are running it on.

    By the way, I have no idea you are having so many problems with getting your version of wfSpy (or even the original version) to work outside of Visual Studio. You’re on your own on that one. The final thing I can offer there is that it seems as if XP might have some oddities in this regard. Check out the following Snoop discussion. Some users of Snoop have reported needing Admin rights in order to Snoop things on XP. Maybe your issue and that one are related. I would also suggest trying your stuff on Vista and Windows 7 to see if this problem goes away.

  11. For my Snoop x64 hooking dll … I did have to manually set the Linker->Advanced->Target Machine option manually to MachineX64 … but if you go through the Build->Configuration Manager properly … it will set this option for you.

    But, you can definitely check this setting to make sure everything is set up correctly! 🙂

  12. Thanks again, Cory.

    The information provided is really useful. I feel more confident with the wfSpy hooking “engine” used in my project since you answered to all my concerns about it. Having a chance to talk with the Snoop author about wfSpy was unexpected since the wfSpy author is unreachable. So again, thanks for you time and for sharing your knowledge with other people like me :).

  13. Still working on this! ;o)

    I’m wondering one thing about Snoop. What are the main reasons why Snoop cannot spy on a Silverlight application?

    I want to support Silverlight also in my application, any starting point or suggestion?

    Thanks again.

  14. @lsdisciples:
    Hey there. I have gotten more than one query about Snoop and Silverlight. 😀

    I have not played with this at all … but obviously, it would be awesome if Snoop could also spy Silverlight applications. Hmmm. I just created a work item for it.

  15. I assume WPF and Silverlight are “almost” the same exact thing for a spying application. So missing Silverlight support is likely not caused by something too drastic. We are at the same point on this. I’m also planning to take a look at this sooner or later. ;o)

    Thanks again.

  16. Looks more complicated than expected … I will forward to you any interesting information on this, but for now, after two days spent on this, I can’t even find a starting point. 🙁

    We know it’s possible since Silverlight Spy exists. Having a chance to see an older version with available source code would be useful.

    I posted the following message in the WPF and Silverlight newsgroups, but nobody seems to be able to answer this simple question:

    Tonight I will take a look at the IHTMLDocument2 interface since the root visual seems to be available on the JavaScript side. I’m also going to explore different things inspired by the HTML document spying part of my application. I will also play with different framework versions of the injected code to make sure HwndSource.FromHwnd is not failing because of the framework version used.

    Silverlight seems to use it’s own mini framework which is not a part of the .NET Framework (i.e. the Silverlight dll is not stored in the normal .NET Framework directory). Silverlight Spy seems to not use any “injector” and uses a client browser in the application … so my guess is that the solution is more on HTML side.

    Sorry, but I’m totally confused on this … and I’m just trying to finding a starting point. Will share the solution if I can find a way to get access to the application.

  17. I’m not surprised that it isn’t simple. Good luck and again, keep me up to date.

  18. I’m exclusively working on Silverlight support since my last post.

    I think I finally found a way to hook into a Silverlight application. Seems like there is no “clean” way to do it.

    The way the Silverlight object is created on the page must be overrided. If the object is created using JavaScript, the content (managed) of the object will be available in JavaScript. The rest can be done using an IHTMLDocument interface to inject and run JavaScript on the page.

    A blog post from Jaime Rodriguez was really useful to understand how to play with the Silverlight object at runtime.

    This early version only supports Silverlight object with content starting with instead of. This can be easily adapted/modified in the code. Since it supports 1.0, I should be able to gradually support all possible Silverlight versions.

    Tomorrow, I will try to prove my theory:
    1- Use a BrowserHelperObject ( 🙁 ) or a custom Client browser to override the Silverlight object creation before the content is sent to Internet Explorer.
    2- “Inject” a modified version of the EarlySnoop example (I already extracted the interesting JavaScript and adapted it to work with Silverlight tool 2.0)
    3- Get an IHTMLDocument interface to send JavaScript instruction to the page at runtime (with execScript or by manipulating the HTML document at runtime).

    Send me an email if you would like to get this first “Hello World” working prototype when it is completed.

    Note that this will be very, very, very far from a final solution. It only shows how it can be done. My application is not only a spy tool … and so the example will better fit your needs … and give you something to start with.

  19. I tried to send you an email … but please send the prototype when you finish it. I would love to add this ability to Snoop.

  20. Hi,

    Is any update regarding `wfspy version that support injection WPF applications?



  21. In case anyone comes looking for a .NET 4.0 version of wfSpy … please note that the code attached to this blog post doesn’t work for .NET 4.0.

    My plan is to one day upload the code to CodePlex … but until that day happens, if you need the 4.0 version, contact me directly and I will email it to you.

  22. Hey Cory,

    I’m interested in having a 4.0 net version of wfSpy … can you send it to my email?

    My application uses an approach similar to wfSpy methods, like you know. I have built my application in Visual Studio 2010 (.NET 4.0), and not it will not work on a Windows XP machine (without installing Visual Studio). It waits forever for the injected dll to respond.

    I want to proove that your upgraded version of wfSpy has the same problem … and use it as a demo generic package to get help on a newsgroup. Everything works when compiled with .NET 3.5.

    By the way, your help on my x64 issue was extremely useful!

  23. Hey Cory.

    Did you ever get around to posting the .NET 4.0 code onto CodePlex? I’d like to see what changes were made to the wfspyhook assembly to get it to work.


  24. @Chris, no, I haven’t yet. But I really should do so … as the original author did finally get back to me.

    I will try to push it out today … but I will be putting it on GitHub and not CodePlex.

    I will post a link here … when I do put it up.

  25. Hi, I would like to ask to you if it’s possible to have the executables for wfSpy, because I use VS 2012 and the source doesn’t compile in this environment.

    Thanks in advance!

  26. Hi there, could you please sent me a copy of the executable based on 4.0 as well? Thx in advance!

  27. Hello Cory,
    I hate to bother you on the subject, yet the binaries I build do not seem to be running correctly.

    I can actually run the executable, but when pressing “Details” (no matter on which window) I get a BadImageFormatException. The case is wfspyhook.dll cannot be loaded. While investigating it with DepWalker, I can see that wfspyhook fails to find many dependencies of Kernel32.dll, User32.dll etc., like API-MS-WIN-CORE-LOCALIZATION-L1-2-1.DLL.

    I tried upgrading the C++ project for it to use a later platform toolset, or to set another .NET version. No success, though.

    Is there a way for me to build a running version of WfSpy? Maybe I should install some VC++ redistributables, etc.
    I use Windows10, 64-bit version, and VisualStudio 2013.

    Or rather, if that’s possible for you, could you please send me the binaries with the correct dependencies?

    Many thanks in advance.

  28. Olga,

    I think you will need to build the 64-bit version of the binaries … if the application you are running is a 64-bit application. That would be my speculation why it isn’t working for you. And, of course, you will need the correct VC++ redistributables.

    Good luck,

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.