diff --git a/App.config b/App.config deleted file mode 100644 index 4bfa005..0000000 --- a/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/GacLoader.cs b/GacLoader.cs new file mode 100644 index 0000000..5025dee --- /dev/null +++ b/GacLoader.cs @@ -0,0 +1,66 @@ +using Ivi.Visa.ConflictManager; +using System; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace IviVisaNetSample +{ +#if NET5_0_OR_GREATER + /// + /// Class used to load .NET Framework assemblies located in GAC from .NET 5+ + /// Requred only for expiremental using VISA.NET library in .NET 5+ + /// + internal static class GacLoader + { + /// + /// Load an assembly from the GAC. + /// + /// + /// Loaded assembly + /// + public static Assembly Load(AssemblyName assemblyName) + { + var gacPaths = new[] + { + $"{Environment.GetFolderPath(Environment.SpecialFolder.Windows)}\\Microsoft.NET\\assembly\\GAC_MSIL\\{assemblyName.Name}", + $"{Environment.GetFolderPath(Environment.SpecialFolder.Windows)}\\assembly\\GAC_MSIL\\{assemblyName.Name}", + }; + + foreach (var folder in gacPaths.Where(f => Directory.Exists(f))) + { + foreach (var subfolder in Directory.EnumerateDirectories(folder)) + { + if (subfolder.Contains(Convert.ToHexString(assemblyName.GetPublicKeyToken()), StringComparison.OrdinalIgnoreCase) + && subfolder.Contains(assemblyName.Version.ToString(), StringComparison.OrdinalIgnoreCase)) + { + var assemblyPath = Path.Combine(subfolder, assemblyName.Name + ".dll"); + if (File.Exists(assemblyPath)) + return Assembly.LoadFrom(assemblyPath); + } + } + } + throw new FileNotFoundException($"Assembly {assemblyName} not found."); + } + + /// + /// Preloading installed VISA implementation assemblies for NET 5+ + /// + public static void LoadInstalledVisaAssemblies() { + var installedVisas = new ConflictManager().GetInstalledVisas(ApiType.DotNet); + foreach (var visaLibrary in installedVisas) + { + try + { + var inst = GacLoader.Load(new AssemblyName(visaLibrary.Location.Substring(visaLibrary.Location.IndexOf(",") + 1))); + Console.WriteLine($"Loaded assembly \"{visaLibrary.FriendlyName}\"."); + } + catch (Exception exception) + { + Console.WriteLine($"Failed to load assembly \"{visaLibrary.FriendlyName}\": {exception.Message}"); + } + } + } + } +#endif +} diff --git a/IviVisaNetSample.csproj b/IviVisaNetSample.csproj index a0752ff..14ea97f 100644 --- a/IviVisaNetSample.csproj +++ b/IviVisaNetSample.csproj @@ -1,58 +1,13 @@ - - - + + - Debug - AnyCPU - {181CDD33-8577-4F46-AF93-2A02660E51AC} Exe - Properties - IviVisaNetSample - IviVisaNetSample - v4.8 - 512 - true - + net48;net5.0;net8.0 + AnyCPU;x64;x86 - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - + - + - - - \ No newline at end of file + + diff --git a/Program.cs b/Program.cs index 5a0c20f..fe4a210 100644 --- a/Program.cs +++ b/Program.cs @@ -9,41 +9,46 @@ static class Program { static void Main() { - // Get a VISA.NET library version. - Version VisaNetSharedComponentsVersion = typeof(GlobalResourceManager).Assembly.GetName().Version; - Console.WriteLine("VISA.NET Shared Components version {0}.", VisaNetSharedComponentsVersion); + // Get VISA.NET Shared Components version. + Version visaNetSharedComponentsVersion = typeof(GlobalResourceManager).Assembly.GetName().Version; + Console.WriteLine($"VISA.NET Shared Components version {visaNetSharedComponentsVersion}."); // Check whether VISA Shared Components is installed before using VISA.NET. // If access VISA.NET without the visaConfMgr.dll library, an unhandled exception will // be thrown during termination process due to a bug in the implementation of the // VISA.NET Shared Components, andthe application will crash. - FileVersionInfo VisaSharedComponentsInfo; try { // Get an available version of the VISA Shared Components. - VisaSharedComponentsInfo = FileVersionInfo.GetVersionInfo(Path.Combine(Environment.SystemDirectory, "visaConfMgr.dll")); - Console.WriteLine("VISA Shared Components version {0} detected.", VisaSharedComponentsInfo.ProductVersion); + FileVersionInfo visaSharedComponentsInfo = FileVersionInfo.GetVersionInfo(Path.Combine(Environment.SystemDirectory, "visaConfMgr.dll")); + Console.WriteLine($"VISA Shared Components version {visaSharedComponentsInfo.ProductVersion} detected."); } catch (FileNotFoundException) { - Console.WriteLine("VISA implementation compatible with VISA.NET Shared Components {0} not found. Please install corresponding vendor-specific VISA implementation first.", VisaNetSharedComponentsVersion); + Console.WriteLine($"VISA implementation compatible with VISA.NET Shared Components {visaNetSharedComponentsVersion} not found. Please install corresponding vendor-specific VISA implementation first."); return; } +#if NET5_0_OR_GREATER + // Preloading installed VISA implementation assemblies for NET 5+ + GacLoader.LoadInstalledVisaAssemblies(); +#endif + try { // Connect to the instrument. - using (IVisaSession res = GlobalResourceManager.Open("TCPIP0::localhost::5025::SOCKET", AccessModes.ExclusiveLock, 2000)) + var resourceName = "TCPIP::localhost::5025::SOCKET"; + using (IVisaSession resource = GlobalResourceManager.Open(resourceName, AccessModes.ExclusiveLock, 2000)) { - if (res is IMessageBasedSession session) + if (resource is IMessageBasedSession session) { // Ensure termination character is enabled as here in example we use a SOCKET connection. session.TerminationCharacterEnabled = true; // Request information about an instrument. session.FormattedIO.WriteLine("*IDN?"); - string idn = session.FormattedIO.ReadLine(); - Console.WriteLine("Instrument information: {0}", idn); + string instrumentInfo = session.FormattedIO.ReadLine(); + Console.WriteLine($"Instrument information: {instrumentInfo}"); } else { @@ -51,28 +56,27 @@ static void Main() } } } - catch (Exception ex) + catch (Exception exception) { - if (ex is TypeInitializationException && ex.InnerException is DllNotFoundException) + if (exception is TypeInitializationException && exception.InnerException is DllNotFoundException) { // VISA Shared Components is not installed. - Console.WriteLine("VISA implementation compatible with VISA.NET Shared Components {0} not found. Please install corresponding vendor-specific VISA implementation first.", VisaNetSharedComponentsVersion); + Console.WriteLine($"VISA implementation compatible with VISA.NET Shared Components {visaNetSharedComponentsVersion} not found. Please install corresponding vendor-specific VISA implementation first."); } - else if (ex is VisaException - && ex.Message == "No vendor-specific VISA .NET implementation is installed.") + else if (exception is VisaException && exception.Message == "No vendor-specific VISA .NET implementation is installed.") { // Vendor-specific VISA.NET implementation is not available. - Console.WriteLine("VISA implementation compatible with VISA.NET Shared Components {0} not found. Please install corresponding vendor-specific VISA implementation first.", VisaNetSharedComponentsVersion); + Console.WriteLine($"VISA implementation compatible with VISA.NET Shared Components {visaNetSharedComponentsVersion} not found. Please install corresponding vendor-specific VISA implementation first."); } - else if (ex is EntryPointNotFoundException) + else if (exception is EntryPointNotFoundException) { - // Installed VISA Shared Components is not compatible with VISA.NET Shared Components - Console.WriteLine("Installed VISA Shared Components version {0} does not support VISA.NET {1}. Please upgrade VISA implementation.", VisaSharedComponentsInfo.ProductVersion, VisaNetSharedComponentsVersion); + // Installed VISA Shared Components are not compatible with VISA.NET Shared Components. + Console.WriteLine($"Installed VISA Shared Components version {visaNetSharedComponentsVersion} does not support VISA.NET. Please upgrade VISA implementation."); } else { // Handle remaining errors. - Console.WriteLine("Exception: {0}", ex.Message); + Console.WriteLine($"Exception: {exception.Message}"); } } diff --git a/README.md b/README.md index a316cfe..2d59929 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,47 @@ [![Build Status Github](https://github.com/vnau/IviVisaNetSample/actions/workflows/build.yml/badge.svg)](https://github.com/vnau/IviVisaNetSample/actions/workflows/build.yml) [![Build Status AppVeyor](https://ci.appveyor.com/api/projects/status/dag3r35u0sn1sci3?svg=true)](https://ci.appveyor.com/project/vnau/IviVisaNetSample) -In traditional approach [VISA.NET Shared Components](http://www.ivifoundation.org/shared_components/) distributed only as part of a vendor's installer for its VISA implementation. -This approach suppose installation of vendor's VISA library implementation on CI server environment even if communication with instruments is not required on this stage. +In the traditional approach, [VISA.NET Shared Components](http://www.ivifoundation.org/shared_components/) are distributed solely as part of a vendor's installer for its VISA implementation. +This approach necessitates the installation of the vendor's VISA library implementation on the CI server environment, even if communication with instruments is not required at this stage. -If developed application assumed to work with various third-party VISA implementations and no VISA libraries were installed it would be nice if it could provide only a part of the functionality or report VISA library necessity. +If a developed application is intended to work with various third-party VISA implementations, and no VISA libraries are installed, it would be beneficial if it could provide only a part of the functionality or report the necessity of the VISA library. -This is simple example of application bypassing those limitations using unofficial NuGet VISA.NET Shared Components distribution [Kelary.Ivi.Visa](https://www.nuget.org/packages/Kelary.Ivi.Visa/). +This is a simple example of an application bypassing those limitations by using the unofficial NuGet VISA.NET Shared Components distribution, [Kelary.Ivi.Visa](https://www.nuget.org/packages/Kelary.Ivi.Visa/). -### VISA.NET implementations ### +### Using VISA.NET in .NET 5+ solutions ### -In most cases, an application built with VISA.NET Shared Components version 5.5 will work with latter implementations of Shared Components. +.NET Standard, introduced in 2016, marked a pivotal moment in the evolution of the .NET ecosystem. +Since then, many versions of .NET have emerged, diminishing the relevance of the traditional .NET Framework for new projects. -Below is a non-exhausting list of vendor-specific VISA implementations with VISA.NET support. +Despite these advancements, VISA.NET remains tied to .NET Framework 2.0, with no indication from the IVI Foundation of plans to embrace modern technologies. + +A notable challenge is VISA.NET's limited integration into projects with contemporary .NET runtimes. +However, compatibility has improved since .NET Core 2, allowing referencing of .NET Framework assemblies in compatibility mode. This suggests potential usability of the VISA.NET library and .NET Framework implementations within a modern .NET runtime. + +Another challenge arises as the modern .NET runtime no longer uses the GAC, which VISA.NET relies on. +This issue is mitigated by preloading VISA.NET implementations. + +In this repository, an **experimental** .NET 8 example application showcases potential VISA.NET usage with various vendors implementations. +Despite progress, successful execution is not guaranteed, as the .NET runtime may lack support for all .NET Framework APIs. +Basic functions have been tested with Rohde & Schwarz and Keysight implementations, but some functions may require further testing. + +We look forward to the IVI Foundation moving the VISA.NET library from the .NET Framework to the .Net Standard, which will allow VISA.NET to become not only interchangeable, but also cross-platform. + +### Existing VISA.NET implementations ### + +In most cases, an application built with VISA.NET Shared Components version 5.5 will work with later implementations of Shared Components. +For .NET 5+ projects, the Shared Components version must match those that the implementation depends on. + +Below is a non-exhaustive list of vendor-specific VISA implementations with VISA.NET support. | Implementation | Size | VISA.NET Shared Components Version | | --- | ---- | ---- | | [Rohde & Schwarz VISA 7.2.3 for Windows](https://scdn.rohde-schwarz.com/ur/pws/dl_downloads/dl_application/application_notes/1dc02___rs_v/RS_VISA_Setup_Win_7_2_3.exe)| 63 MB | 7.2 | -| [NI-VISA 2023 Q4](https://www.ni.com/en/support/downloads/drivers/download.ni-visa.html)| 1.41 GB | 7.2 | +| [NI-VISA 2023 Q4](https://www.ni.com/en/support/downloads/drivers/download.ni-visa.html#494653)| 1.41 GB | 7.2 | | [Rohde & Schwarz VISA 5.12.3 for Windows](https://www.rohde-schwarz.com/us/applications/r-s-visa-application-note_56280-148812.html) | 59 MB | 5.11 | | [Keysight IO Libraries Suite 2019](https://www.keysight.com/main/software.jspx?id=2175637) | 251 MB | 5.11 | -| [NI-VISA 20.0](https://www.ni.com/ru-ru/support/downloads/drivers/download.ni-visa.html#346210)| 1.16 GB | 5.11 | +| [NI-VISA 20.0](https://www.ni.com/en/support/downloads/drivers/download.ni-visa.html#346210)| 1.16 GB | 5.11 | | [Keysight IO Libraries Suite 2018](https://www.keysight.com/main/software.jspx?id=2175637) | 260 MB | 5.8 | | [Keysight IO Libraries Suite 17.2](https://www.keysight.com/main/software.jspx?id=2784293) | 191 MB | 5.6 | -| [NI-VISA 15.0,17.5](http://www.ni.com/download/ni-visa-17.5/7220/en/) | 756 MB | 5.6 | +| [NI-VISA 15.0,17.5](https://www.ni.com/en/support/downloads/drivers/download.ni-visa.html#306106) | 122 MB | 5.6 | | [Kikusui KI-VISA 5.5](https://www.kikusui.co.jp/en/download/en/?fn=com_kivisa) | 89 MB | 5.5 |