This post originated from an RSS feed registered with .NET Buzz
by Eric Gunnerson.
Original Post: What's wrong with this code? (Answer)
Feed Title: Eric Gunnerson's C# Compendium
Feed URL: /msdnerror.htm?aspxerrorpath=/ericgu/Rss.aspx
Feed Description: Eric comments on C#, programming and dotnet in general, and the aerodynamic characteristics of the red-nosed flying squirrel of the Lesser Antilles
The problem is that I've used the IntPtr that came back in pbFormat, but it's an internal pointer. In other words, the buffer that I pass looks like this:
_WMMediaType structure
WAVEFORMATEX structure
There's a small chance that a garbage collection will happen between the time I call GetMediaType and the time I get into the fixed block, and if that happens, buffer will be moved. That will leave pbFormat pointing at where the WAVEFORMATEX used to be, not where it is now.
The basic rule here is "be suspicious whenever you get a pointer back from interop". In this case, you can't use the pointer at all, and need to depend on the size of the structure. In this case, since we know the two structures are allocated contiguously, we can use:
int mediaTypeSize = Marshal.SizeOf(mediaType); waveFormatEx = *((DirectShow.WAVEFORMATEX*) (pBuffer + mediaTypeSize));
and things will be fine.
Interestingly, after I wrote the post, I came up with another method that also returns an array of the same structure, but instead of the "make the structures longer" approach, it uses two separate unmanaged allocations. That makes it safe to follow the pointer, but it also means that you need to call Marshal.FreeCoTaskMem() on the pointers to clean up after you're done with them.