Page 6 of 6
Now that we have mastered the manual marshaling of a simple pointer to a struct the next step is a pointer to a pointer to a struct. Surprisingly this requires nothing new because the struct-to-pointer function will actually convert any data type to an unmanaged pointer – including a pointer.
The function AVISaveOption is a suitable example as it needs two pointers to pointers as parameters:
extern static int AVISaveOptions(
In fact the ppavi parameter is a pointer to a handle (which is itself a pointer) and the ppOptions is a pointer to a pointer to a struct. To call this function we first need the struct:
AVICOMPRESSOPTIONS opts = new
You can look up the definition of the structure in the standard AVI documentation.
Next we need the marshaled pointer to the struct:
IntPtr lpstruct = MarshalToPointer(opts);
and then the pointer to the pointer:
IntPtr lppstruct = MarshalToPointer(
followed by the pointer to the handle:
IntPtr lphandle = MarshalToPointer(
The call to the API function is now simple:
result = AVISaveOptions(
where the other parameters and constants aren’t of any great interest to us and you can find more details in the API’s documentation.
When the function completes all that is left to do is transfer the data in the unmanaged buffer back into the managed struct:
opts = (AVICOMPRESSOPTIONS)
You have to be careful to use the pointer to the struct and not the pointer to the pointer!
Finally we can free all of the unmanaged memory we used:
This might all seem complicated. Using pointers-to-pointers is never an easy thing to do and it is one of the reasons that C# makes sure that when you do use pointers then you mark the code as unsafe. However you might like to contemplate just how safe this sort of juggling is and all without an unsafe block in sight.
On the other hand the general principles are very simple. When you pass anything by ref to an API it has to be copied to unmanaged memory and the address of this memory is passed to the function. Normally default marshaling takes care of this and you can ignore it - but it still happens. If you need to go beyond what is provided by the marshaling attributes then you have to perform this copying explicitly.