tags:

views:

129

answers:

4

I use 3rd party COM to find faces in a picture. One of the methods has the following signature, from SDK:

long FindMultipleFaces(
  IUnknown* pIDibImage,
  VARIANTARG* FacePositionArray
);

Parameters: pIDibImage[in] - The image to search.

FacePositionArray[out]- The array of FacePosition2 objects into which face information is placed. This array is in a safe array (VARIANT) of type VT_UNKNOWN. The size of the array dictates the maximum number of faces for which to search.

which translates into the following C# method signature (from metadata):

int FindMultipleFaces(object pIDibImage, ref object pIFacePositions);

Being optimistic I call it the following way but get an exception that the memory is corrupt. The exception is thrown only when a face is present in the image.

FacePosition2[] facePositions = new FacePosition2[10];
object positions = facePositions;
int faceCount = FaceLocator.FindMultipleFaces(dibImage, ref positions);

What's the right way to pass SAFEARRAY to unmanaged code?

A: 

Take a look at this article by Rick Strahl: http://www.west-wind.com/Weblog/posts/464427.aspx

thomask
This article is about getting SafeArray from a COM call but I needed the opposite.
SlavaGu
A: 

It's something like you initialize an array using Marshal.AllocCoTaskMem and then use Marshal.Copy to copy it to unmanaged memory and the pass an IntPtr pointing to the array into the COM method.

In general, look at the Marshal class:
http://msdn.microsoft.com/en-gb/library/system.runtime.interopservices.marshal.aspx

ho1
Oops, it seems it only needed from me to initialize the array because FacePosition2 was not a struct but class and it was not initialized automatically as I though it would. FacePosition2[] facePositions = new FacePosition2[10]; for (var i = 0; i < facePositions.Length; i++) { facePositions[i] = new FacePosition2(); }
SlavaGu
A: 

Oops, it seems it only needed from me to initialize the array because FacePosition2 was not a struct but class and it was not initialized automatically as I though it would. This piece was missing:

for (var i = 0; i < facePositions.Length; i++)
{
  facePositions[i] = new FacePosition2();
}
SlavaGu
A: 

There are more sophisticated method, but opinion is more correct: change this signature Interop, so, he looks like taking an array.

Accessing a SafeArray Result from a COM Call in C#

Default Marshaling for Arrays

Correcting Common Interop Assembly Problems

Victor