Was this page helpful?
Your feedback about this content is important. Let us know what you think.
Additional feedback?
1500 characters remaining
Marshaling Function Pointers

Marshaling Function Pointers

Visual Studio .NET 2003

When functions accept a function pointer as a parameter, they can be used as a callback function, as demonstrated in the following unmanaged code:

typedef int (*PFN_ANSWER)();
TRADITIONALDLL_API int GetTheAnswer(PFN_ANSWER pfn)
{
   return pfn();
}

The GetTheAnswer function expects a function pointer for a method that takes no arguments and returns an integer.

If the caller of this unmanaged function is a managed application, then you would call the function this way:

int SlowGetAnswer()
{
   return 42;
}
int main()
{
   int answer;
   DWORD tStart,tStop;
   tStart = GetTickCount();
   for (int s = 0;s<10000000;s++)
   {
      answer = GetTheAnswer(SlowGetAnswer);
   }
   tStop = GetTickCount();
   Console::WriteLine("{0}",__box(tStop-tStart));
   return 0;
}

When this code calls the unmanaged function, it causes a managed to unmanaged code transition. When GetTheAnswer calls back to the caller, another unmanaged to managed code transition occurs, which is very inefficient. Inserting a pragma statement will improve the speed, as demonstrated in the following code:

#pragma unmanaged
int FastGetAnswer()
{
   return 33;
}
#pragma managed
int main()
{
   int answer;
   DWORD tStart,tStop;
   tStart = GetTickCount();
   for (int f = 0;f<10000000;f++)
   {
      answer = GetTheAnswer(FastGetAnswer);
   }
   tStop = GetTickCount();
   Console::WriteLine("{0}",__box(tStop-tStart));
   return 0;
}

The code bracketed by the two pragma statements is unmanaged. When the GetTheAnswer function calls back to the caller, the function being called is also unmanaged. This eliminates one unmanaged to managed code transition.

Unmanaged C++ clients cannot call this function directly. To do this, define a PInvoke signature with a delegate as the parameter type for the function pointer. The following code defines an appropriate delegate and the required PInvoke signature and then calls the unmanaged function with the delegate.

public __delegate int GetTheAnswerDelegate();
public __value struct TraditionalDLL
{
   [DllImport("TraditionalDLL.dll")]
   static public int GetTheAnswer(GetTheAnswerDelegate* pfn);
// ...
};
// ...
int SelectNumber()
{
   static int x = 0;
   return ++x;
}
// ...
GetTheAnswerDelegate* pfn;
pfn = new GetTheAnswerDelegate(this,SelectNumber);
int answer = TraditionalDLL::GetTheAnswer(pfn);
Console::WriteLine("The answer is {0}",__box(answer));

Go to the next step | Go back to the last step

See Also

Managed Extensions for C++ and Data Marshaling Tutorial

Show:
© 2015 Microsoft