문제

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

흠 ... 나는 나를 더 가까이 데려다 줄 정보를 찾았다 ...

마샬링 변경 - 적합한 C 스타일 어레이

이 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) 또는 이와 유사한 것을 사용해 보셨습니까?

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