Question

J'essaie d'appeler une dll héritée compilée à partir du code FORTRAN. Je suis un nouveau venu chez Interop, mais j’ai lu des articles à ce sujet et il semble que mon cas devrait être assez simple.

La méthode que je souhaite vraiment appeler a une signature de méthode complexe, mais je ne peux même pas appeler cette méthode GetVersion simple sans obtenir une violation de mémoire protégée.

Voici mon code DllImport:

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

Voici le code 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

Voici mon test unitaire qui échoue:

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

Voici le message d'erreur que je reçois:

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

Autres choses que j'ai essayées:

  • Utilisation du marshalling par défaut
  • Passage d'un caractère [] au lieu d'une chaîne (récupère les erreurs de signature de méthode)
Était-ce utile?

La solution 2

OK, je me suis fait au travail, le problème passait par réf. Je ne sais pas pourquoi, mais cela fonctionne:

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

Avec ce test:

[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);
    }

Autres conseils

... snip ... OK, je me suis fait au travail, le problème passait par réf. Je ne sais pas pourquoi, mais ça marche: ... snip ...

Vous devez passer par référence car c'est la sémantique utilisée par le code FORTRAN. Le code client passe dans une mémoire tampon dans laquelle le code FORTRAN va écrire au lieu d'utiliser une valeur de retour.

... snip ... ! MS $ ATTRIBUTES REFERENCE :: VRSION ... snip ...

Cet attribut dans votre code FORTRAN spécifie que ce paramètre est transmis par référence. Cela signifie que le code FORTRAN va écrire à cette adresse. Si DllImport ne le déclare pas également comme valeur de référence, vous obtiendrez une violation d'accès.

Avez-vous essayé d'utiliser un constructeur de chaînes?

Créez votre chaîne en tant que constructeur de chaînes et transmettez-la à la fonction dll.

Je ne suis pas sûr de savoir quelle instruction Marashlling utiliser, la valeur par défaut pourrait fonctionner.

Jetez un coup d'œil à: classe «chaîne» Marshal C ++ en C # P / Invoquer

Voici un bon article qui pourrait également vous aider: Interopérabilité Interop

Je ne peux pas essayer cette solution car je n'ai pas de compilateur Fortran, mais je pense que cela fonctionnerait pour vous:

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

Merci à tous les gars, j'ai essayé de passer une chaîne de c # à un sous-programme de fortran dll et cette méthode était la seule qui fonctionnait parmi beaucoup d'autres

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top