In previous posts I mentioned the Fusion log viewer (FUSLOGVW.EXE). Now it’s time to talk about how to use it.
It’s important to realize that there are already a lot of sites that talk about this tool, so this isn’t the final word on it, but I’ll focus on the parts that I’ve found useful when debugging assembly load problems. If you’re interested in other sites, here are some good ones: MSDN Article on the tool itself and Junfeng Zhang’s blog about fusion logs.
Using the Fusion Log Viewer
The first thing is to get the logger to record all log attempts – not just failures. The reason is that in certain cases (such as when the assembly is found via an assembly resolver) Fusion first fails to find the assembly, logs the fact, and then tries another track and succeeds. Thus, just because you see a failure doesn’t mean there was one.
Standard Warning – This involves editing the registry. Please be extra extra extra extra…big breath…extra extra extra careful when editing the registry. Do the right things wrong and you will be reinstalling your operating system.
First fire up regedit.exe and go to HKLM\Software\Microsoft\Fusion. If ForceLog isn’t in that key, create it as a DWORD. Either way, it should be set to 1. The next value you can also set via the GUI but you are here anyway, so go ahead and set the LogFailures to 1. Close regedit.
Warning: You are now going to be generating a lot of log entries. You might want to turn on ForceLog only when debugging a problem.
Now fire up the logger (FUSLOGVW.EXE) and click Delete All. This is mainly to start with a clean slate. Unfortunately the logger is a bit primitive and so it can be difficult to follow the log messages (for example, you can’t sort by date/time of the entry). Best to start with a clear slate.
Now go back to your application (I’m assuming that if you are reading this blog that the app would be LabVIEW calling .NET) and run it. Switch back to the viewer and hit refresh. For the sake of this discussion, I am running LabVIEW 7.1 under Windows XP and running the calculator example.
You’ll now see several entries of all assembly loads that took place. Again, the viewer is a bit primitive so it’s hard to tell what worked and what didn’t. But you can see some important information. First, notice that for a LabVIEW application, there are different “Application” names that are all LabVIEW. The obvious one, LabVIEW.exe, represents the DefaultDomain AppDomain and is where we do all of our edit mode reflection. Calculator.vi is the AppDomain where the VI itself is running.
Another important thing to note is the Load() and LoadFrom() assembly bindings that are going on. If you remember from my previous post, LabVIEW uses both techniques to pull in assemblies and you can see that here. Anytime you see the regular, full name of the assembly in “Description”, you know that you are dealing with a Load(). If you see either WhereRefBind or something like “file://” you are dealing with LoadFrom().
So, here is a good example of failure followed by success. Notice that in LabVIEW.exe there is an attempt to load DNDomain, Version=18.104.22.168. etc. etc. If you double click on that, your browser will pop up and display something like
*** Assembly Binder Log Entry (3/24/2005 @ 9:26:41 AM) *** The operation failed. Bind result: hr = 0x80070002. The system cannot find the file specified. Assembly manager loaded from: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\fusion.dll Running under executable C:\Program Files\National Instruments\LabVIEW 7.1\LabVIEW.exe --- A detailed error log follows. === Pre-bind state information === LOG: DisplayName = DNDomain, Version=22.214.171.124, Culture=neutral, PublicKeyToken=null (Fully-specified) LOG: Appbase = C:\Program Files\National Instruments\LabVIEW 7.1\ LOG: Initial PrivatePath = NULL LOG: Dynamic Base = NULL LOG: Cache Base = NULL LOG: AppName = NULL Calling assembly : (Unknown). === LOG: Processing DEVPATH. LOG: DEVPATH is not set. Falling through to regular bind. LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). LOG: Post-policy reference: DNDomain, Version=126.96.36.199, Culture=neutral, PublicKeyToken=null LOG: Attempting download of new URL file:///C:/Program Files/National Instruments/LabVIEW 7.1/DNDomain.DLL. LOG: Attempting download of new URL file:///C:/Program Files/National Instruments/LabVIEW 7.1/DNDomain/DNDomain.DLL. LOG: Attempting download of new URL file:///C:/Program Files/National Instruments/LabVIEW 7.1/DNDomain.EXE. LOG: Attempting download of new URL file:///C:/Program Files/National Instruments/LabVIEW 7.1/DNDomain/DNDomain.EXE. LOG: All probing URLs attempted and failed.So, we have a failed load attempt. This is what happens when we tried to load in one of our assemblies (DNDomain.dll) using Load(). However, notice that there is a second attempt in LabVIEW.exe to load dndomain.dll (look at the WhereRefBind’s). If you open that one up, you get
*** Assembly Binder Log Entry (3/24/2005 @ 9:26:40 AM) *** The operation was successful. Bind result: hr = 0x0. The operation completed successfully. Assembly manager loaded from: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\fusion.dll Running under executable C:\Program Files\National Instruments\LabVIEW 7.1\LabVIEW.exe --- A detailed error log follows. === Pre-bind state information === LOG: Where-ref bind. Location = C:\Program Files\National Instruments\LabVIEW 7.1\resource\dndomain.dll LOG: Appbase = C:\Program Files\National Instruments\LabVIEW 7.1\ LOG: Initial PrivatePath = NULL LOG: Dynamic Base = NULL LOG: Cache Base = NULL LOG: AppName = NULL Calling assembly : (Unknown). === LOG: Processing DEVPATH. LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). LOG: Attempting download of new URL file:///C:/Program Files/National Instruments/LabVIEW 7.1/resource/dndomain.dll. LOG: Assembly download was successful. Attempting setup of file: C:\Program Files\National Instruments\LabVIEW 7.1\resource\dndomain.dll LOG: Entering run-from-source setup phase.
Here we have a successful load. Again, our edit mode code first tried to load DNDomain via Load(), which failed, but our assembly resolver stepped in and loaded it via LoadFrom(). This is why it is important to always show success and failures when debugging load problems.
Debugging Load Problems
The key to debugging an assembly load problem is to understand the rules of Fusion and see what Fusion tried to do in loading your assembly. It really is just that simple.
The most common problem for people using LabVIEW is just the inconsistency between edit mode and run mode (which is fixed in Constellation) and the log viewer can quickly show you that difference. Looking at where Fusion is probing for your assembly tells you where you should keep it.
Some of you more observant people may have noticed that my logger was configured for Custom instead of default. That is just because I have set the log directory for the viewer. Out of the box, FUSLOGVW uses the IE cache to hold its log entries. You can, however, set the LogPath string value in the registry Fusion key (see above). In this case, Fusion puts the log entries to the path specified and you must click the custom radio button to view them.