« February 2005 | Main | April 2005 »
March 29, 2005 in Programming | Permalink | Comments (0)
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.
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=1.0.0.0. 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=1.0.0.0, 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=1.0.0.0, 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.
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.
If you are getting a more exotic failure, such as access denied, bad image, etc., Suzanne Cook has some good advice here, here, and here. And with .NET 2.0 coming out, don’t forget this.
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.
March 24, 2005 in Programming | Permalink | Comments (0) | TrackBack (0)
March 18, 2005 in Dogs | Permalink | Comments (0)
March 16, 2005 in Programming | Permalink | Comments (0)
Check it out for yourself: http://pluralsight.com/wiki/default.aspx/Keith/ManagedAppSurvey.html
March 16, 2005 in Programming | Permalink | Comments (0)
March 14, 2005 in Dogs | Permalink | Comments (0)
March 09, 2005 in Programming | Permalink | Comments (0)
DISCLAIMER: All discussion regarding upcoming releases of LabVIEW are not commitments that the final product will be as I describe here. It’s merely what we are thinking at the moment or have implemented to date. Of course, if you have any feedback on this, please post it up or contact me. That is part of the reason for these posts.
So, we’ve talked about assemblies. We’ve talked about how LabVIEW 7 does things. Now it’s time to gaze into the crystal ball and take a look at the upcoming release: Constellation.
I’m letting the cat out of the bag a bit on some new Constellation features to explain everything, but I’ve been assured by marketing I won’t “disappear” after this.
New and Improved
To keep things simple, I’ll start with how things work using LabVIEW in the same way as before (versus projects, which we’ll discuss next). In this case, we cleaned up the algorithm to make it a bit more friendly and robust.
First thing - that Assembly Reference Window is gone! We’ve integrated the .NET nodes into the LabVIEW linker. This means that in addition to the full name of the assembly, we also store the relative path inside the VI (for non-GAC assemblies). Not only does this give you more flexibility, but it also means that if LabVIEW can’t find the assembly, it’ll prompt you with the file dialog to locate it. Nice, huh?
The next thing is that we’ve made the edit mode and run mode behaviors consistent. The algorithm always attempts to load the assembly via a Load() call. If that fails, and we’ve a path, we can fall back to LoadFrom(). This means it’s still best to keep your application and assemblies together, but as long as the files stay in the same relative place during a deployment, it’ll continue to work.
You might wonder why we don’t do a LoadFrom() in the first place if we’ve a path? Well, the answer has to do with how Fusion works in 1.1 of .NET. One key difference between Load() and LoadFrom() is that the first one obeys the .NET version policy files, while the second ignores them. To give you access to the full power of .NET, we are stay in line with the recommended approach as much as possible.
But wait, there’s more
Yep - that’s right. Constellation introduces the concept of projects into LabVIEW. They make it so much easier to do LabVIEW development that I think people will forget (or try to forget) what it was like without them … remember life before Undo?
In a lot of ways, projects are very similar to the project/solution paradigm that you may have seen in Microsoft’s Visual Studio but with some extra twists thrown in for the world of LabVIEW. Well, there are a lot of neat things about projects, but I better stop here until a beta version goes out - I really don’t want to know whether the trunk light goes off when the lid is closed ….
Anyway, the biggest change that projects introduce for .NET integration is that we moved the first-class citizen award from top level VIs to projects. Thus, instead of creating an AppDomain for each top level VI, we create one for each project (actually one per computing machine per project, but we’ll save that for another post - you’re gonna love projects!).
This has one interesting side effect: currently if you do have multiple top level VIs, you can’t share .NET refnums between them, nor use any sort of static state of a .NET class, without a whole lot of work. But now, since all top level VIs in the same project are in the same AppDomain, this works fine.
Also, the AppBase of the domain is set to the home directory of the project. Does this change your deployment? Not necessarily. While projects do let you have your VI’s scattered all over your hard drive if you want, I think most people will keep their main application VIs in same directory as the project they belong to. If that is the case, nothing changes.
What if you don’t? What if your .NET VIs are more of a library shared among different projects? No problem - just keep the relative location of the library VIs the same, and the linker will resolve the assembly – or you can put them in the GAC.
Julienne Fries?
Another change that impacts our assembly view is a new feature -- .NET Controls. Yep, you can now drop a .NET WinForm Control onto a LabVIEW front panel, just like you do with ActiveX controls. Boy - this one was a lot of fun for the team let me tell you. Getting .NET events to flow into a LabVIEW callback was an interesting challenge. But it works!
This actually doesn’t impact the assembly stuff as much as you might think. As with any assembly, you need to follow the rules described above for your controls, but that’s about it. The only real change is that it introduces another AppDomain.
What, another one? Yes, but don’t worry about this one. It’s simply the AppDomain we use to display the .NET controls on the front panel when the VI is not running. This allows you to access the edit mode properties of the control, which still require some .NET code execution.
Spaceman signing off
I figure that is enough for now. I hope you are going to be very pleased with these improvements, as well as all the other new features in Constellation.
Let me know if there is anything else you would like to hear about. It can be either an expansion on something we already discussed, or something totally new – you decide.
March 06, 2005 in Programming | Permalink | Comments (0) | TrackBack (1)
Okay, so you want to know about LabVIEW and assemblies, huh? Well sit back and get comfy.
DISCLAIMER: For the most part, I am going to avoid assuming that you are a .NET or LabVIEW expert. However, I am not planning on going into great detail on things not directly related to the post. If you ever want more details on something, please post a feedback and I’ll see what I can do.
What is a Top Level VI?
Basically it is the VI where you clicked the run button. All the VIs that it calls are its children – ergo they are not top level. However, while that one is running you could go and hit run on a different VI and presto – you have two top level VIs.
How does LabVIEW load assemblies in 7.0/7.1?
In the first version of our support for .NET, we created multiple AppDomains depending on the situation. Basically, you got one AppDomain for your edit-time work inside the LabVIEW environment, and one for each top-level VI that ran.
What about assemblies? Well, since each AppDomain is effectively its own process, each one must load its own assemblies. This is where the fun starts…
Within the VI containing the constructor node, LabVIEW saves the fully qualified name of your assembly. For example, if it is an unsigned assembly then you get
ClassLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
If it is a signed assembly, then you get
System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
This is all that is stored. When it comes time to load the assembly, if it isn’t in the GAC and it isn’t in the same directory as the top-level VI, LabVIEW will fail to load it.
But what about the .NET Assembly References that you put into LabVIEW? That little database of assemblies under Tools->Advanced? Well, truth be told, we made a mistake. We have some very different execution paths depending on whether you’re in edit mode or run mode.
During edit mode, we look at that list of assembly references to resolve any attempts to load. We first attempt to load via LoadFrom() with those references and then fail over to Load() if that does not work.
During run time, however, one of the first things we do for either a constructor or a static method is attempt to load the assembly via Load() – oops. If that fails, you get the classic:
“Error 1172 occurred at File or assembly name ClassLib, or one of its dependencies, was not found”
So, for 7.0 and 7.1, please put your assemblies either in the GAC or in the same directory as your top-level VI.
Yes, but what about that version problem discussed on the forum?
Actually, I believe it is the problem we just discussed. I hope to get in touch with Ratin and AnalogKid2DigitalMan to learn more, but their talk about updating the references indicates to me that the updated DLL lived in a new directory. This means that it most likely fell into the problem area above. The reason the error message referenced the old assembly version was that that version was what was stored in the VI. If the old DLL had been overridden by the new DLL, LabVIEW would have gone on its merry way.
Golly gee, Spaceman, what’s next?
Ah, for that you must wait for the next exciting episode of “ASSEMBLIES IN SPACE!!!!” Watch our intrepid heroes as they visit the nearby Constellation…
March 04, 2005 in Programming | Permalink | Comments (2) | TrackBack (0)
March 04, 2005 in Programming | Permalink | Comments (5) | TrackBack (0)