LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Can .NET DLLs not registered in GAC be excluded from LV source distributions?

Solved!
Go to solution

Hello!

 

I'm writing a LV wrapper of the SolidWorks EPDM .NET DLL (located in C:\Program Files\SOLIDWORKS PDM, not C:\Windows\Microsoft.NET\assembly, which is where GAC-registered .NET DLLs live).  When I make LV APIs for reuse within our company, I usually make a source distribution of the VIs and then an NI package to put that source dist in user.lib.

 

When I make the source distribution, the EPDM .NET DLL is auto-included in the build output.  I don't want this to happen because all devs who'd use this API will have SolidWorks (and thus that EPDM DLL) already installed in the right C:\Program Files location (this is where SOLIDWORKS installs the DLL).  I also don't want to be unnecessarily copying that DLL to user.lib when I want the LV code to always reference the one in C:\Program Files.

 

The final post on this related forum states:

 

Strictly speaking .Net DLLs are either in the Global Assembly Cache (GAC) or in a private location. The Windows sytem folder is in that context a private location. LabVIEW at least in earlier versions took this very literal meaning to include any .Net DLL as build dependency unless it was located in the GAC. For a .Net DLL to be part of the GAC it needs to be "strongly named" meaning it needs to have a valid signing.

 

The comment was made in 2011 and talks about "earlier versions" of LabVIEW, but it appears to still match what I'm seeing in LabVIEW 2018.  The .NET DLL I want to use is not in the GAC.  Thus, LabVIEW appears to be auto-including it in my build.  (This doesn't happen with other APIs I've written that reference .NET DLLs in the GAC.)  Still, I'm wondering if there's a way to get around this given that 10 years have passed since that last comment.

 

A few things that you may think of bringing up that I've already tried:

  1. Just reference the DLL with a path on your block diagram instead of in the node dialog.  This works for C/C++ DLLs but not .NET DLLs which use Constructor Nodes with no file path input.
  2. There is an option in the build spec to remove dependent libraries.  Yes, there is a checkbox called "Exclude dependent shared libraries" that doesn't actually exclude the .NET DLL from the source dist build.  I've read the help for this checkbox, and honestly I really don't understand what this option is supposed to do.  It's very confusing to me; regardless, it definitively does NOT exclude the DLL from the source distribution.
  3. Just delete the DLL from your source distribution with a post build action before then building your NI Package.  Tried that.  The NI Package build then fails because it knows that the DLL was part of the source dist and can't find it (error 7) when building the NI Package.

Interestingly, if I package the source dist that includes the .NET DLL and distribute it to user.lib and then drop one of the user.lib VIs on a new VI, I get a dependency load warning saying that LV is loading the DLL from C:\Program Files instead of the user.lib location...

 

Capture.PNG

 

So, my questions are:

  1. Why won't LabVIEW let me exclude the .NET DLL in my source dist?
  2. If LabVIEW is going to force me to include the .NET DLL in my source dist, why does it search for the DLL in its original C:\Program Files location instead of first loading the copy in user.lib that it forced me to include?  This seems wacky.
  3. Where are the search paths for .NET DLLs defined?  There are various search paths I know how to define for loading VIs, but I don't know how LabVIEW tries to load .NET DLLs.  I don't understand why it's loading the DLL from C:\Program Files when there's a copy of the DLL sitting next to all the VIs that call it.

To reiterate , I want LV to call the DLL from C:\Program Files.  I just don't understand why it's doing that when it wouldn't let me build my source dist without including the DLL.

 

Any help/tips would be welcome!

 

David

0 Kudos
Message 1 of 10
(3,485 Views)

@croohcifer wrote:

So, my questions are:

  1. Why won't LabVIEW let me exclude the .NET DLL in my source dist?
  2. If LabVIEW is going to force me to include the .NET DLL in my source dist, why does it search for the DLL in its original C:\Program Files location instead of first loading the copy in user.lib that it forced me to include?  This seems wacky.
  3. Where are the search paths for .NET DLLs defined?  There are various search paths I know how to define for loading VIs, but I don't know how LabVIEW tries to load .NET DLLs.  I don't understand why it's loading the DLL from C:\Program Files when there's a copy of the DLL sitting next to all the VIs that call it.

To reiterate , I want LV to call the DLL from C:\Program Files.  I just don't understand why it's doing that when it wouldn't let me build my source dist without including the DLL.


