It's much simpler than you think.
[DLLImport("some.dll")]
public static extern int foo(somestruct[] vector, int size);
The one thing to consider is marshaling direction. The runtime makes some decisions on whether to marshal the array before the call, after the call, or both. To make sure it makes the right decision, you may want to use In and/or Out attributes.
[DLLImport("some.dll")]
public static extern int foo([In] somestruct[] vector, int size);
// will only marshal the array to native memory before the call
[DLLImport("some.dll")]
public static extern int foo([Out] somestruct[] vector, int size);
// will only marshal the array to managed memory after the call
[DLLImport("some.dll")]
public static extern int foo([In, Out] somestruct[] vector, int size);
// will marshal the array both ways
On the other hand, if somestruct is blittable, then no marshaling is necessary, as the runtime can just pin the array and pass a pointer to the managed copy.