Gents,
I’m looking for solve an issue that occur in the following conditions:
Dgn = MstnApp.CreateDesignFile(Template, Filename, OpenDgn)
the error message is shown 6 times in the Microstation Text Window and it is the following:
OS could not load C:\Program Files\Bentley\MicroStation CONNECT Edition\MicroStation\mdlsys\asneeded\helpload.dll, error 126.
MDL Loader: Unable to load library (DLL or MDL shared library) helpload
Note that this error does not occur if the AddIn is not loaded.
The AddIn has been developed starting for the example WPFDemo.
I’m using Microstation Connect Update 13, version 10.13.01.01
The AddIn and external application are developed using VS2019, version 16.8.3, target framework .Net framework 4.7.2.
Can someone heap me?
Many thanks
This is the function which creates a new design file and it does not catch any exception.
Public Function Mstn_CreateDgn(Template As String, Filename As String, Optional _ OpenDgn As Boolean = True) As Integer If MstnApp.HasActiveDesignFile Then If String.Compare(MstnApp.ActiveDesignFile.FullName, Filename, True) = 0 Then MstnApp.ActiveDesignFile.Close() End If End If Try If IO.File.Exists(Filename) Then IO.File.Delete(Filename) End If Dgn = MstnApp.CreateDesignFile(Template, Filename, OpenDgn) Return 1 Catch ex As Exception Return 0 End Try End Function
Paolo Cherubini said:This is the function which creates a new design file and it does not catch any exception
Your .exe runs and completes successfully?
.exe
I suggest that you divide and conquer! For diagnostic purposes, divide your .exe into three, and test each part separately...
Test ActiveDesignFile.Close
If MstnApp.HasActiveDesignFile Then If String.Compare(MstnApp.ActiveDesignFile.FullName, Filename, True) = 0 Then MstnApp.ActiveDesignFile.Close() End If End If
Test IO.File.Delete(Filename)
If IO.File.Exists(Filename) Then IO.File.Delete(Filename) End If
Test CreateDesignFile
Regards, Jon Summers LA Solutions
Hi, Jan,
Yes, the application written in vb.net is working without problems if the AddIn is not loaded. I tested the three steps as you suggested with the AddIn loaded. The issue arises when the application calls the CreateDesignFile method, while no problems occurred when ActiveDesignFile.Close method is called and when the existing file is deleted. The vb.net application runs successfully also when the issue is raised. In some cases, the vb.net application activates the AddIn to perform some works and also this processing is completed successfully. However, after several runs, some Microstation tools, like "Properties" raise an exception.
Can this issue related to MicroStation Connect version, or a specific setting is required during Connect installation in order to avoid similar issues?
the AddIn is configured to use x64 and during the compilation a warning appears because microstation is configured to use AMD64. Can this different configuration cause this issue?
Thanks in advance
Paolo Cherubini said: The issue arises when the application calls the CreateDesignFile method
Paolo Cherubini said:the AddIn is configured
You may need to add some state handlers to your addin. There are several .NET handlers that call your AddIn when certain events happen. For example...
protected override int Run(string[] commandLine) { // Application initialization code RegisterEventHandlers(); ... return 0; }
private void RegisterEventHandlers() { ReloadEvent += YourApp_ReloadEvent; UnloadedEvent += YourApp_UnloadedEvent; Session.Instance.OnMasterFileStart += OnMasterFileStart; Session.Instance.OnModelRefActivate += OnModelActivate; }
Write those handlers and include a message in each, so you can see when they are called.
first of all, thank you for your support.
The issue arises after the event OnModelRefActivated and before the event OnMasterFileStart. However, during last debugging sessions, I noted some anomalies related to Microstation start. The diagnostic shows among others the following messages:
Assembly resolver failed to load assembly: "Bentley.DrawingScale.resources"
Assembly resolver failed to load assembly: "DgnDisplayCSUI2.resources"
Assembly resolver failed to load assembly: "Bentley.Visualization.LightsRibbonToolbar.resources"
Assembly resolver failed to load assembly: "Bentley.ViewGroupHistory.resources"
Assembly resolver failed to load assembly: "Bentley.ViewGroupList.resources"
…
After these messages, Microstation apparently work correctly, but I cannot be sure.
Maybe, before continuing the issue analysis, it would be better to reinstall Microstation Connect and verify if the above anomalies disappear.
Paolo Cherubini said:The issue arises after the event OnModelRefActivated and before the event OnMasterFileStart
Your code should not attempt anything until you receive the OnMasterFileStart message. Call your startup code from that handler.
If you start your AddIn using mdl load MyApp, then MicroStation has already started and the DGN file is open and stable. In that case you can call your startup code in the Run method as you do now.
mdl load MyApp
Run
protected override int Run (string[] commandLine) { // save a reference to our addin to prevent it from being garbage collected. s_AddIn = this; // Get the localized resources s_ResourceManager = Properties.Resources.ResourceManager; switch (this.ApplicationType) { case MdlApplicationType.User: // Now it's safe to do things like this... UpdateGuids(Session.Instance.GetActiveDgnFile()); Session.Instance.Keyin("MYAPP DIALOG OPEN"); break; } return 0; }
/// Called when a DGN file has been opened. /// Equivalent to MicroStationAPI OnNewDesignFile. /// param name="dgnFile" The DGN file just opened. private static void OnMasterFileStart(DgnFile dgnFile) { string s = null; switch (s_AddIn.ApplicationType) { case MdlApplicationType.DesignApp: s = $"Opening DGN file '{dgnFile.GetFileName()}' as DGNAPP"; break; case MdlApplicationType.User: s = $"Opening DGN file '{dgnFile.GetFileName()}' as USER"; break; case MdlApplicationType.InitApp: s = $"Opening DGN file '{dgnFile.GetFileName()}' as INITAPP"; break; } // Enable debug messages in MicroStation's Message Center to see MessageType.Debug MessageCenter.Instance.ShowMessage(MessageType.Debug, s, s, MessageAlert.None); UpdateGuids(dgnFile); AddIn.MicroStation.UI.MainPage.OpenWindow(null); }
The addin should do nothing when a drawing is closed, and another drawing is opened. I updated the code as you suggested but unfortunately the problem is still present.
The addin has the command table and the external app (the vb.net app) runs the addin by simulating the user commands:
'AddIn loading
MstnApp.CadInputQueue.SendCommand($"MDL LOAD ""{AppInfo.ExePath}Connect\MstnDrawAddIn"" ""{AppInfo.IniPath}""")
'send draw sheet command
MstnApp.CadInputQueue.SendCommand($"SHEET ""{Job.Name}"" ""{AppInfo.InputFile}""")
When the addin starts for the first time no exception occurs. The addin performs the work and remains in idle condition.
Then, the external app can select another drawing and repeat the process and, in such case, the exception occurs.
Definitely, I need to verify the Microstation installation (carried out through an automatic batch script). My impression is that something is not working correctly.
Hi Jan,
after many tests, hopefully I have identified the true source of the exception: the exception depends completely on the AddIn and not by the external application.
The exception is raised under the following circumstances:
Instead, the exception does not raise if the user changes the design file (because the addin is not unloaded).
This AddIn uses an assembly named Sealib, which uses several other assemblies including a GDAL plugin available at https://www.nuget.org/packages/GDAL/2.4.4?_src=template
Here there is the addin source code.
/*--------------------------------------------------------------------------------------+ | ROUTING ADDIN +--------------------------------------------------------------------------------------*/ using System; using System.Globalization; using System.Threading; using System.Resources; using System.Windows; using System.Windows.Threading; using Bentley.DgnPlatformNET; using Bentley.MstnPlatformNET; using SeaLib.Core; using SeaLib.Routing; namespace MstnRouteAddIn { /*====================================================================================**/ /// /// <summary>Singleton AddIn class</summary> /// /*==============+===============+===============+===============+===============+======*/ [AddInAttribute(MdlTaskID = "RouteAddIn")] public sealed class RouteApp : AddIn { private static RouteApp s_AddIn = null; private static ResourceManager s_ResourceManager; private static RoutingApplication appInfo = null; private static CRoutingLogin logingInfo = null; /*------------------------------------------------------------------------------------**/ /// <summary>Constructor for the AddIn</summary> /*--------------+---------------+---------------+---------------+---------------+------*/ private RouteApp (IntPtr mdlDesc) : base(mdlDesc) { s_AddIn = this; } /*------------------------------------------------------------------------------------**/ /// <summary>The Run method</summary> /*--------------+---------------+---------------+---------------+---------------+------*/ protected override int Run ( string[] commandLine ) { // save a reference to our addin to prevent it from being garbage collected. s_AddIn = this; // register event handler RegisterEventHandlers(); // Get the localized resources s_ResourceManager = Properties.Resources.ResourceManager; switch (this.ApplicationType) { case MdlApplicationType.User: // Now it's safe to do things like this... // Initialization InitializeRouting(); // open route Toolbar string unparsed = ""; RouteKeyins.OpenRoute(unparsed); break; } return 0; } /*------------------------------------------------------------------------------------**/ /// <summary>Static method to get the AddIn</summary> /*--------------+---------------+---------------+---------------+---------------+------*/ internal static RouteApp Instance { get { return s_AddIn; } } /*------------------------------------------------------------------------------------**/ /// <summary>Static method to get the ResourceManager</summary> /*--------------+---------------+---------------+---------------+---------------+------*/ internal static ResourceManager ResourceManager { get { return s_ResourceManager; } } internal static RoutingApplication RoutingApplication { get { return appInfo; } } internal static CRoutingLogin CRoutingLogin { get { return logingInfo; } } bool InitializeRouting() { //Initialize ApplicationInfo (static class in namespace Sealib.Core) ApplicationInfo.Initialize(1); //Configure GDAL (partial static class in the namespace Sealib.Routing) // This will raise an exception if: // - this AddIn is unloaded when a design file is closed // - a new design file is opened GdalConfiguration.ConfigureGdal(); if (!GdalConfiguration.Usable) throw new InvalidOperationException("GDAL unavailable"); // Tested. Do not raise exception appInfo = new RoutingApplication(); appInfo.Initialize(); logingInfo = new CRoutingLogin(); logingInfo.Initialize(appInfo); return true; } #region "Event Handlers" /*------------------------------------------------------------------------------------**/ /// <summary>Static method to get the ResourceManager</summary> /*--------------+---------------+---------------+---------------+---------------+------*/ private void RegisterEventHandlers() { ReloadEvent += ThisApp_ReloadEvent; UnloadedEvent += ThisApp_UnloadedEvent; Session.Instance.OnMasterFileStop += OnMasterFileStop; Session.Instance.OnMasterFileStart += OnMasterFileStart; Session.Instance.OnMasterFileChanging += OnMasterFileChaning; Session.Instance.OnModelRefActivated += OnModelActivated; } public void ThisApp_ReloadEvent(AddIn sender, ReloadEventArgs eventArgs) { System.Diagnostics.Trace.WriteLine($"Reload event {sender.MdlTaskId}"); } public void ThisApp_UnloadedEvent(AddIn sender, UnloadedEventArgs eventArgs) { System.Diagnostics.Trace.WriteLine($"Unloaded Event {sender.MdlTaskId}"); } public void OnMasterFileChaning(DgnFile dgnfile) { // for debugging: FileChanging does not raise any exception string s = $"OnMasterFileChaning {dgnfile.GetFileName()}"; MessageCenter.Instance.ShowMessage(MessageType.Info, s, s, MessageAlert.None); System.Diagnostics.Trace.WriteLine(s); } public void OnMasterFileStop(DgnFile dgnfile) { string s = $"OnMasterFileStop {dgnfile.GetFileName()}"; MessageCenter.Instance.ShowMessage(MessageType.Info, s, s, MessageAlert.None); System.Diagnostics.Trace.WriteLine(s); } public void OnMasterFileStart(DgnFile dgnFile) { string s = null; switch (s_AddIn.ApplicationType) { case MdlApplicationType.DesignApp: s = $"Opening DGN file '{dgnFile.GetFileName()}' as DGNAPP"; break; case MdlApplicationType.User: s = $"Opening DGN file '{dgnFile.GetFileName()}' as USER"; break; case MdlApplicationType.InitApp: s = $"Opening DGN file '{dgnFile.GetFileName()}' as INITAPP"; break; } // Enable debug messages in MicroStation's Message Center to see MessageType.Debug MessageCenter.Instance.ShowMessage(MessageType.Debug, s, s, MessageAlert.None); System.Diagnostics.Trace.WriteLine(s); } public void OnModelActivated(DgnModelRef newModelRef, DgnModelRef oldModelRef) { System.Diagnostics.Trace.WriteLine($"OnModelActivated {newModelRef.GetDgnFile().GetFileName()}"); } #endregion } }
GDAL plugin require a configuration before use. The assembly Sealib is written in vb and the GDAL configuration is setup using this class.
'****************************************************************************** '* '* Name: GdalConfiguration.vb.pp '* Project: GDAL VB.NET Interface '* Purpose: A static configuration utility class to enable GDAL/OGR. '* Author: Felix Obermaier '* '****************************************************************************** '* Copyright (c) 2012-2018, Felix Obermaier '* '* Permission is hereby granted, free of charge, to any person obtaining a '* copy of this software and associated documentation files (the "Software"), '* to deal in the Software without restriction, including without limitation '* the rights to use, copy, modify, merge, publish, distribute, sublicense, '* and/or sell copies of the Software, and to permit persons to whom the '* Software is furnished to do so, subject to the following conditions: '* '* The above copyright notice and this permission notice shall be included '* in all copies or substantial portions of the Software. '* '* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS '* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, '* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL '* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER '* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING '* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER '* DEALINGS IN THE SOFTWARE. '*****************************************************************************/ Option Infer On Imports System.IO Imports System.Reflection Imports System.Runtime.InteropServices Imports Gdal = OSGeo.GDAL.Gdal Imports Ogr = OSGeo.OGR.Ogr Namespace Routing ''' <summary> ''' Configuration class for GDAL/OGR ''' </summary> Partial Public Class GdalConfiguration Private Shared _configuredOgr As Boolean Private Shared _configuredGdal As Boolean Private Shared _usable As Boolean <DllImport("kernel32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> Public Shared Function SetDefaultDllDirectories(directoryFlags As UInteger) As Boolean End Function ' LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 Private Const DllSearchFlags As UInteger = &H400 Or &H800 <DllImport("kernel32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)> Public Shared Function AddDllDirectory(lpPathName As String) As <MarshalAs(UnmanagedType.Bool)> Boolean End Function ''' <summary> ''' Construction of Gdal/Ogr ''' </summary> Shared Sub New() Dim nativePath As String = Nothing Dim executingDirectory As String = Nothing Dim gdalPath As String = Nothing Try If Not IsWindows Then Const notSet As String = "_Not_set_" Dim tmp As String = Gdal.GetConfigOption("GDAL_DATA", notSet) _usable = (tmp <> notSet) Return End If Dim executingAssemblyFile As String = New Uri(Assembly.GetExecutingAssembly.GetName.CodeBase).LocalPath executingDirectory = Path.GetDirectoryName(executingAssemblyFile) If String.IsNullOrEmpty(executingDirectory) Then Throw New InvalidOperationException("cannot get executing directory") End If 'la cartella gdal potrebbe essere una sottocartella dell'eseguibile 'oppure trovarsi anche in una cartella allo stesso livello delle executingfolder Dim parentExecuting As String = Path.GetDirectoryName(executingDirectory) Dim parentGDal As String = executingDirectory 'cerco gdal nella executing e nella parentExecutin If Not Directory.Exists(Path.Combine(executingDirectory, "gdal")) Then If Directory.Exists(Path.Combine(parentExecuting, "gdal")) Then parentGDal = parentExecuting End If End If SetDefaultDllDirectories(DllSearchFlags) gdalPath = Path.Combine(parentGDal, "gdal") nativePath = Path.Combine(gdalPath, GetPlatform()) If Not Directory.Exists(nativePath) Then Throw New DirectoryNotFoundException($"GDAL native directory not found at '{nativePath}'") End If If Not File.Exists(Path.Combine(nativePath, "gdal_wrap.dll")) Then Throw New FileNotFoundException($"GDAL native wrapper file not found at '{Path.Combine(nativePath, ", gdal_wrap.dll, ")}'") End If AddDllDirectory(nativePath) AddDllDirectory(Path.Combine(nativePath, "plugins")) ' Set the additional GDAL environment variables. Dim gdalData As String = Path.Combine(gdalPath, "data") Environment.SetEnvironmentVariable("GDAL_DATA", gdalData) Gdal.SetConfigOption("GDAL_DATA", gdalData) Dim driverPath As String = Path.Combine(nativePath, "plugins") Environment.SetEnvironmentVariable("GDAL_DRIVER_PATH", driverPath) Gdal.SetConfigOption("GDAL_DRIVER_PATH", driverPath) Environment.SetEnvironmentVariable("GEOTIFF_CSV", gdalData) Gdal.SetConfigOption("GEOTIFF_CSV", gdalData) Dim projSharePath As String = Path.Combine(gdalPath, "share") Environment.SetEnvironmentVariable("PROJ_LIB", projSharePath) Gdal.SetConfigOption("PROJ_LIB", projSharePath) _usable = True Catch e As Exception _usable = False Trace.WriteLine(e, "error") Trace.WriteLine($"Executing directory: {executingDirectory}", "error") Trace.WriteLine($"gdal directory: {gdalPath}", "error") Trace.WriteLine($"native directory: {nativePath}", "error") 'throw; End Try End Sub ''' <summary> ''' Gets a value indicating if the GDAL package is set up properly. ''' </summary> Public Shared ReadOnly Property Usable As Boolean Get Return _usable End Get End Property ''' <summary> ''' Method to ensure the static constructor is being called. ''' </summary> ''' <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks> Public Shared Sub ConfigureOgr() If Not _usable Then Return End If If _configuredOgr Then Return End If ' Register drivers Ogr.RegisterAll() _configuredOgr = True PrintDriversOgr() End Sub ''' <summary> ''' Method to ensure the static constructor is being called. ''' </summary> ''' <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks> Public Shared Sub ConfigureGdal() If Not _usable Then Return End If If _configuredGdal Then Return End If ' Register drivers Gdal.AllRegister() _configuredGdal = True PrintDriversGdal() End Sub ''' <summary> ''' Function to determine which platform we're on ''' </summary> Private Shared Function GetPlatform() As String If (Environment.Is64BitProcess) Then Return "x64" Return "x86" End Function ''' <summary> ''' Gets a value indicating if we are on a windows platform ''' </summary> Private Shared ReadOnly Property IsWindows As Boolean Get Dim res = Not ((Environment.OSVersion.Platform = PlatformID.Unix) _ OrElse (Environment.OSVersion.Platform = PlatformID.MacOSX)) Return res End Get End Property Private Shared Sub PrintDriversOgr() #If (DEBUG) Then If _usable Then Dim num = Ogr.GetDriverCount Dim i = 0 Do While (i < num) Dim driver = Ogr.GetDriver(i) Trace.WriteLine($"OGR {i}: {driver.GetName()}", "Debug") i = (i + 1) Loop End If #End If End Sub Private Shared Sub PrintDriversGdal() #If (DEBUG) Then If _usable Then Dim num = Gdal.GetDriverCount Dim i = 0 Do While (i < num) Dim driver = Gdal.GetDriver(i) Trace.WriteLine($"GDAL {i}: {driver.ShortName}-{driver.LongName}") i = (i + 1) Loop End If #End If End Sub End Class End Namespace
There also the corresponding version of this class, written in c#
/****************************************************************************** * * Name: GdalConfiguration.cs.pp * Project: GDAL CSharp Interface * Purpose: A static configuration utility class to enable GDAL/OGR. * Author: Felix Obermaier * ****************************************************************************** * Copyright (c) 2012-2018, Felix Obermaier * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *****************************************************************************/ using System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using Gdal = OSGeo.GDAL.Gdal; using Ogr = OSGeo.OGR.Ogr; namespace SeaLib.Routing.Tests { public static partial class GdalConfiguration { private static volatile bool _configuredOgr; private static volatile bool _configuredGdal; private static volatile bool _usable; [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)] static extern bool SetDefaultDllDirectories(uint directoryFlags); // LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 private const uint DllSearchFlags = 0x00000400 | 0x00000800; [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool AddDllDirectory(string lpPathName); /// <summary> /// Construction of Gdal/Ogr /// </summary> static GdalConfiguration() { string executingDirectory = null, gdalPath = null, nativePath = null; try { if (!IsWindows) { const string notSet = "_Not_set_"; string tmp = Gdal.GetConfigOption("GDAL_DATA", notSet); _usable = tmp != notSet; return; } string executingAssemblyFile = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase).LocalPath; executingDirectory = Path.GetDirectoryName(executingAssemblyFile); if (string.IsNullOrEmpty(executingDirectory)) throw new InvalidOperationException("cannot get executing directory"); // modify search place and order SetDefaultDllDirectories(DllSearchFlags); gdalPath = Path.Combine(executingDirectory, "gdal"); nativePath = Path.Combine(gdalPath, GetPlatform()); if (!Directory.Exists(nativePath)) throw new DirectoryNotFoundException($"GDAL native directory not found at '{nativePath}'"); if (!File.Exists(Path.Combine(nativePath, "gdal_wrap.dll"))) throw new FileNotFoundException( $"GDAL native wrapper file not found at '{Path.Combine(nativePath, "gdal_wrap.dll")}'"); // Add directories AddDllDirectory(nativePath); AddDllDirectory(Path.Combine(nativePath, "plugins")); // Set the additional GDAL environment variables. string gdalData = Path.Combine(gdalPath, "data"); Environment.SetEnvironmentVariable("GDAL_DATA", gdalData); Gdal.SetConfigOption("GDAL_DATA", gdalData); string driverPath = Path.Combine(nativePath, "plugins"); Environment.SetEnvironmentVariable("GDAL_DRIVER_PATH", driverPath); Gdal.SetConfigOption("GDAL_DRIVER_PATH", driverPath); Environment.SetEnvironmentVariable("GEOTIFF_CSV", gdalData); Gdal.SetConfigOption("GEOTIFF_CSV", gdalData); string projSharePath = Path.Combine(gdalPath, "share"); Environment.SetEnvironmentVariable("PROJ_LIB", projSharePath); Gdal.SetConfigOption("PROJ_LIB", projSharePath); _usable = true; } catch (Exception e) { _usable = false; Trace.WriteLine(e, "error"); Trace.WriteLine($"Executing directory: {executingDirectory}", "error"); Trace.WriteLine($"gdal directory: {gdalPath}", "error"); Trace.WriteLine($"native directory: {nativePath}", "error"); //throw; } } /// <summary> /// Gets a value indicating if the GDAL package is set up properly. /// </summary> public static bool Usable { get { return _usable; } } /// <summary> /// Method to ensure the static constructor is being called. /// </summary> /// <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks> public static void ConfigureOgr() { if (!_usable) return; if (_configuredOgr) return; // Register drivers Ogr.RegisterAll(); _configuredOgr = true; PrintDriversOgr(); } /// <summary> /// Method to ensure the static constructor is being called. /// </summary> /// <remarks>Be sure to call this function before using Gdal/Ogr/Osr</remarks> public static void ConfigureGdal() { if (!_usable) return; if (_configuredGdal) return; // Register drivers Gdal.AllRegister(); _configuredGdal = true; PrintDriversGdal(); } /// <summary> /// Function to determine which platform we're on /// </summary> private static string GetPlatform() { return Environment.Is64BitProcess ? "x64" : "x86"; } /// <summary> /// Gets a value indicating if we are on a windows platform /// </summary> private static bool IsWindows { get { var res = !(Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX); return res; } } private static void PrintDriversOgr() { #if DEBUG if (_usable) { var num = Ogr.GetDriverCount(); for (var i = 0; i < num; i++) { var driver = Ogr.GetDriver(i); Trace.WriteLine($"OGR {i}: {driver.GetName()}", "Debug"); } } #endif } private static void PrintDriversGdal() { #if DEBUG if (_usable) { var num = Gdal.GetDriverCount(); for (var i = 0; i < num; i++) { var driver = Gdal.GetDriver(i); Trace.WriteLine($"GDAL {i}: {driver.ShortName}-{driver.LongName}"); } } #endif } } }
I went through GDAL configuration static class, but I couldn’t find anything that should cause an exception. May the calls SetDefaultDllDirectories or AddDllDirectory (in kernel32.dll) alter something in the Microstation environment?
thanks
Hi Paolo,
thanks for the details
I read again the whole conversation and right now I am not sure whether I understood the situation right, because:
How these two pieces of the code, that run in separate processes (addin shares MicroStation process, external app is another process) communicates?
Paolo Cherubini said:Instead, the exception does not raise if the user changes the design file (because the addin is not unloaded).
Yes, it's correct. When design file is closed, addins have to be loaded again.
A standard solution, when particular addin should be loaded automatically (and the application is not loaded through key-in), is to configure MicroStation to load it, e.g. through MS_DGNAPPS variable.
With regards,
Jan
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
Hi Jon, Jan,
Thanks for your support once again.
Initially, I thought that the exception is caused when an external application applies the method CreateDesignFile, but after many tests, I understood that this not the root source of error.
The root source of error appears to be entirely in the AddIn and more specifically related to the static class necessary to configure GDAL plugin.
Currently this AddIn opens a tollbar and does not do anything else. If GDAL configuration class is called, the exception raises, otherwise not.
Moreover, note that the use of other classes ApplicationInfo (static class), RoutingApplication and CRoutingLogin belonging to the same assembly SeaLib do not raise exceptions.
The classes ApplicationInfo and GDAL configuration look like similar for some elements, so I cannot understand why the GDAL configuration class raises the exception.
Here you can find the ApplicationInfo class.
Option Explicit On Option Strict On Imports System.Reflection Imports System.IO Namespace Core Public Class ApplicationInfo ''' <summary> ''' simple shared class for basic info about an application avoiding the use of VB specific objects ''' </summary> Private Shared NotInitialized As Boolean = True Private Shared _Name As String = "" Private Shared _ProductName As String = "" Private Shared _ExePath As String = "" Private Shared _Description As String = "" Private Shared _Title As String = "" Private Shared _Version As String = "" Private Shared _VersionBuilt As String = "" Private Shared _TradeMark As String = "" Private Shared _CompanyName As String = "" Public Shared ReadOnly Property Name() As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _Name End Get End Property Public Shared ReadOnly Property ExePath As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _ExePath End Get End Property Public Shared ReadOnly Property Description As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _Description End Get End Property Public Shared ReadOnly Property ProductName As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _ProductName End Get End Property Public Shared ReadOnly Property Title As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _Title End Get End Property Public Shared ReadOnly Property TradeMark As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _TradeMark End Get End Property Public Shared ReadOnly Property CompanyName As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _CompanyName End Get End Property Public Shared ReadOnly Property Version As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _Version End Get End Property Public Shared ReadOnly Property VersionBuilt As String Get If NotInitialized Then Throw New Exception("ApplicationInfo not initialized") End If Return _VersionBuilt End Get End Property ''' <summary> ''' Initializes this class. this method shall be called before any other request ''' </summary> ''' <param name="EntryOrCalling">defines if the info shall be recovered by the main application or from the addin</param> Public Shared Sub Initialize(EntryOrCalling As Integer) NotInitialized = False Dim asm As Assembly If EntryOrCalling = 0 Then asm = Assembly.GetEntryAssembly Else asm = Assembly.GetCallingAssembly End If _Name = Path.GetFileNameWithoutExtension(Application.ExecutablePath) _Name = asm.GetName.Name Dim w = asm.GetName.Version _Version = w.Major & "." & w.Minor _VersionBuilt = Version & "." & w.Revision 'Executing path Dim executingAssemblyFile = New Uri(asm.GetName().CodeBase).LocalPath _ExePath = Path.GetDirectoryName(executingAssemblyFile) Try _ProductName = Application.ProductName Dim attr = DirectCast(asm.GetCustomAttribute(GetType(AssemblyProductAttribute)), AssemblyProductAttribute) _ProductName = attr.Product Catch ex As Exception End Try 'Application Title Try _Title = Application.ProductName Dim attrTitle = asm.GetCustomAttribute(GetType(AssemblyTitleAttribute)) If attrTitle IsNot Nothing Then _Title = DirectCast(attrTitle, AssemblyTitleAttribute).Title End If Catch ex As Exception End Try 'Application Description _Description = "" Try Dim attrDescr = asm.GetCustomAttribute(GetType(AssemblyDescriptionAttribute)) If attrDescr IsNot Nothing Then _Description = DirectCast(attrDescr, AssemblyDescriptionAttribute).Description End If Catch ex As Exception End Try 'Company _CompanyName = Application.CompanyName Try Dim attrCompany = asm.GetCustomAttribute(GetType(AssemblyCompanyAttribute)) If attrCompany IsNot Nothing Then _CompanyName = DirectCast(attrCompany, AssemblyCompanyAttribute).Company End If Catch ex As Exception End Try 'Trademark _TradeMark = "" Try Dim attrTradeMark = asm.GetCustomAttribute(GetType(AssemblyTrademarkAttribute)) If attrTradeMark IsNot Nothing Then _TradeMark = DirectCast(attrTradeMark, AssemblyTrademarkAttribute).Trademark End If Catch ex As Exception End Try End Sub End Class End Namespace