|
I'm using a couple of API calls that require function pointers for callbacks.
So far I've been passing in a delegate instance and it's worked fine. I'm concerned that the delegate reference however may be changed in managed memory. On researching this I came accross the Marshal.GetFunctionPointerForDelegate method.
Some people say this is not needed as passing the delegate directly invokes the internal version of this anyway. Other's suggest that pinning the delegate or the class instance that contains it is necessary.
All MSDN has to offer is "You must manually keep the delegate from being collected by the garbage collector from managed code."
Has anyone had total success (or occaisional failures) just passing the delegate instance directly, or recommend a robust approach?
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Hi Dave,
I strongly suspect .NET pins function parameters for you when there is a need to do so, of course only for as long as the native function is being called. This applies to:
- strings you pass to a const char*
- StringBuilders you pass to a char*
- delegates you pass to a function pointer
- etc.etc.
I have been doing this all along. I only use GCHandle to explicitly pin down things that need to remain natively in use after the native function returns, such as buffers that will be used asynchronously.
I've never used Marshal.GetFunctionPointerForDelegate(); I suspect the only real use for it is when a delegate is buried inside a larger structure. Same seems to apply for a lot of stuff in the Marshal class.
Luc Pattyn [Forum Guidelines] [My Articles]
DISCLAIMER: this message may have been modified by others; it may no longer reflect what I intended, and may contain bad advice; use at your own risk and with extreme care.
|
|
|
|
|
Hi Luc,
Thanks, pretty much confirms what I thought. I've found a little more MSDN documentation to support this too so I can rest more easily
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Just a quick follow up Luc...
The delegate is a parameter in an Open function. To keep the instance alive, I have a private static list of open devices and the instance is added to that.
The callbacks can keep coming until the Close function is called. When closing, I'm removing the instance from the static list. I've also implemented the Dispose pattern on the device instances and if any are open when Dispose is called, the Close function is called. Doing it this way seems to remove the need for any pinning etc.
Is that sufficient in your opinion?
(I haven't managed to call the Close without runtime errors from a finalizer BTW, so if you know a solution to that I'd be glad to hear it! I can post code if you wish).
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
Hi Dave,
DaveyM69 wrote: To keep the instance alive, I have a private static list of open devices and ...
That should be fine, although I would probably prefer to have the delegate as an instance member of your device object, rather than in a static list. I probably would also have a static list of devices, either just for debugging or to make sure they remain alive if that's useful. Or I would try and create such device objects with a using construct provided that fits the overall software architecture.
DaveyM69 wrote: I haven't managed to call the Close without runtime errors from a finalizer
That doesn't ring any bells (maybe the symptoms are too vague to ring anything). I trust you are aware all finalizers are ran from a single low-priority thread in the GC (not necessarily soon), and having a finalizer throwing uncatched exceptions is (or at least has been) a bad idea. That reminds me it has been a long time I researched finalizers...
Luc Pattyn [Forum Guidelines] [My Articles]
DISCLAIMER: this message may have been modified by others; it may no longer reflect what I intended, and may contain bad advice; use at your own risk and with extreme care.
|
|
|
|
|
Luc Pattyn wrote: prefer to have the delegate as an instance member... have a static list of devices
That's what I meant, I just didn't describe it that well! This code is to be consumed elsewhere so the using would be tricky to implement here - but easy for the consumer.
The Close from the finalizer is a strange issue. It works fine (I think) if the finalizer is called during normal execution, but if called when a consuming application closes (and so releases all references) it causes the problems. I don't have the code with me right now but will post a snippet later when I get home (this is a hobby not work project - the best kind ).
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
I just made a complete sample ready to post here, and calling Close in the finalizer is working without error!
Must have something else causing the problem in the original code - thanks for your time anyway!
DaveBTW, in software, hope and pray is not a viable strategy. (Luc Pattyn) Visual Basic is not used by normal people so we're not covering it here. (Uncyclopedia) Why are you using VB6? Do you hate yourself? (Christian Graus)
|
|
|
|
|
perseverance is king!
Luc Pattyn [Forum Guidelines] [My Articles]
DISCLAIMER: this message may have been modified by others; it may no longer reflect what I intended, and may contain bad advice; use at your own risk and with extreme care.
|
|
|
|