I have avoided such complexities till now, except for once, a rather simple variable array length.
Here are the results of the Antwerp jury:
 int eventSize = Marshal.SizeOf(ev) * events.Length;
 IntPtr eventPointer = Marshal.AllocHGlobal(eventSize);
 for (int i = 0; i < events.Length; i++)
 Marshal.StructureToPtr(events[i], (IntPtr)((int)eventPointer + (eventSize * i)), false);
There is something fishy about eventSize;
 is an attempt to compute the overall size; it may be correct, I am not sure, as Sizeof(ev) is the size of one struct and could be rounded up to a multiple of 16 or so, whereas an array would not contain padding bytes between elements.
And  treats eventSize as if it were the size of a single element, which it isn't. So that is probably the direct cause of your overflow.
Seems like you want to move the multiplication from  to .
FWIW: IntPtr will adapt to Win32/Win64 as you probably know; don't let it fool you.