Marshal.Copy() isn't the right method in this case, it forces you to cough up the byte[] and that hurts in more than one way. What you really need is a method that copies from an IntPtr to an IntPtr so that simply pinning the array gets the job done, avoiding the copy and the structure layout hassle. The .NET framework doesn't have one.
But Windows does, you can pinvoke the memcpy()
function. You can tinker the declaration to make it accept your RGBColor[] array. Like this:
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int memcpy(IntPtr dest, RGBColor[] srce, int bytes);
The first argument is slightly tricky. You'll need:
BitmapData bd = ...
IntPtr dest = new IntPtr((long)bd.Scan0 + scanline * bd.Stride);