salto linea common comandos comando ciclo arreglos c# .net interop fortran dllimport

c# - linea - fortran pdf



ViolaciĆ³n de memoria protegida llamando a la DLL de FORTRAN desde C# (5)

Estoy tratando de llamar a un dll heredado compilado del código FORTRAN. Soy nuevo en Interop, pero he leído algunos artículos y parece que mi caso debería ser bastante sencillo.

El método que realmente quiero llamar tiene una firma de método compleja, pero ni siquiera puedo llamar a este simple método GetVersion sin obtener una violación de memoria protegida.

Aquí está mi código de DllImport:

[DllImport("GeoConvert.dll", EntryPoint="_get_version@4", CallingConvention=CallingConvention.StdCall)] public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPStr, SizeConst=8)] ref string version);

Aquí está el código FORTRAN:

SUBROUTINE GetVer( VRSION ) C !MS$DEFINE MSDLL !MS$IF DEFINED (MSDLL) ENTRY Get_Version (VRSION) !MS$ATTRIBUTES DLLEXPORT,STDCALL :: Get_Version !MS$ATTRIBUTES REFERENCE :: VRSION !MS$ENDIF !MS$UNDEFINE MSDLL C CHARACTER*8 VRSION C VRSION = ''1.0a_FhC'' C RETURN END

Aquí está la prueba de mi unidad que falla:

[Test] public void TestGetVersion() { string version = ""; LatLonUtils.GetGeoConvertVersion(ref version); StringAssert.IsNonEmpty(version); }

Aquí está el mensaje de error que recibo:

System.AccessViolationException Message: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

Otras cosas que he intentado:

  • Usar la clasificación predeterminada
  • Pasar un char [] en lugar de una cadena (obtener errores de firma de método en su lugar)

... snip ... OK, lo hice funcionar, el problema estaba pasando por ref. No estoy seguro por qué, pero esto funciona: ... snip ...

Debe pasar por referencia porque esa es la semántica utilizada por el código FORTRAN. El código de cliente pasa en un búfer al que el código FORTRAN va a escribir en lugar de usar un valor de retorno.

... snip ...! MS $ ATRIBUTOS REFERENCIA :: VRSION ... snip ...

Este atributo en su código FORTRAN especifica que este parámetro se pasa por referencia. Eso significa que el código FORTRAN va a escribir en esta dirección. Si el DllImport no lo declara como un valor de referencia también, obtendrá una infracción de acceso.


No puedo probar esta solución ya que no tengo un compilador FORTRAN, pero creo que esto funcionaría para usted:

[DllImport("GeoConvert.dll", EntryPoint="_get_version@4", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)] public static extern void GetGeoConvertVersion(StringBuilder version);


OK, lo hice funcionar, el problema estaba pasando por ref. No estoy seguro por qué, pero esto funciona:

[DllImport("GeoConvert.dll", EntryPoint="_get_version@4", CallingConvention=CallingConvention.StdCall)] public static extern void GetGeoConvertVersion([MarshalAs(UnmanagedType.LPArray)] byte[] version);

Con esta prueba:

[Test] public void TestGetVersion() { //string version = ""; byte[] version = new byte[8]; LatLonUtils.GetGeoConvertVersion(version); char[] versionChars = System.Text.Encoding.ASCII.GetChars(version); string versionString = new string(versionChars); }


Gracias a todos, he estado tratando de pasar una cadena de c # a una subrutina de Fortran DL y este método fue el único que funciona entre muchos otros


¿Has intentado usar un StringBuilder?

Crea tu String como un StringBuilder y pasa eso a la función dll.

No estoy seguro de qué declaración de Marashlling usar, por ejemplo, el predeterminado podría funcionar.

Eche un vistazo a: Clase de "cuerda" Marshal C ++ en C # P / Invoke

Aquí hay un buen artículo que podría ayudar también: Interop Marshalling