问题
I am triggering my managed code and initiating a call to unmanaged code. There is a callback in unmanaged code. From unmanaged I am getting callback in my managed method 'DelegateMethod'. But I am not getting proper parameter/argument values from unmanaged code. Please help me with this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace TestApp
{
public class Program
{
public delegate void fPointer(byte[] Sendapdu, ref int Sendlen, byte[] Recvapdu, ref int Recvlen);
public struct sCommsAbstraction
{
///Function to send and receive.
public fPointer pf_TxRx;
///Other functions if necessary, e.g. reset
}
// Create a method for a delegate.
public static void DelegateMethod(byte[] Sendapdu, ref int Sendlen, byte[] Recvapdu, ref int Recvlen)
{
//This is called from unmanaged code. I am not getting proper arguments
Console.WriteLine(Sendlen);
}
[DllImport("AuthLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int CmdLib_RegisterItsIO(ref sCommsAbstraction psCommsFunctions);
[DllImport("AuthLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int CmdLib_OpenApplication();
[DllImport("TransparentChannel.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TC_Transceive(byte[] writeBuf, ref int writeBufLen, byte[] readBuf, ref int pwReadBufferLen);
static void Main(string[] args)
{
sCommsAbstraction psCommsFunctions = new sCommsAbstraction();
// Instantiate the delegate.
psCommsFunctions.pf_TxRx = DelegateMethod;
CmdLib_RegisterItsIO(ref psCommsFunctions);
CmdLib_OpenApplication();
}
}
}
My unmanged piece of code is present here - CmdLib.c
//C code - unmanaged
typedef int32_t (*pFTransceive)(const uint8_t *prgbWriteBuffer, const uint16_t *pwWriteBufferLen, uint8_t *prgbReadBuffer, uint16_t *pwReadBufferLen);
typedef struct sCommsAbstraction
{
///Function to send and receive.
pFTransceive pf_TxRx;
///Other functions if necessary, e.g. reset
}sCommsAbstraction_d
static sCommsAbstraction_d sCommsAbstraction = {0};
void CmdLib_RegisterItsIO(const sCommsAbstraction_d *psCommsFunctions)
{
sCommsAbstraction.pf_TxRx = psCommsFunctions->pf_TxRx;
}
void CmdLib_OpenApplication()
{
sCommsAbstraction.pf_TxRx(rgbAPDUBuffer,&wTotalLength,rgbAPDUBuffer,&psApduData->wResponseLength);
}
回答1:
Your delegate declaration is not a match for the pFTransceive
function pointer declaration. Which produces garbage argument values in your callback method.
Get closer with:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void fPointer(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
byte[] Sendapdu, ref short Sendlen,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)]
byte[] Recvapdu, ref short Recvlen
);
Note the required attribute to match the default calling convention that's used in C/C++ programs. And the short argument types to match uint16_t
.`
More about the mysteries of calling conventions in this post.
sCommsAbstraction psCommsFunctions = new sCommsAbstraction();
This is another thing you have to fret about. That object needs to survive as long as the native code can make callbacks. Right now it doesn't, the next garbage collection is going to destroy it since the garbage collector has no way to find out that the native code is using it. Kaboom when the native code makes the callback. You are not seeing that bug yet, the debugger keeps the object alive right now. That is not going to happen in production.
As written, you need to add this statement to the bottom of your Main() method:
GC.KeepAlive(psCommsFunctions);
Storing it in a static variable is the better approach, only ever set it back to null
when you know for a fact that the native code isn't going to make callbacks anymore.
来源:https://stackoverflow.com/questions/31511996/callback-from-unmanaged-code-to-managed