C#에서 C 스타일 배열을 가져 오는 함수의 IDL 선언 (C ++)
문제
C# 프론트 엔드와 함께 C ++로 작성된 일부 COM 인터페이스로 구성된 기존 코드베이스로 작업 중입니다. 추가해야 할 새로운 기능이 있으므로 COM 부분을 수정해야합니다. 한 가지 경우에, 나는 배열 (c#에서 할당 된)을 채우기 위해 구성 요소로 전달해야한다.
내가하고 싶은 것은 int 배열을 c#의 메소드에 다음과 같은 것들에 전달할 수 있다는 것입니다.
// desired C# signature
void GetFoo(int bufferSize, int[] buffer);
// desired usage
int[] blah = ...;
GetFoo(blah.Length, blah);
작품의 몇 렌치 :
- C ++/CLI 또는 관리 된 C ++를 사용할 수 없습니다 (이 경우 COM을 수행 할 수 있음).
- C# 측면은 /안전하지 않은 상태로 컴파일 할 수 없습니다 (원수 사용은 허용됩니다).
COM 인터페이스는 C# 부품 만으로만 사용되므로 다른 COM 소비자와의 상호 운용성에 덜 관심이 없습니다. 32와 64 비트 사이의 이식성도 걱정하지 않습니다 (모든 것이 32 비트 기계에서 컴파일되고 실행되므로 코드 생성기는 포인터를 정수로 변환합니다). 결국, 그것은 C ++/CLI로만 대체 될 것이지만 이는 방법입니다.
나의 초기 시도
다음과 유사한 것입니다.
HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);
출력 TLB 정의는 다음과 같습니다.
HRESULT _stdcall GetFoo([in] int bufferSize, [in] int* buffer);
C#로 가져온 (그렇게 합리적이지 않음) :
void GetFoo(int bufferSize, ref int buffer);
내가 ~할 수 있었다 함께 사용하십시오
int[] b = ...;
fixed(int *bp = &b[0])
{
GetFoo(b.Length, ref *bp);
}
... /안전하지 않은 /안전하지 않다는 점을 제외하고.
현재
나는 사용 중입니다 :
HRESULT GetFoo([in] int bufferSize, [in] INT_PTR buffer);
다음과 같이 가져옵니다.
void GetFoo(int bufferSize, int buffer);
그리고 사용해야합니다.
int[] b = ...;
GCHandle bPin = GCHandle.Alloc(b, GCHandleType.Pinned);
try
{
GetFoo(b.Length, (int)Marshal.UnsafeAddrOfPinnedArrayElement(b, 0));
}
finally
{
bPin.Free();
}
그것이 작동하지만 ...하지만 더 깨끗한 방법을 찾고 싶습니다.
따라서 질문은입니다
이 경우 TLB 생성기에서 C# 가져 오기에 친숙한 IDL 정의가 있습니까? 그렇지 않다면 C# 측에서 무엇을 할 수 있도록 조금 더 안전하게 만들 수 있습니까?
해결책 3
흠 ... 나는 나를 더 가까이 데려다 줄 정보를 찾았다 ...
이 IDL 선언 (C ++)
HRESULT GetFoo([in] int bufferSize, [in, size_is(bufferSize)] int buffer[]);
(MSIL)로 가져옵니다.
method public hidebysig newslot virtual instance void GetFoo([in] int32 bufferSize, [in] int32& buffer) runtime managed internalcall
그리고 (msil)으로 변경 된 경우
method public hidebysig newslot virtual instance void GetFoo([in] int32 bufferSize, [in] int32[] marshal([]) buffer) runtime managed internalcall
(C#)처럼 사용할 수 있습니다.
int[] b = ...;
GetFoo(b.Length, b);
정확히 내가 garning했던 것!
그러나 TLBimport에서 생성 한 런타임 호출 가능한 래퍼의 MSIL을 고정 할 필요가없는 다른 솔루션이 있습니까?
다른 팁
따라서 32 비트 머신에서 32 비트, 64 비트 기계에서 64 비트 인 IDL 데이터 유형을 요구합니다. 그러나 당신은 마샬링 코드가 그것을 int처럼 포인터처럼 취급하는 것을 원하지 않습니다. 그렇다면 64 비트 프로세스에서 32 비트 프로세스로 전화 할 때 추가 32 비트에 어떤 일이 발생합니까?
나에게 물리학 위반처럼 들립니다.
인프로 전용이라면이 토론의 맨 아래를 참조하십시오. http://www.techtalkz.com/vc-net/125190-how interop-net-client-com-dll.html.
권장 사항은 intptr 대신 void *를 사용하고 [로컬]과 플래그를 사용하여 마샬러가 관여하지 않습니다.
C# com 작동성에 대해 많이 모르지만 SafeArray (int_ptr) 또는 이와 유사한 것을 사용해 보셨습니까?