LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Specify or Set a .NET Assembly (DLL) Call or Search Path for a Built LabVIEW EXE (Executable)

Solved!
Go to solution

Oh hi!

 

From what I've found, there are only two locations at which a built LabVIEW EXE is able to find a private .NET assembly (one that wasn't explicity installed to the Windows GAC [Global Assembly Cache]) referenced within. The locations are: in the same directory as the EXE and <exe directory>\data . If the assembly is located in any other EXE subdirectories, it will not be found.

 

I've done about 30 minutes of searching, and this seems to be a reoccuring issue. My question is: is there a way of instructing a built LabVIEW EXE to search additional paths for a private .NET assembly? Maybe through a secret INI token or something along those lines?

 

Relevant links:

https://forums.ni.com/t5/LabVIEW/Built-exe-not-referencing-correct-NET-assembly-locations/td-p/24888...

http://zone.ni.com/reference/en-XX/help/371361P-01/lvconcepts/net_defaults/#search

http://zone.ni.com/reference/en-XX/help/371361P-01/lvconcepts/loading_assemblies/

https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z000000PAm6SAG

 

May the LabVIEW gods grant us with an answer on this merry Tuesday!

Mike

0 Kudos
Message 1 of 21
(7,295 Views)

I'd give viSearchPath a try.

 

Add this to the .ini of the exe:

viSearchPath="<topvi>:\*;;c:\new path"

 

I'm not sure what the default tis for executables. In LabVIEW.exe, the default is:

viSearchPath="<topvi>:\*;<foundvi>:\;<vilib>:\*;<userlib>:\*;<instrlib>:\*;C:\Program Files (x86)\National Instruments\LabVIEW 2013\resource"

 

I honestly don't know if this search path is used for .NET dll's, but it's worth a shot.

 

Alternatively, see this thread about why it's not working out, and why it shouldn't, and some potential workarounds.

 

I guess for .NET there are ways to dynamically load assemblies in memory, so LabVIEW will find them. I'm not sure how complicated that would be, since the assemblies are probably loaded when the VI's are loaded. I guess it would require dynamically loading of all VI's that use assemblies, even if dynamically loading the assemblies is possible (my guess would be .NET reflector subsystem).

Message 2 of 21
(7,255 Views)

Thanks for the reply. I'll give the INI token a shot.

 

Would you mind reposting the link you referenced? It doesn't seem to work, and I'm curious to know why telling an EXE where to look for assemblies shouldn't work.

 

I'm by no means a .NET expert, but from the description on Wikipedia, .NET Reflector doesn't seem like it'd be able to help with this problem.

0 Kudos
Message 3 of 21
(7,250 Views)
Solution
Accepted by Poolean

Ah. I got the permalink, but forgot to copy the URL:

https://forums.ni.com/t5/LabVIEW/Despite-indicating-the-path-still-have-to-manually-point-to-DLL/m-p...

 

That is .NET reflection. Sorry about that.

 

.NET reflection is a .NET class browser. It can be used to inspect .NET classes as well. It can be used for instance to get methods from an assembly, and to get inputs\outputs from the methods. It's been a while, but I thing it will load assemblies from a path. Not sure how helpful it is, it will probably mostly consume your time.

Message 4 of 21
(7,246 Views)

That forum post explains the problem well and the MSDN page is a good resource for this or related problems. Thanks a bunch for the links!

0 Kudos
Message 5 of 21
(7,221 Views)

Please note that the explanations in that thread are really about standard DLLs. .Net DLLs have different search paths (most of the locations for standard DLLs do simply not apply).

 

Basically .Net by default only searches in the application directory (where the executable that started the current process resides) and in the GAC (Global Assembly Cache). LabVIEW adds to this the path where the current LabVIEW project resides (and maybe the directory where the library file is if the VI referencing the .Net assembly is part of a library, but I haven't confirmed this last one).

In order to add a .Net assembly to the GAC it needs to be strongly named, meaning it needs to have also a full version number and all that.

The search paths for .Net can be modified by adding other paths to the current application domain, which LabVIEW does for VIs which are part of a LabVIEW project. Beyond that LabVIEW can't really start to guess what other directories might be useful candidates to add to the application domain for .Net.

 

You could try to add your own paths by using AppDomain.AppendPrivatePath but that has been obsoleted as it changes the probing path directly which could cause problems for already loaded assemblies that need to be resolved again for whatever reason to load additional resources and then .Net might end up finding a different version of the assembly first.

The recommended alternative AppDomainSetup.PrivateBinPath won't work as it only works for newly created app domains, but the app domain in which LabVIEW runs its .Net subsystem has been already created when the first .Net function in LabVIEW gets called.

The recommended way to extend search locations at runtime is to implement the AppDomain.AssemblyResolve event.

Rolf Kalbermatter
My Blog
Message 6 of 21
(7,216 Views)

@rolfk wrote: 

The recommended alternative AppDomainSetup.PrivateBinPath won't work as it only works for newly created app domains, but the app domain in which LabVIEW runs its .Net subsystem has been already created when the first .Net function in LabVIEW gets called.

The recommended way to extend search locations at runtime is to implement the AppDomain.AssemblyResolve event.


Would that work in practice? AFAIK, LabVIEW tries to load the assemblies when the VI's are loaded. So would adding a path from within the application work? I'd say dynamic loading is needed to make this work? So the exe can set this path, and then the assemblies are loaded with this new path set. That could be inconvenient.

 

A loader VI\splash screen might work. It would set the path and then start the real main.

0 Kudos
Message 7 of 21
(7,210 Views)
Solution
Accepted by Poolean

wiebe@CARYA wrote:

@rolfk wrote: 

The recommended alternative AppDomainSetup.PrivateBinPath won't work as it only works for newly created app domains, but the app domain in which LabVIEW runs its .Net subsystem has been already created when the first .Net function in LabVIEW gets called.

The recommended way to extend search locations at runtime is to implement the AppDomain.AssemblyResolve event.


Would that work in practice? AFAIK, LabVIEW tries to load the assemblies when the VI's are loaded. So would adding a path from within the application work? I'd say dynamic loading is needed to make this work? So the exe can set this path, and then the assemblies are loaded with this new path set. That could be inconvenient.

 

A loader VI\splash screen might work. It would set the path and then start the real main.


Actually if you change the search path through AppDomain.AppendPrivatePath, then yes you would have to first load the code that changes the search path and then after that the code that references those .Net assemblies.

But AppDomain.AssemblyResolve is an event that gets triggered everytime .Net needs to resolve an assembly. I'm not sure if this event is triggered before .Net searches it's standard paths or when it hasn't found an assembly in those standard paths, but it is dynamic at runtime. Of course you need to have some code that installs that event and that needs to be also run before you load the VIs that try to load any assemblies whose paths you might resolve yourself.

But .Net resolution happens when an object is first instantiated so it may be possible to load the main .Net assembly without the dependencies, depending how that assembly instantiates its internal objects that have those dependencies.

Rolf Kalbermatter
My Blog
Message 8 of 21
(7,203 Views)

I'm surprised that this is so complicated. I was really expecting and hoping for an INI token! :'(

0 Kudos
Message 9 of 21
(7,197 Views)

Unfortunately .Net is a 200 ton dinosaurus with an internal architecture that beats most other setups in complexity. Solving an assembly resolver with an INI token in such a beast is worse than trying to patch up a real dinosaurus with some bandaids Smiley Very Happy

 

Try to do dynamic module loading in Java, which .Net is in many ways largely based on in terms of concepts and ideas and you end up with a module resolver that can be more complex than the actual code in the modules.

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 21
(7,192 Views)