I think you've hit on a number of quirks with .NET CLR hosting in LabVIEW. I'll try to answer these questions best I can:

 

  1. You can't. The option you are talking about if actually for packed project libraries, not .NET assemblies. I'm assuming you've added the assembly to the project from the absolute path. I don't recall VI Package Manager having the same issue in terms of build but I could be wrong there.
  2. This is to do with search directories and the order thereof. The VIs save the relative path to the assemblies they use, and this is included in the Fusion search list (Fusion is the old name for the CLR assembly loader tasked with finding a specific named and versioned assembly). Having a project adds any sub-folders of that project to the list as well, which is why NI always recommends using a project when using assemblies. Based on your use-case, I don't think this works for you as the VIs will be opened outside the project. 
  3. I assume you've read this: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z000000PAm6SAG 

Based on what you've said, it sounds like if you could resolve the NI Package Manger problem (ie not including the assembly) then you'd have a solution. Having said that - it also sounds like its not really a real issue - yes, there is a copy of an assembly eventually in the user.lib but its never actually used?

0 Kudos
Message 2 of 10
(3,409 Views)

@tyk007 wrote:


I think you've hit on a number of quirks with .NET CLR hosting in LabVIEW. I'll try to answer these questions best I can:

 

  1. You can't. The option you are talking about if actually for packed project libraries, not .NET assemblies. I'm assuming you've added the assembly to the project from the absolute path. I don't recall VI Package Manager having the same issue in terms of build but I could be wrong there.
  2. This is to do with search directories and the order thereof. The VIs save the relative path to the assemblies they use, and this is included in the Fusion search list (Fusion is the old name for the CLR assembly loader tasked with finding a specific named and versioned assembly). Having a project adds any sub-folders of that project to the list as well, which is why NI always recommends using a project when using assemblies. Based on your use-case, I don't think this works for you as the VIs will be opened outside the project. 
  3. I assume you've read this: https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z000000PAm6SAG 

Based on what you've said, it sounds like if you could resolve the NI Package Manger problem (ie not including the assembly) then you'd have a solution. Having said that - it also sounds like its not really a real issue - yes, there is a copy of an assembly eventually in the user.lib but its never actually used?


Thanks @Tyk007.

  1. Regarding "The option you are talking about if actually for packed project libraries, not .NET assemblies."  When I hover over "Exclude dependent shared libraries", the context help is headed "Exclude DLL" and never mentions packed project libraries.  Do you know of any LV documentation that suggests that this option only applies to PPLs?  Regarding "I'm assuming you've added the assembly to the project from the absolute path," the assembly ended up in my dependencies when I dropped a constructor node and browsed for the assembly.  If that means adding the assembly to the project from the absolute path, then yes.  Regarding "I don't recall VI Package Manager having the same issue in terms of build but I could be wrong there," I'm sorry if I was unclear, but I'm building a source distribution from my LV project.  I'm not using VI Package Manager.
  2. "Based on your use-case, I don't think this works for you as the VIs will be opened outside the project."  Haha, I mean, that may be the case, but can I develop a LabVIEW class or library outside of the context of a project?  When people make reuse APIs (as in, everything that lives in user.lib, instr.lib, etc.), do they not develop in a project?
  3. Yes, I have read that, and it doesn't match what I'm experiencing.  The KB says for LV 8.0 and above, LV looks in three locations: (A) The GAC.  I know the .NET doesn't exist in the GAC because I've run a "Search Everything" for it, and it doesn't show up in any C:\Windows locations.  (B) Specified subdirectories. I've wrapped the API in a class with various methods and deployed it to a folder in user.lib.  I assume that the search subdirectories of the class would thus be at the class's directory location and lower directories.  Again, when I deploy to user.lib, the first thing that happens when I try to drop a VI from the API on a new BD is that it says it's loading the DLL from the C:\Program Files\SOLIDWORKS PDM location, which isn't a subdirectory of the LV class that houses the VIs that call the assembly.  (C) Relative path to the non-GAC assembly with respect to the VI.  I just tried moving my API folder to different levels within user.lib in an attempt to break any relative pathing, but LabVIEW always ends up loading the copy in C:\Program Files\SOLIDWORKS PDM despite the relative path to it from the calling VI being different.  What appears to be happening is that the LabVIEW VIs that call the constructor know the absolute path to this non-GAC DLL, and this experience is in conflict with the documentation unless I'm missing something.

