从非托管代码回调到托管代码
Callback from Unmanaged code to managed
我正在触发我的托管代码并启动对非托管代码的调用。非托管代码中有一个回调。从非托管我在我的托管方法 'DelegateMethod' 中获得回调。但是我没有从非托管代码中获得正确的 parameter/argument 值。请帮我解决这个问题
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();
}
}
}
我未处理的代码出现在这里 - 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);
}
您的委托声明与 pFTransceive
函数指针声明不匹配。这会在您的回调方法中产生垃圾参数值。
近距离接触:
[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
);
请注意 required 属性以匹配 C/C++ 程序中使用的默认调用约定。 short 参数类型匹配 uint16_t
.`
更多关于this post中调用约定的奥秘。
sCommsAbstraction psCommsFunctions = new sCommsAbstraction();
这是另一件你不得不担心的事情。只要本机代码可以进行回调,该对象就需要生存。现在它没有,下一次垃圾收集将销毁它,因为垃圾收集器无法发现本机代码正在使用它。 Kaboom 当本机代码进行回调时。您还没有看到该错误,调试器现在使对象保持活动状态。这不会在生产中发生。
正如所写,您需要将此语句添加到 Main() 方法的底部:
GC.KeepAlive(psCommsFunctions);
将其存储在 static 变量中是更好的方法,只有当您知道本机代码不是这样的事实时才将其设置回 null
打算再回调了。
我正在触发我的托管代码并启动对非托管代码的调用。非托管代码中有一个回调。从非托管我在我的托管方法 'DelegateMethod' 中获得回调。但是我没有从非托管代码中获得正确的 parameter/argument 值。请帮我解决这个问题
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();
}
}
}
我未处理的代码出现在这里 - 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);
}
您的委托声明与 pFTransceive
函数指针声明不匹配。这会在您的回调方法中产生垃圾参数值。
近距离接触:
[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
);
请注意 required 属性以匹配 C/C++ 程序中使用的默认调用约定。 short 参数类型匹配 uint16_t
.`
更多关于this post中调用约定的奥秘。
sCommsAbstraction psCommsFunctions = new sCommsAbstraction();
这是另一件你不得不担心的事情。只要本机代码可以进行回调,该对象就需要生存。现在它没有,下一次垃圾收集将销毁它,因为垃圾收集器无法发现本机代码正在使用它。 Kaboom 当本机代码进行回调时。您还没有看到该错误,调试器现在使对象保持活动状态。这不会在生产中发生。
正如所写,您需要将此语句添加到 Main() 方法的底部:
GC.KeepAlive(psCommsFunctions);
将其存储在 static 变量中是更好的方法,只有当您知道本机代码不是这样的事实时才将其设置回 null
打算再回调了。