C#에서 Fortran DLL을 호출하는 보호 메모리 위반
문제
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의 서브 루틴으로 문자열을 전달하려고 했는데이 방법은 다른 많은 사람들 중에서 유일하게 작동했습니다.