** 주요 업데이트 ** 나는 약간의 실수를했지만, 나는 아직도 정확히 무슨 일이 일어나고 있는지 궁금해.multibyte ANSI를 varargs에 PInvoke 할 수 있습니까? 내가 도대체 뭘 잘못하고있는 겁니까?
내가 부르고 기능은 실제로 "fooV"이 서명하는 기능입니다 :
foo(const char *, const char *, EnumType, va_list)
이 내가지고 있던 AccessViolationExceptions을 지 웁니다하지만 PARAMS 매개 변수는 다른 모든 작동 이유를 설명하지 않습니다. 멀티 바이트 ANSI 문자로 변환해야하는 문자열을 제외하고는 NET 형식입니다. 나는 DLL의 개발자에게 실제로 사용하는 버전을 공개 할 것입니다 ... 매개 변수 목록에 va_list가 매개 변수 인 경우 PInvoking에 대한 힌트가 있습니까?
** 이전 게시물 **
이는 관련이 있지만, recent question I asked 다릅니다.
는 I는 다음의 특성이있는 C 라이브러리 함수를 호출하는 PInvoke를 사용해야 : 함수가 StructType으로 변화하는 방식으로 자원을 구성
foo(const char *, const char *, EnumType, ...)
단계; 내가 관심이있는 경우 varargs가 단일 ANSI 멀티 바이트 문자열이 될 것으로 예상하는 구성을합니다. 나는 함수를 호출이의 PInvoke 서명을 사용 :
[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo")]
public static extern int Foo(string s1, string s2, EnumType st1, params string[] s3);
params string[]
나에게 이상한 듯하지만,이 함수를 호출 이전 서명 bool
그래서 난 패턴을 다음과 같은 다른 유형의 그것을 사용했다.
나는 친숙한 .NET 방법으로이 포장 :
public void Foo(string s1, string s2, string s3)
{
int error = Dll.Foo(s1, s2, EnumType.Foo, s3);
// handle errors
}
는 최근에 나는의 FxCop의 제안을 준수하는 속성 같이 DllImport에서 "거짓 BestFitMapping = ThrowOnUnmappableChar = true"로 포함하는 서명을 변경했습니다. 나중에 설명 하겠지만 이것은 빨간색 청어입니다.
이 변경 작업에서 기대하는 것은 유니 코드에 대한 제한된 지원입니다. 예를 들어, 영어 코드 페이지가있는 시스템에서 일본어 문자가 포함 된 문자열을 전달하면 예외가 발생합니다. 일본어 컴퓨터에서는 일본어 문자열을 함수에 전달할 수 있어야합니다. 영어 테스트는 예상대로 작동하지만 일본어 테스트에서는 HRESULT 0x8007007A가있는 System.Runtime.InteropServices.COMException을 throw합니다. 이것은 BestFitMapping 및 ThrowOnUnmappableChar 설정 없이도 발생합니다.
나는 주위를 찾고 작은 일을 당신이 할 수 PInvoke를 그냥 보통의 인수를 지정하여 변수 인수 제안 일부 사이트를보고, 그래서 나는이 서명 시도했다 : 나는 그것을 사용하는 경우
[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo")]
public static extern int Foo(string s1, string s2, EnumType st1, string s3);
이는 AccessViolationException를 throw를 영어 또는 일본어 기계.
이 C 라이브러리는 멀티 바이트 ANSI 만 사용하고 처리하기 때문에 UTF-8 또는 다른 유니 코드 인코딩을 사용할 수 없습니다. 나는이 함수에 CharSet.Unicode를 지정하는 것이 효과가 있다는 것을 알았지 만, 우연히 만났을 때가 아니라 우연히 의지해야만하는 것이 아닌가 걱정된다. 나는 시스템 코드 페이지를 사용하여 문자열을 byte []로 변환하려고 생각했지만 varargs 매개 변수에 바이트 배열을 전달하고 싶습니다.
무슨 일 이니?영어 시스템에서는 영어 문자가 제대로 작동하고 일본어 문자가 예상대로 ArgumentException을 발생시킵니다. 일본어 시스템에서는 영어 문자가 제대로 작동하고 일본어 문자가 COMException을 던집니다. 내 PInvoke 서명에 문제가 있습니까? 나는 MarshalAs
속성을 사용하여 LPArray의 유형과 LPStr의 유형을 지정하려고했지만 동일한 방식으로 실패합니다. UnmanagedType.LPStr은 단일 바이트 ANSI 문자열임을 나타냅니다. multibyte ANSI 문자열을 지정하는 방법이 있습니까?
** 업데이트 ** 다음은 현재 댓글을 고려한 내용입니다.
내가 CDECL의 호출 규칙을 지정하고 다음과 같이 일반 매개 변수를 사용하는 경우 :이 규격을 사용하는 경우
[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo", CallingConvention = CallingConvention.Cdecl)]
public static extern int Foo(string s1, string s2, EnumType e1, string s3)
, 내가 AccessViolationException를 얻을. 그래서 이것을 시도 :
[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo", CallingConvention = CallingConvention.CDecl)]
public static extern int Foo(string s1, string s2, EnumType e1, string s3)
이 작동합니다 및 일본어 문자를 사용할 때 COMException throw합니다
지속적으로 작동 내가 찾은 유일한 것은
은 이것이다 :[DllImport(DllName, CharSet = CharSet.Ansi, EntryPoint = "foo", BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int Foo(string s1, string s2, EnumType e1, params IntPtr[] s3)
이 일을하려면, 나는 Marshal.StringToHGlobalAnsi를 (사용) 및 그 포인터를 전달합니다. 이것은 영어와 일본어로 작동합니다. 나는 이것이 왜 해결책인지 이해하지 못하고 편안하지 않지만 작동한다.
나는 이것을 시도했는데, 어떤 이유로 그럴 때 그 기능이 아무런 효과가 없다. (이 경우 Get/Set 쌍의 "Set"이며 Set을 호출 할 때 Get은 아무 것도 반환하지 않습니다.) 저는 이것이 올바른 트랙이라는 것을 확신합니다. – OwenP
실제로 일본어 머신에서 Cdecl을 사용할 때 AccessViolationException이 발생합니다. 이상한. – OwenP