Hi ForumI have made a little edit utility for ArcMap. It works well, but about once a day ArcMap will close unexpectedly, leaving a message like the attached png. Different dll's like nt.dll, EditTools.dll and Geometry.dll experience uncaught Access Violation Errors.I am not sure if my utility is causing these errors, but they seem to occur more often, when this utility is used.One of the things I am not sure of is my use of ESRI's projection Engine.I followed the advices on this thread: Can I get the Geodesic Angle directly from projection Engine? and it does work.1) I made a fairly simple class ProjectionEngineWrap as an excerpt from Richie Carmichael's example. But should I give it a GUID and find it with findExtension()?2) Should I do something special in order to make it threadsafe?3) My Class Edithelper uses an instance of ProjectionEngineWrap. When I am finished with the instance, is it sufficient, as I do, to call dispose() and set the member variable to null, or should I do something more?I am using ArcGis 9.3.1 and C# in Visual Studio I would be happy if someone could point me in the direction of more information.RegardsMarianne B. Wiese
/* GEUS 2010
* Author: Marianne B. Wiese
*
* This Module uses the methods from Richie Carmichael's wrapper
* http://mrrichie.spaces.live.com/blog/cns!DD16C3F34F4D913E!1807.entry
*
* */
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace GEUS
{
public class ProjectionEngineWrap : IDisposable
{
private bool m_disposed = false;
private IntPtr m_pe = IntPtr.Zero;
private GeodesicDistance m_gd = null;
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string dllname);
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
private delegate void GeodesicDistance(
[In] double semiMajorAxis,
[In] double eccentricity,
[In] double longitude1,
[In] double latitude1,
[In] double longitude2,
[In] double latitude2,
[Out] out double distance,
[Out] out double azimuthForward,
[Out] out double azimuthBack);
public ProjectionEngineWrap()
{
string dll = getDesktopDll();
// Load Projection Engine
this.m_pe = ProjectionEngineWrap.LoadLibrary(dll);
if (this.m_pe == IntPtr.Zero)
throw new Win32Exception(Marshal.GetLastWin32Error());
// Get pointer to function call
IntPtr gd = ProjectionEngineWrap.GetProcAddress(this.m_pe, "pe_geodesic_distance");
if (gd == IntPtr.Zero) {
int err = Marshal.GetLastWin32Error();
this.Dispose();
throw new Win32Exception(err);
}
// Create delegate
this.m_gd = (GeodesicDistance)Marshal.GetDelegateForFunctionPointer(gd, typeof(GeodesicDistance));
}
~ProjectionEngineWrap() { this.Dispose(); }
public void Dispose() {
if (this.m_disposed) { return; }
if (this.m_pe != IntPtr.Zero)
{
// Release Memory
ProjectionEngineWrap.FreeLibrary(this.m_pe);
}
// Update flag.
this.m_disposed = true;
// No need to finalize
GC.SuppressFinalize(this);
}
/// <summary>
/// Returns the geodestic azimuth and distance between two geographic locations.
/// http://edndoc.esri.com/arcsde/9.3/api/capi/geometry/coordsys/pegeodesicdistance.htm
/// </summary>
/// <param name="semiMajorAxis">Semi Major Axis</param>
/// <param name="eccentricity">Globe Eccentricity</param>
/// <param name="longitude1">From Longitude (radians)</param>
/// <param name="latitude1">From Latitude (radians)</param>
/// <param name="longitude2">To Longitude (radians)</param>
/// <param name="latitude2">To Latitude (radians)</param>
/// <param name="distance">Returned Geodetic Distance</param>
/// <param name="azimuthForward">Returned Forward Azimuth (radians)</param>
/// <param name="azimuthBack">Returned Reverse Azimuth (radians)</param>
public void GetGeodesicDistance(
double semiMajorAxis,
double eccentricity,
double longitude1,
double latitude1,
double longitude2,
double latitude2,
out double distance,
out double azimuthForward,
out double azimuthBack)
{
this.m_gd(
semiMajorAxis,
eccentricity,
longitude1,
latitude1,
longitude2,
latitude2,
out distance,
out azimuthForward,
out azimuthBack);
}
private string getDesktopDll()
{
RegistryKey coreRuntime = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\ESRI\CoreRuntime", false);
if (coreRuntime == null) { return null; }
object installDir = coreRuntime.GetValue("InstallDir", null);
coreRuntime.Close();
if (installDir == null) { return null; }
string folder = installDir.ToString();
string bin = Path.Combine(folder, "bin");
return Path.Combine(bin, "pe.dll");
}
}
}
private float getMeridianConvergence(IPoint p0)
{
// GRS_1980. From File: North American Datum 1983.prj
const double semiMajorAxis = 6378137;
// Eccentricity squared of the spheroid e^2 = 2f-f^2
// Calculated from flattening f = 1/298.257222101
// Inverse flattening from File: North American Datum 1983.prj
const double eccentricity = 0.00669438002298586;
if (peEngine == null)
peEngine = new ProjectionEngineWrap();
meridianConvergence = 0; // float
try
{
// p0's latlong koordinater
p0.Project(geographicSpatialRef);
p0.QueryCoords(out fromLong, out fromLat);
// Koordinater fra et punkt 100 m nord for p0 (kort nord)
p0.Project(map.SpatialReference);
p0.QueryCoords(out X, out Y);
p0.PutCoords(X, Y + 100);
p0.Project(geographicSpatialRef);
p0.QueryCoords(out toLong, out toLat);
// Sæt tilbage, så anchorpoint i onVertexAdded() ikke forskydes
p0.Project(map.SpatialReference);
p0.PutCoords(X, Y);
// Lokal meridiankonvergens fra ESRI's 'projektionsmaskine' bibliotek, pe.dll
peEngine.GetGeodesicDistance(semiMajorAxis,
eccentricity,
ToRadians(fromLong),
ToRadians(fromLat),
ToRadians(toLong),
ToRadians(toLat),
out distance,
out azimuthForward,
out azimuthBack);
meridianConvergence = 360 + (float)ToDegrees(azimuthForward);
if (meridianConvergence > 359)
meridianConvergence -= 360;
}
catch (Exception e)
{
MessageBox.Show("GEUS EditHelper getMeridianConvergence(): \n" + e.Message);
}
return meridianConvergence;
}
void EditHelper_OnStopEditing(bool save)
{
if (peEngine != null)
{
peEngine.Dispose();
peEngine = null;
}
}