From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Using a .net dll with PPL based application

Solved!
Go to solution

Hi Everyone,

 

Summary:

I have a PPL that's dependant on a .net DLL. The build spec is behaving the same way you would expect it to when you have dependant PPLs with Exclude dependant packed libraries unchecked. This is causing dependency issues, and several .net dll duplications are being created in the build process. Checking Exclude dependant shared libraries doesn't solve the issue.

 

I have a project that is based on several (30 or so) PPLs, the build routine is working well and I'm confident in using PPLs generally.

 

However, I have one PPL that is using a .net dll (Teledyne Photometrics camera driver). The issue seems to be that the dll is being included in the PPL build (regardless of if Exclude dependant shared libraries is checked). If I was just using the PPL on its own that would be fine. However, that PPL is being called by another PPL which when built is also copying the DLL. This causes several copies of the DLL in the final built solution, non of which seem to be the 'correct dependency' as the final build executable complains it is missing the dll (when it calls the PPL (via relative path)).

 

If I don't make the library into a PPL, that just pushes the issue up the chain. I want to use a PPL as I want it to be dynamically loaded when required. I suppose I could distribute the library and VIs to use as a plug in, but that creates a bit of a smell.

 

I have read about the Global Assembly Cache (GAC) which might solve the issue. However, this seems quite invasive when distributing the software to customers. Also, I have no experience in using the GAC, and I am unaware of the possible consequences. I would much rather have the PPL always expect the DLL in a relative position (like you would with other dependant PPLs).

 

I hope this makes sense, let me know if you have any experience with PPLs and .net DLLs, any words of wisdom would be appreciated!

 

Cheers,

Tom

0 Kudos
Message 1 of 6
(1,978 Views)

Heya Tom,

 

That's a good question and I think was a lot of the reasons behind the creation of this unofficial tool: https://github.com/jovianarts/LVSolutionBuilder

It was presented at UKTAG#6 for the purpose of trying to deal with cascading builds within LabVIEW, although this isn't explicitly addressing the use of DLLs but of other build order issues.

 

You're correct in that some people may not be happy with an install into the GAC and that general Microsoft guidelines are to leave the GAC alone, but a lot of installers do xuse this and it's pretty common. The old NI VeriStand Steps for TestStand built a DLL and installed this into the GAC with a post-install action (and then had an uninstall action to remove it from the GAC). If you wanted to look an example, you can see the source code on the GitHub for the steps

 

Brainstorming here; is there a way of dynamically calling the DLL so that it's not linked in the build dependencies, or by referencing it, not including the DLL but then having an action that creates the path linking to a dependent location? I've not got too much time to test this currently but might be an idea.

 

Cheers,

Nick

Message 2 of 6
(1,884 Views)

Hi Tom,

 

Can you rearrange your code such that you have an interface PPL for the camera that doesn't include the DLL, and then create a single PPL that inherits from the interface in that PPL and uses the DLL?

Then your other PPLs could perhaps depend only on the interface (so no DLL problems) and you can inject the single DLL-containing PPL as required?

 

I'd imagine (having not tested this) that when you come to build the application, you'll probably want to have the concrete class in your application, in which case the DLL will be pulled into your dependencies, but I *think* this is a good thing here - you'll want the DLL to be findable via the search paths described here: How LabVIEW Locates .NET Assemblies, in particular:

"If you are using .NET assemblies in a shared library or stand-alone application, LabVIEW searches the directory that contains the library or application and the data and bin subdirectories."

so I *think* that you no longer want the PPL to find it, but now the application... hopefully that a) works and b) doesn't spam you with some "we loaded this from an unexpected path" message...


GCentral
Message 3 of 6
(1,876 Views)
Solution
Accepted by topic author McQuillan

@NPowl wrote:

 

You're correct in that some people may not be happy with an install into the GAC and that general Microsoft guidelines are to leave the GAC alone, but a lot of installers do xuse this and it's pretty common. The old NI VeriStand Steps for TestStand built a DLL and installed this into the GAC with a post-install action (and then had an uninstall action to remove it from the GAC). If you wanted to look an example, you can see the source code on the GitHub for the steps


