문제

Fortran 코드에서 컴파일 된 레거시 DLL을 호출하려고합니다. 나는 Interop을 처음 접했지만 그것에 대한 몇 가지 기사를 읽었으며 내 사건이 매우 간단 해야하는 것 같습니다.

실제로 호출하려는 방법에는 복잡한 방법 서명이 있지만 보호 된 메모리 위반을받지 않고도이 간단한 getversion 메소드를 호출 할 수 없습니다.

내 dllimport 코드는 다음과 같습니다.

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

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

실패한 내 단위 테스트는 다음과 같습니다.

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

내가받는 오류 메시지는 다음과 같습니다.

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

내가 시도한 다른 것들 :

  • 기본 마샬링 사용
  • 문자열 대신 char [] 전달 (대신 메소드 서명 오류를 얻음)
도움이 되었습니까?

해결책 2

좋아, 나는 그것을 일하게했다. 문제는 심판을 지나가는 것이었다. 왜 그런지 잘 모르겠지만 이것은 작동합니다.

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

이 테스트로 :

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

다른 팁

... Snip ... 좋아, 나는 그것을 일하게했다. 문제는 심판을 지나가는 것이었다. 왜 그런지 잘 모르겠지만 이것이 효과가 있습니다 : ... Snip ...

Fortran 코드에서 사용하는 의미 론적이기 때문에 참조별로 통과해야합니다. 클라이언트 코드는 리턴 값을 사용하는 대신 Fortran 코드가 쓸 것이라는 버퍼를 전달합니다.

... Snip ...! MS $ 속성 참조 :: vrsion ... Snip ...

Fortran 코드 의이 속성은이 매개 변수가 참조로 전달되어 있음을 지정합니다. 즉, Fortran 코드 가이 주소에 쓸 수 있습니다. DLLIMPORT가 참고 값으로 선언하지 않으면 액세스 위반을 받게됩니다.

StringBuilder를 사용해 보셨습니까?

문자열을 StringBuilder로 만들고 그것을 dll 함수로 전달하십시오.

나는 Marashlling의 진술이 무엇을 사용할지 확신하지 못하고 기본값이 작동 할 수 있습니다.

다음을 살펴보십시오. C# P/Invoke의 Marshal C ++ "String"클래스

여기에 좋은 기사가 도움이 될 수 있습니다. 인터 로프 마샬링

Fortran 컴파일러가 없기 때문에이 솔루션을 시도 할 수는 없지만 이것이 효과가 있다고 생각합니다.

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

모든 사람들에게 감사합니다. C#에서 Fortran DLL의 서브 루틴으로 문자열을 전달하려고 했는데이 방법은 다른 많은 사람들 중에서 유일하게 작동했습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top