The client receives an array of bytes returned from C ++ COM dll

I have this declaration in the C ++ COM header and IDL files:

//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); 

This is the C # client code:

 //After C# interop compilation, the method 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); 

The code will crash in the ntdll.dll file before the call returns to C #, but the C ++ server has already completed processing and is no longer on the stack.

Can anyone figure out how to solve this? And since I use interop compilation to compile the idl file to create C # signaure, so I cannot do something in the C ++ IDL file and manually change the C # signature.

And what's funny about this is that I have another similar call that returns the same phKey from C ++ to C # and it works fine. The only difference is that the phKey call is in the structure, and the whole structure is the "[out]" parameter. I don’t really see why this can be returned inside the structure, but not directly as a parameter.

+4
source share
1 answer

The [out] attribute in an IDL declaration is a serious interaction issue. This means that your COM server will allocate an array and the caller needs to free it. This is very rarely suitable for a good result, there is no guarantee that your server and your client will use the same heap. And it will always fail if you use the C runtime allocator using the malloc () or new [] function, CRT uses its own heap, which the caller can never get if they do not share the same version of CRT. The odds are very small, which is generally zero when you go through the CLR.

That's why it is bombing, the CLR knows that it needs to free the array after copying it to a managed array. It will use CoTaskMemFree (), using the heap reserved for communication distributions between COM. Of course, you did not use CoTaskMemAlloc () to allocate the array.

A common solution to this problem is to provide the caller with an array that the caller fills it with. This requires [in, out] for the parameter. And an additional parameter indicating the size of this passed array is [sizeis] to tell the marshaller about it. Very effective, no distribution required. Using the automation type SAFEARRAY allows you to not specify an additional argument, the CLR knows about this type.

+1
source

All Articles