The .Net loader is specifically designed to ONLY search by default for assemblies in the application directory and the GAC. An application can elect to add additional paths to the AppDomain when starting up the CLR but a user can not add arbitrary directories to the system that the .Net loader should search. The reason behind this is security. If a user could simply add extra directories for any .Net application to the system, so could a rogue piece of software like a virus or trojan and bang, you have a very trivial method of injecting arbitrary code into any .Net process that tries to load assemblies.

 

In order for an assembly to be put into the GAC it needs to be strongly named, meaning it needs to have a full version, and a valid signature key. This is the main reason for assemblies to not be in the assembly since the developer did not care to create a strongly named assembly. And of course in order to add assemblies to the GAC you need to have elevated rights too.

 

But a software developer providing assemblies that can be potentially used by multiple application on the same system REALLY should consider to install them in the GAC. That's the location Microsoft intended to be used for any assembly that is not supposed to be application private. As such it should not be your task to do that but the task of the installer for your assembly.

 

One workaround might be to install the assembly into the GAC on your development machine (if it is strongly named, which any assembly should be that someone distributes for anything but development purposes). That way the LabVIEW Application Builder will NOT add it to the build product (PPL or EXE), but assume that it is provided by the target system. Then manually add the assembly to your installer specification to be added into the same directory as your executable. That way the .Net loader will find it anyways on a target system, without needing to add it to the GAC on a customer machine.

Rolf Kalbermatter
My Blog
Message 4 of 6
(1,869 Views)

Thank you very much everyone who replied.

 

rolfk's workaround worked a treat!

 

One workaround might be to install the assembly into the GAC on your development machine (if it is strongly named, which any assembly should be that someone distributes for anything but development purposes). That way the LabVIEW Application Builder will NOT add it to the build product (PPL or EXE), but assume that it is provided by the target system. Then manually add the assembly to your installer specification to be added into the same directory as your executable. That way the .Net loader will find it anyways on a target system, without needing to add it to the GAC on a customer machine.


Just to summarise for other developers who find themselves here:

  1. I worked with the .net assembly vendor who agreed to send me a signed copy of the .net dll
  2. Using command prompt I installed the dll into the GAC
    "<path>\gacutil.exe" -i "<path to .net assembly>"​

    (gacutil.exe has to be installed with the Windows SDK (if you have Visual Studio installed, you probably already have gacutil)

  3. I updated my project so all the .net dependencies were to the dll in the GAC (right click property node > Select class > .net etc...)
  4. Added the dll to the overall installer (and made the dll location the same directory as the launching executable). 

 

This is my first time using custom .net assembles and I've definitely learnt a lot from this challenge and all your replies - thanks team!

Message 5 of 6
(1,853 Views)

Anyone know how to solve this *without* using the GAC (for example if I have test versions of a DLL or don't want to use the version in the GAC)

 

I tried using a config file with <codeBase> and <developmentMode> but have not been able to force loading from a specific path (in this case to override using the DLL in the GAC).  My interpretation of <developmentMode> is that it allows you to avoid the GAC and use whatever path you specify with the DEVPATH environment variable. <developmentMode> Element - .NET Framework | Microsoft Learn

 

 

For testing purposes, I copied TaskScheduler.dll from C:\Windows\Microsoft.NET\assembly\GAC_MSIL\TaskScheduler\v4.0_10.0.0.0__31bf3856ad364e35 to C:\NETDLLTEST

 

I then created LabVIEW project TaskScheduleTest.lvproj and a config fileTaskScheduleTest.lvproj.config (see attached zip) and also set my DEVPATH environment variable to "C:\NETDLLTEST".   I also tried using "C:\NETDLLTEST\TaskScheduler.dll" for DEVPATH

 

NIExpert_0-1707168471149.png

 

 

The LabVIEW project TaskScheduleTest.lvproj (2023Q4 version attached) still shows that the DLL is loading from the GAC despite using the config file.

 

Likewise, Use PPL.lvproj  project that uses the PPL is also using the DLL from the GAC

 

 

How do I force both TaskScheduleTest.lvproj and PPL.lvproj  to use specific instances of the DLL?

0 Kudos
Message 6 of 6
(396 Views)