So, basically, yes, my "problem" is that I don't get why LabVIEW makes it so hard (or impossible?) to exclude this assembly from source distributions when it seems intent on never loading the copy I'm forced to include.  (I've also just tested this with an EXE and saw the same thing!  LabVIEW forces the inclusion of the DLL in the "data" folder next to the EXE, but when I run the EXE, even on another PC, I can delete the DLL from that "data" folder, and the EXE runs fine, meaning that LV is able to find the C:\Program Files copy of the DLL.)  Also, the documentation around excluding libraries and loading .NET assemblies is in conflict with my experience.  Is this really an issue?  I'd say yes, which is why I posted, but I can understand why others would see this and say "what's the big deal?"

 

My "workaround" for now will be to tell developers who install this API to manually delete the .NET DLL that installs in user.lib because (A) LabVIEW doesn't want to use it despite forcing it to be there and (B) I don't want to be distributing tons of copies of a .NET DLL (32 and 64-bit APIs in multiple LabVIEW versions) that should exist already once in the right Program Files location and that LabVIEW somehow (still unknown to me) knows how to find.  But this is a really lame workaround and won't solve the problem (at least, what I perceive to be a problem) of needlessly proliferating copies of this DLL in any EXEs, TestStand distributions, etc. that happen to call members of the API I've deployed to user.lib.

0 Kudos
Message 3 of 10
(3,395 Views)

Regarding "The option you are talking about if actually for packed project libraries, not .NET assemblies."  When I hover over "Exclude dependent shared libraries", the context help is headed "Exclude DLL" and never mentions packed project libraries.  Do you know of any LV documentation that suggests that this option only applies to PPLs?  Regarding "I'm assuming you've added the assembly to the project from the absolute path," the assembly ended up in my dependencies when I dropped a constructor node and browsed for the assembly.  If that means adding the assembly to the project from the absolute path, then yes.  Regarding "I don't recall VI Package Manager having the same issue in terms of build but I could be wrong there," I'm sorry if I was unclear, but I'm building a source distribution from my LV project.  I'm not using VI Package Manager.

OK, your original post states that you are using NI Package Manager to build a package from your source distribution; which is where you are getting the error - and this was why a Post-Build action in Application Builder was not feasible. This would have been my original suggestion had you not described that, but building an NI Package (not a VI package) would preclude that.

 

I mis-read your post; for the "shared libraries" I think its specifically the CLFN nodes (for Win32 libraries). I don't believe this is for .NET assemblies. Having said that, I can't find any NI documentation that specifically states that, however it is inferred in the terminology of "shared library" which elsewhere in the docs refers to win32 libs. So I don't think this will help you.

 


"Based on your use-case, I don't think this works for you as the VIs will be opened outside the project."  Haha, I mean, that may be the case, but can I develop a LabVIEW class or library outside of the context of a project?  When people make reuse APIs (as in, everything that lives in user.lib, instr.lib, etc.), do they not develop in a project?

Actually you can in a limited fashion, yes. No Application Builder but fine for modifications (and quite common to do so). What I was actually referring to is that when you load VIs from within a project the rules around .NET Fusion search directories change. When you are just loading a library (which a class is a type of library) as a result of loading a VI within that library you are using different search rules.

 

The link I posted introduces this and also links to a more detailed section in the help file (also on your PC) - perhaps this will help clarify: https://zone.ni.com/reference/en-XX/help/371361R-01/lvconcepts/loading_assemblies/ . In any event, your use case prohibits that usefulness as you are loading without a project (from LabVIEW.exe).

 


So, basically, yes, my "problem" is that I don't get why LabVIEW makes it so hard (or impossible?) to exclude this assembly from source distributions when it seems intent on never loading the copy I'm forced to include.  (I've also just tested this with an EXE and saw the same thing!  LabVIEW forces the inclusion of the DLL in the "data" folder next to the EXE, but when I run the EXE, even on another PC, I can delete the DLL from that "data" folder, and the EXE runs fine, meaning that LV is able to find the C:\Program Files copy of the DLL.)  Also, the documentation around excluding libraries and loading .NET assemblies is in conflict with my experience.  Is this really an issue?  I'd say yes, which is why I posted, but I can understand why others would see this and say "what's the big deal?"

Based on what you've described, the behavior sounds exactly like the link I posted to above. Please read that. However it will only explain the expected behavior, its not really the behavior you want. I should also point out that that this isn't specific to LabVIEW - this is how the CLR locates assemblies and you would have the same issue if you built a C# console application to do the same job.

 

VI Package Manager has a post-build action after the package is built that could be used to delete the assembly from disk but if memory serves you need the paid version to do that.

0 Kudos
Message 4 of 10
(3,385 Views)

OK, your original post states that you are using NI Package Manager to build a package from your source distribution; which is where you are getting the error - and this was why a Post-Build action in Application Builder was not feasible. This would have been my original suggestion had you not described that, but building an NI Package (not a VI package) would preclude that.

Again, sorry if this was unclear.  I'm not using NI Package Manager, and my original post never stated that I was.  I am building a source distribution and an NI Package from my LabVIEW project.  (Rereading my post, I never explicitly mentioned a LV project, but I also never said NI Package Builder.)  Either way, sounds like we're on the same page now.

 


Actually you can in a limited fashion, yes. No Application Builder but fine for modifications (and quite common to do so). What I was actually referring to is that when you load VIs from within a project the rules around .NET Fusion search directories change. When you are just loading a library (which a class is a type of library) as a result of loading a VI within that library you are using different search rules.

 

The link I posted introduces this and also links to a more detailed section in the help file (also on your PC) - perhaps this will help clarify: https://zone.ni.com/reference/en-XX/help/371361R-01/lvconcepts/loading_assemblies/ . In any event, your use case prohibits that usefulness as you are loading without a project (from LabVIEW.exe).

So, interestingly, a paragraph in the link you shared says:

 

"If you call a .NET assembly from a VI that does not belong to a project," [which is exactly what I'm doing when opening the VI in user.lib] "you technically can save the assembly in the same directory as its calling VI. LabVIEW searches certain VI directories, including the calling VI directory, for assemblies that the CLR cannot load by default. However, calling assemblies stored in this location can result in name conflicts and other unexpected .NET behavior. Therefore, National Instruments does not recommend that you save assemblies in this location."

 

In other words, what I'm trying to avoid (LabVIEW proliferating copies of the EPDM .NET DLL with my source dist deployment) is exactly what NI is saying not to do, but LabVIEW is forcing me to do it.  Hence this entire thread.

 


Based on what you've described, the behavior sounds exactly like the link I posted to above. Please read that. However it will only explain the expected behavior, its not really the behavior you want. I should also point out that that this isn't specific to LabVIEW - this is how the CLR locates assemblies and you would have the same issue if you built a C# console application to do the same job.


You have provided two links, and neither one describes the behavior I'm seeing.  I'm seeing that the class VI that's not in a project in user.lib appears to be locating the .NET DLL via its absolute path, not via the GAC, the LabVIEW.exe, the VI's path, or the relative path to the DLL from the VI (these are all of the expected search locations the documentation you've linked suggests).  If I'm missing something, please let me know exactly what it is.  I've read the documents you've shared multiple times and am not seeing how they sound like what I'm experiencing.

 

VI Package Manager has a post-build action after the package is built that could be used to delete the assembly from disk but if memory serves you need the paid version to do that.


Interesting.  I'll look into it, but that would be a bummer given that all of our build processes happen through LabVIEW projects currently.  I've been considering looking into NI Package Builder, but I haven't gotten around to it.  Maybe I should look into VI Package Builder, too.

 

Not sure how much further we'll get here.  It's sounding like:

  1. The LabVIEW documentation on how .NET DLLs get loaded is either wrong or incomplete.
  2. There is no way using build processes in the LabVIEW project to exclude .NET DLLs from build outputs.
0 Kudos
Message 5 of 10
(3,369 Views)

@croohcifer wrote:

OK, your original post states that you are using NI Package Manager to build a package from your source distribution; which is where you are getting the error - and this was why a Post-Build action in Application Builder was not feasible. This would have been my original suggestion had you not described that, but building an NI Package (not a VI package) would preclude that.

Again, sorry if this was unclear.  I'm not using NI Package Manager, and my original post never stated that I was.  I am building a source distribution and an NI Package from my LabVIEW project.  (Rereading my post, I never explicitly mentioned a LV project, but I also never said NI Package Builder.)  Either way, sounds like we're on the same page now.

No problem; the fact that you are using the "Package" Build Specification means you are using the NI Package Manager build sub-system and components, even if you aren't using the Manger UI. This is what I meant, apologies if that caused confusion. You did also say "Source Distribution" which is another build specification type - so I assumed you were following a two-step build process. Is that correct?

 


You have provided two links, and neither one describes the behavior I'm seeing.  I'm seeing that the class VI that's not in a project in user.lib appears to be locating the .NET DLL via its absolute path, not via the GAC, the LabVIEW.exe, the VI's path, or the relative path to the DLL from the VI (these are all of the expected search locations the documentation you've linked suggests).  If I'm missing something, please let me know exactly what it is.  I've read the documents you've shared multiple times and am not seeing how they sound like what I'm experiencing.



It also adds the list in the VI Search Path as configured in the LabVIEW environment (first paragraph of that second link) to the Fusion search list. You haven't described what your settings for that are in your environment, but I assume they are the default. Note this part from the link:

 

"If the CLR cannot find the assembly, LabVIEW then searches for the assembly in the same manner it searches for missing VIs. LabVIEW searches for missing VIs in the directories ...."

 

The absolute path is referenced in the VI, as we discussed earlier. When Fusion can't find it there, or in any of the default search directories (the subject of the next paragraph in that link),  LabVIEW provides those alternate paths as well (VI Search Path). I agree the wording is a little vague, but you'll find this is frequently true of technical documentation. The MSDN link in that article clarifies the Fusion search process better and it looks to me like NI tried to summarize it. Could the documentation be better? Possibly. Probably. But I wouldn't say its wrong, just missing detail for some specific use-cases (like yours). Luckily it links to the article that clarifies much of that detail, since this process is effectively the same for any process that hosts the CLR.

 


Not sure how much further we'll get here.  It's sounding like:

  1. The LabVIEW documentation on how .NET DLLs get loaded is either wrong or incomplete.
  2. There is no way using build processes in the LabVIEW project to exclude .NET DLLs from build outputs.

Yes, you can't exclude the .NET assembly from the build process, though, like you have said, in this case its entirely a non-issue at run-time (where it matters most). As a result, I can't see NI investing resources in changing something like that. LabVIEW NXG managed this better in some ways (worse in others) though it remains to be seen if any of those ideas are folded back into LabVIEW.

0 Kudos
Message 6 of 10
(3,364 Views)

@tyk007 wrote:

 

I mis-read your post; for the "shared libraries" I think its specifically the CLFN nodes (for Win32 libraries). I don't believe this is for .NET assemblies. Having said that, I can't find any NI documentation that specifically states that, however it is inferred in the terminology of "shared library" which elsewhere in the docs refers to win32 libs. So I don't think this will help you.



Shared libraries is not limited to Windows DLLs, but also includes Unix shared libraries and Mac OS X Frameworks. But it most likely does not extend to ActiveX components and .Net assemblies, even though they also use usually the DLL extension.

Rolf Kalbermatter
My Blog
0 Kudos
Message 7 of 10
(3,338 Views)

@rolfk wrote:

@tyk007 wrote:

 

I mis-read your post; for the "shared libraries" I think its specifically the CLFN nodes (for Win32 libraries). I don't believe this is for .NET assemblies. Having said that, I can't find any NI documentation that specifically states that, however it is inferred in the terminology of "shared library" which elsewhere in the docs refers to win32 libs. So I don't think this will help you.



Shared libraries is not limited to Windows DLLs, but also includes Unix shared libraries and Mac OS X Frameworks. But it most likely does not extend to ActiveX components and .Net assemblies, even though they also use usually the DLL extension.


Thanks for the clarification - I tend to forget the Linux and OSX cousins!

0 Kudos
Message 8 of 10
(3,334 Views)
Solution
Accepted by topic author croohcifer
Message 9 of 10
(3,320 Views)

Thank you!  Googling for that CAR number (720595), I also found it here:  https://forums.ni.com/t5/LabVIEW/NET-assembly-and-packed-project-lirary-warnings/td-p/3963682?profil...

 

Turns out this is a bug where LabVIEW is loading the .NET assembly from the absolute path (as I've been experiencing) because the .NET object is stored in private class data.

 

This doesn't solve my issue of LabVIEW forcing me to include the .NET DLL, but at least I now know why LabVIEW is searching for and loading the "wrong" copy, which actually happens to be the copy I want to use.

0 Kudos
Message 10 of 10
(3,305 Views)