1

We are building an application with visual studios 2017 using wpf, C# and Prism v6.1.0.0. We have a 3d view that is an Esri .net runtime SceneView. We wanted to use the GetElevationAsync(mapPoint) function to get elevation data from DTED level 0 data. In a stand-alone application using just Esri SceneView the GetElevationAsync(mapPoint) function works for both the SceneView and MapView if the SceneView is active. This is also using FileElevationSource and loading in DTED level 0 into the FileElevationSource and then adding that to the SceneView.Scene.Surface.

The issue we are having is when we try and call the GetElevationAsync(mapPoint) we get an System.AccessViolationException. Has anyone else tried using ESRi's .net runtime and Prism to create a SceneView application that is using the GetElevationAsync(mapPoint) function?

What are have is a Prism application with multiple view and a main shell. The SceneView Module has a service and was using this server to load the DTED level 0 data into the SceneView.Scene.Surface. I have moved all the functionality into the SceneViewView and we still get the same access error. The calling Thread is the main application thread. I have post the error and some code snippets. The same code I have in the Prism application is the same code I have in a simple WPF application that is using all the same controls but not a Prism architecture. It works great and I can get the eleveation data just by activating the Sceneview and passing a mapoint from the Mapview into the GetElevationAsync function with no issue.

  private void OnSceneViewViewLoaded(object sender, RoutedEventArgs e)
  {
     SceneViewService = UnityContainer.Resolve<ISceneViewService>();

     string elevationSourcePath = System.Environment.GetEnvironmentVariable("SHELL") + "\\Resources\\Terrain\\DTED\\Level0\\";
     AddElevationSources(elevationSourcePath);
     mSceneView.MouseMove += OnSceneViewMouseMove;
  }
  private void OnSceneViewMouseMove(object sender, MouseEventArgs e)
  {
     {
        Point screenPoint = e.GetPosition(mSceneView);
        double elevation = 0.0;
        MapPoint point = mSceneView.ScreenToLocation(screenPoint);
        if (point != null)
        {
           MapPoint mapPoint = GeometryEngine.Project(point, SpatialReferences.Wgs84) as MapPoint;

           elevation = GetElevation(mapPoint).Result;

           if (!Double.IsNaN(elevation))
           {
              mElevationStatusBarTextBlock.Text = elevation.ToString();
           }
        }
     }
  }
  public void AddElevationSources(string elevationSourcePath)
  {
     FilenameCollection mFilenameCollection = new FilenameCollection();
     List<String> files = new List<String>();

     try
     {
        files = DirSearch(elevationSourcePath);

        foreach (String file in files)
           mFilenameCollection.Add(file);

        mFileElevationSource.Filenames = mFilenameCollection;
        mFileElevationSource.ID = "Elevation Source";
        mSceneView.Scene.Surface.Add(mFileElevationSource);
        mFileElevationSource.IsEnabled = true;
     }
     catch (Exception excpt)
     {
        Console.WriteLine("AddElevationSources, ElevationSourceService " + excpt.Message);
     }
  }
  public List<String> DirSearch(string sourceDirectory)
  {
     List<String> files = new List<String>();
     try
     {
        foreach (string file in Directory.GetFiles(sourceDirectory, "*.dt0"))
        {
           files.Add(file);
        }
        foreach (string directory in Directory.GetDirectories(sourceDirectory))
        {
           files.AddRange(DirSearch(directory));
        }

     }
     catch (Exception excpt)
     {
        Console.WriteLine("DirSearch, AddElevationSources " + excpt.Message);
     }
     return files;
  }

Map Point data being passed “mapPoint = {MapPoint[X=4.54778361440582, Y=27.7940801510867, Z=5.58793544769287E-09, Wkid=4326]}”

  public async Task<double> GetElevation(MapPoint mapPoint)
  {
     double elevation = 0.0;

     try
     {
        if (!Double.IsNaN(mapPoint.X) && !Double.IsNaN(mapPoint.Y))
        {
           elevation = await mFileElevationSource.GetElevationAsync(mapPoint);
           if (Double.IsNaN(elevation))
              elevation = 0;
        }
     }
     catch (Exception excpt)
     {
        Console.WriteLine("Task<double> GetElevation, ElevationSourceModule " + excpt.Message);
     }

     return elevation;
  }
}

System.AccessViolationException occurred HResult=0x80004003 Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. Source=Esri.ArcGISRuntime StackTrace: at runtimeCoreNet.CoreLocalElevationRaster.LocalElevationLayerPickElevation(IntPtr pNativeElevationLayer, Double x, Double y, Double& z) at Esri.ArcGISRuntime.Controls.FileElevationSource.GetElevationAsync(MapPoint point) at SceneViewModule.Views.SceneViewView.SceneViewView.d__19.MoveNext() in \SceneViewModule\Views\SceneViewView\SceneViewView.xaml.cs:line 141

Eric Boice
  • 11
  • 2
  • Just curious why you are using v4 of Prism? You know Prism 6.3 is out, and 4 is no longer supported or maintained right? –  Mar 27 '17 at 22:38
  • Could you enable "native debugging" in the project settings, and share the callstack that you get when the crash occurs? It might give me something to go on. – dotMorten Mar 27 '17 at 22:47
  • Yes i will enable "native debugging" today and look at the results. Good idea. – Eric Boice Mar 29 '17 at 17:22
  • System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.' in Esri.ArcGISRuntime.dll. This is using the same async task and await as the prototype application. the GetElevationAsync doesnt seem to play nice with Prism. – Eric Boice Mar 29 '17 at 21:20
  • Can you share a repro sample somewhere, and I'll be more than happy to debug the internals and see if I can't get you a solution. – dotMorten Mar 30 '17 at 18:16
  • I might be able to recreate this in a small sample application that i can post the code for. At this point decoupling all the elements to isolate the specific section of the code would be a mess. I will work on just the code examples and the specific module that is having the issue. – Eric Boice Mar 31 '17 at 19:52

1 Answers1

0

You mentioned you are using it within Unity?

The GetElevationAsync APIs only work with it in an active SceneView rendering. While the error doesn't sound right, this API will not work at this point stand-alone outside the SceneView (it's on our list for future enhancements though). It's main purpose at this point is to click the SceneView and get an accurate elevation for that point. It's not meant to be stand-alone. I'm guessing there's a bit of error handling not checking correctly for this, which is why you're seeing a crash. But if it were to be fixed, all you would get would be a better error message.

dotMorten
  • 1,953
  • 1
  • 14
  • 10
  • Prism.Unity.Wpf and Prism.Wpf, runtime version v4.0.30319, release 6.1.0.0. Running in a stand along wpf application the GetElevationAsync works great. When we setup the exact same situation but using Prism and the SceneView running in a module we get access violation when making the GetElevationAsync call. Yes i have setup an active SceneView and i am passing in the map point when the mouse point is moved. This works fine in the prototype not using Prism and Unity. – Eric Boice Mar 29 '17 at 17:21