One of the big changes in P/Invoke in .NET Framework 2.0 vs. .NET Framework 1.0/1.1 is that you can now pass function pointers from a C API back to .NET.
In previous versions (1.0/1.1) you could pass a delegate as a function pointer to a C API, but could not receive a function pointer from the C API back to .NET.
This technique of passing a pointer from within the API is relatively common in more than a few APIs in Windows, where you have one function that initializes a special struct that simply contains pointers to various functions. This is like an interface for an unobject oriented language like C. It gives the designers of the API the ability to plugin and replace an implementation of a certain function dynamically depending on either the environment or parameters passed to the function that initializes the struct.
This also means that various other Windows APIs (SSPI, for example) can now be called directly from C# and does not require a bridging C dll or writing a mixed (managed and unmanaged) code in C++ to glue things together.
I’ve previously covered a few of the common problems in P/Invoke code, so be sure to read that if you are facing problems when P/Invoking code!