2

I've written C# code that passes a delegate to be called by C++ as a function pointer. When the C++ code calls the function pointed to, I get the error:

A first chance exception of type 'System.NullReferenceException' occurred
in PInvokeTest.exe Additional information: Object reference not set to an 
instance of an object.

What could be causing this? In this tutorial on Pinvoke, the author quotes an MSDN article that says:

...the application is responsible for somehow extending the lifetime of 
the delegate until no more calls will occur from unmanaged code...

Could this be the problem? If it is, I'm not sure how to make sure the lifetime of the delegate is long enough.

Currently, I define the following in a class (the delegate is named myCalllback)

private static MyCallback _callbackInstance;

and pass it to C++ in a class method with the following:

_callbackInstance = new MyCallback(CallbackFunction);
setCallback(_callbackInstance);

where CallbackFunction is a static function, and setCallback is a static extern function.

user327301
  • 2,641
  • 2
  • 26
  • 33
  • Did you pin your delegate before passing to the c++ method? – Sriram Sakthivel Dec 25 '14 at 06:04
  • I didn't pin the delegate. Right before the line I quoted in the tutorial, it says " This leads many applications to create a pinning handle for the delegate. This is completely unnecessary..." (the whole quote doesn't fit in this comment). – user327301 Dec 25 '14 at 06:24
  • 1
    If the method call is synchronous, you don't need to pin the delegate. If the unmanaged method stores the function pointer for calling the function later at some point, you **must** pin the delegate(at least keep it alive as the author says). That's what author says here *the application is responsible for somehow extending the lifetime of the delegate until no more calls will occur from unmanaged code* – Sriram Sakthivel Dec 25 '14 at 06:32
  • Almost all cases of `NullReferenceException` are the same. Please see "[What is a NullReferenceException in .NET?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-in-net)" for some hints. – John Saunders Dec 25 '14 at 07:09
  • Assigning a field in a managed type isn't in any way the same as passing it to C++ code. If you want specific help with your question, you need to provide a good, specific code example. See https://stackoverflow.com/help/mcve – Peter Duniho Dec 25 '14 at 07:57
  • @SriramSakthivel That's not what pinning means. Pinning means that the managed object must not be moved around in memory. Keeping it alive merely means that the managed object must not be destroyed. Pinning is unnecessary according to that tutorial (which is quoting [this blog post](http://blogs.msdn.com/b/cbrumme/archive/2003/05/06/51385.aspx) from a CLR developer), keeping it alive is necessary. –  Dec 25 '14 at 09:06
  • @hvd You're correct and I'm having the correct understanding of pinning as well. AFAIK for synchronous methods, P/invoke marshaller will pin the delegate till the function returns from unmanaged code. For asynchronous calls like passing the pointer to unmanaged code and it invokes the function later, you need to pin it. PS: I've not read that article fully, I'll read it later. – Sriram Sakthivel Dec 25 '14 at 09:13
  • Could it simply be a NRE in your callback code? Post the full exception and code. – usr Dec 25 '14 at 11:14
  • You need to say whether the unmanaged API you call is synchronous or asynchronous? Then the answer becomes simple. And I see that my above comment is little misleading. If your call is synchronous, you don't need to pin the delegate but make sure it is alive, but when your unmanaged api call is asynchronous, you must pin the delegate. – Sriram Sakthivel Dec 25 '14 at 11:17
  • @Peter Duniho, absolutely! I didn't write that clearly. I meant that is how I create the instance of a delegate that I then pass to C++. Edited. – user327301 Dec 25 '14 at 15:58
  • I want to delete this question as I'm not able to create a small example that doesn't run into other errors. I'll post a better question later if I still have one after I deal with the other errors. When I tried to delete the question I was warned not to delete questions with answers. Should I delete? – user327301 Dec 25 '14 at 18:29
  • IMHO, while one should be cautious about deleting questions with answers, that's not a hard and fast rule. If an answer was posted, but it doesn't actually solve the question as asked, and you feel that the question itself is in need of reworking to the extent that simply editing the existing question is insufficient, then deletion of the question could be fine. – Peter Duniho Dec 25 '14 at 23:10
  • I think the question is perfectly well answered. The fact that you still have a problem is another matter. You suspected delegate lifetime to be the problem but it is not. – David Heffernan Dec 26 '14 at 17:30
  • Well, it's complicated. The answer is good, but it's been voted to be closed. I can't confirm myself that the answer is correct because there are other problems with the code (you answered my other question). Although I doubt that you're wrong given your 320k reputation, I'm not sure I'm supposed to accept an answer that I can't (yet) confirm myself. I won't delete it and I'll accept the answer once I can actually get to this issue. – user327301 Dec 26 '14 at 17:36

1 Answers1

2

The application is responsible for somehow extending the lifetime of the delegate until no more calls will occur from unmanaged code.

This advice is indeed accurate. You address that concern like this:

private static MyCallback _callbackInstance;
....
_callbackInstance = new MyCallback(CallbackFunction);

So long as you don't assign to _callbackInstance until the unmanaged code is finished with your delegate then you will indeed have extended its lifetime as required.

In other words, you clearly have a fault in your program, but that fault is not in how you handle the delegate's lifetime. You will need to look elsewhere to find your defect.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490