The callback passed to CreateTimerQueueTimer is expected to be the unmanaged function that will exist for the callback lifetime. A managed delegate can move around in memory, but the basic stub created by marshalling will not do this, so there is no need to bind a delegate . However, there is a need to keep the delegate from garbage collection, because a pointer from unmanaged code is not enough to save it. Thus, you must ensure that either the delegate is supported by a supported managed link (possibly using GCHandle
The PVOID parameter that is passed to the callback function must be fixed in memory, since again the unmanaged function expects it to not move after the function returns. In .Net, this pinning occurs (efficiently) automatically, but only for the life of the called function. Thus, if you use a link to some managed object (say, by getting IntPtr to it), the base object must be docked (again, GCHandle can be used for this in different ways). To make sure this is a problem, try using IntPtr.Zero as a parameter to check if it works.
If this solves the problem, you need to either assign your parameter as raw bytes in the unmanaged heap (and accordingly the marshal), use some type of blittable, which can be safely inserted into some PVOID size (for example, Int32) or use the GCHandle above to support a stable pointer to a managed instance, this will have significant performance implications if done incorrectly.
ShuggyCoUk
source share