2012-08-23 3 views
4

에서 반환하기 ++ COM 헤더와 IDL 파일 :클라이언트는 바이트 배열 내가 C에서이 선언을 C++ COM DLL을

//After C# interop compilation, the method's signature in C# becomes: 
Save(uint dwCommand, float[] fdata, out byte[] phKey); 

//The code to call the C++ COM server:  
uint dwCommand = 2; 
float[] fdata = new float[dwCommand]; 

fdata[0] = 1; 
fdata[1] = 2; 

byte[] phKey = new byte[320]; 

save(dwCommand, fdata, out phKey); 

하는 코드가 충돌합니다 :

//Header file: 
#define MAX_LENGTH  320 
typedef BYTE   PRE_KEY [MAX_LENGTH]; 

//IDL file: 
#define MAX_COUNT  10 
HRESULT Save([in] DWORD dwCommand, [in]float fdata[MAX_COUNT], [out] PRE_KEY* phKey); 

이는 C# 클라이언트 코드 ntdll.dll에서 호출이 C#으로 반환되기 전에 C++ 서버가 이미 처리를 마쳤으므로 더 이상 스택에 없습니다.

누구든지이 문제를 해결하는 방법을 알 수 있습니까? 그리고 interop 컴파일을 사용하여 idl 파일을 컴파일하여 C# signaure를 생성하므로 C++ IDL 파일에서 무언가를 수행하고 C# 시그너처를 수동으로 변경할 수 없습니다.

그리고 이것에 대해 재밌는 점은 C++에서 C#으로 정확히 동일한 phKey를 반환하는 유사한 호출이 있고 완벽하게 작동한다는 것입니다. 유일한 차이점은 phKey가 구조체에 있고 전체 구조체가 '[out]'매개 변수라는 것입니다. 구조체 내에서 이것이 왜 반환 될 수 있는지 직접 볼 수는 없지만 직접 매개 변수로 반환 할 수는 없습니다.

답변

1

IDL 선언의 [out] 특성은 심각한 interop 문제입니다. 즉, COM 서버가 배열을 할당하고 호출자가 배열을 릴리스해야합니다. 매우 드물게 좋은 결과가 나오기는하지만 서버와 클라이언트가 동일한 힙을 사용한다는 보장은 없습니다. 그리고 C 런타임 할당자를 malloc() 함수 또는 new [] 연산자와 함께 사용하면 CRT는 CRT와 완전히 동일한 버전을 공유하지 않는 한 호출자가 얻을 수없는 자체 비공개 힙을 사용합니다. 확률은 매우 낮아 일반적으로 CLR을 통해 상호 작용할 때 제로입니다.

폭탄 때문에 CLR은 배열을 관리되는 배열에 복사 한 후 배열을 릴리스해야한다는 것을 알고 있습니다. COM interop 할당을 위해 예약 된 힙을 사용하여 CoTaskMemFree()를 사용합니다. 확실히 배열을 할당하기 위해 CoTaskMemAlloc()을 사용하지 않았습니다.

이 문제에 대한 일반적인 해결책은 호출자가 배열을 제공하고 호출 수신자가 매개 변수에 [in, out]을 필요로하는 것입니다. 그리고 전달 된 배열의 크기를 나타내는 추가 매개 변수 인 [sizeis]는 마샬 러에게 알려줍니다. 매우 효율적이며 할당 할 필요가 없습니다. 자동화 SAFEARRAY 유형을 사용하면 추가 인수를 지정하지 않아도되므로 CLR은 해당 유형을 알고 있습니다.