2009-05-05 2 views
0

** 주요 업데이트 ** 나는 약간의 실수를했지만, 나는 아직도 정확히 무슨 일이 일어나고 있는지 궁금해.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를 (사용) 및 그 포인터를 전달합니다. 이것은 영어와 일본어로 작동합니다. 나는 이것이 왜 해결책인지 이해하지 못하고 편안하지 않지만 작동한다.

답변

2

varargs 함수가 _cdecl 호출 규칙을 사용하므로 CallingConvention=CallingConvention.Cdecl을 지정해야 할 수도 있습니다. 기본값은 Winapi이며 기본값은 StdCall입니다.

다른 것이 필요할 수도 있지만, 적어도 그렇게 할 필요가있을 것이라고 확신합니다.

+0

나는 이것을 시도했는데, 어떤 이유로 그럴 때 그 기능이 아무런 효과가 없다. (이 경우 Get/Set 쌍의 "Set"이며 Set을 호출 할 때 Get은 아무 것도 반환하지 않습니다.) 저는 이것이 올바른 트랙이라는 것을 확신합니다. – OwenP

+0

실제로 일본어 머신에서 Cdecl을 사용할 때 AccessViolationException이 발생합니다. 이상한. – OwenP

관련 문제