It appears that the caller is responsible for passing an array of IUnknown pointers and the number of elements in the array and the MyCPlusPlus function will fill the array and indicate the number of IUnknown pointers that were stored in the array.
Give this a try to let the .Net handle the marshaling for you -
[DllImport("ArrayMarshal.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
static extern uint MyCPlusPlusFunction([MarshalAs(UnmanagedType.IUnknown)] object document, uint id, string name,
[In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown)] object[] ids,
ref uint flags, ref uint size);
And the call the function like this with respect to the IUnknown pointer array -
uint id = 5;
uint aSize = 16;
uint flags = 42;
object[] aObjects = new object[aSize];
uint ret = MyCPlusPlusFunction(null, id, "test", aObjects, ref flags, ref aSize);