winapi - Does a C# method need to be pinned when used as Win32 callback? -
i passing c# instance method win32 api call later used callback function windows application. when pass reference object, reference temporarily pinned until call returns (see this article jason clark).
if api call retain address later use after call returns, have pin object explicitly before call (i can allocate unmanaged memory via marshal.allochglobal, or can pin down managed object via gchandle.alloc).
but methods retained use callbacks win32 api? specifically, have code:
protected const int callback_function = 0x30000; private delegate void midiinproc( int handle, uint msg, int instance, int param1, int param2); [dllimport("winmm.dll")] private static extern int midiinopen( out int handle, int deviceid, midiinproc proc, int instance, int flags); private void midiinprocess( int hmidiin, uint umsg, int dwinstance, int dwparam1, int dwparam2) { } ... int hresult = midiinopen( out hhandle, deviceid, midiinprocess, // might move after call returns? 0, callback_function);
at archived tutorial, microsoft says, "...make sure lifetime of delegate instance covers lifetime of unmanaged code; otherwise, delegate not available after garbage-collected." makes perfect sense, class might unloaded if there no managed-code references it, resulting in method ("delegate") no longer being in memory.
but possibility of relocation of method, there of objects allocated on heap? might method's address change during lifetime?
in other words: provided class defining midiinprocess
remains loaded, can midiinprocess
method, above, not change address after midiinopen
returns, or must take step(s) pin it?
update
as per hans's first comment, delegate passed midiinopen
, above, ephemeral , not guaranteed available later when called (because there's no persistent reference on managed code side). believe retaining reference in private member of enclosing instance should enough keep alive, provided reference enclosing instance kept somewhere else in application long callback might needed. although incomplete, how might look:
private midiinproc midiinproc; ... midiinproc = midiinprocess; int hresult = midiinopen( out hhandle, deviceid, midiinproc, // pass reference retained. 0, callback_function);
from msdn article how to: marshal callbacks , delegates using c++ interop:
notice possible, not necessary, pin delegate using pin_ptr (c++/cli) prevent being re-located or disposed of garbage collector. protection premature garbage collection needed, pinning provides more protection necessary, prevents collection prevents relocation.
if delegate re-located garbage collection, not affect underlaying managed callback, alloc used add reference delegate, allowing relocation of delegate, preventing disposal. using gchandle instead of pin_ptr reduces fragmentation potential of managed heap.
emphasis mine.
sure, it's relevant using p/invoke , not using c++ ijw interop, hand said in comments , chris brumme said in blog post linked in comments, that's best documentation has, think.
you can file bug documentation if care enough. it's hosted on github it's easier in in old days.
Comments
Post a Comment