从非托管代码回调到托管 [英] Callback from Unmanaged code to managed

查看:46
本文介绍了从非托管代码回调到托管的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在触发我的托管代码并启动对非托管代码的调用.非托管代码中有回调.从非托管中,我在托管方法DelegateMethod"中收到回调.但是我没有从非托管代码中获得正确的参数/参数值.请帮我解决这个问题

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();
        }
    }
}

我的无人管理的代码出现在这里 - CmdLib.c

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);
}

推荐答案

您的委托声明与 pFTransceive 函数指针声明不匹配.这会在您的回调方法中产生垃圾参数值.

Your delegate declaration is not a match for the pFTransceive function pointer declaration. Which produces garbage argument values in your callback method.

靠近:

    [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
    );

注意 必需 属性以匹配 C/C++ 程序中使用的默认调用约定.和 short 参数类型匹配 uint16_t.`

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.`

更多关于这篇文章.

    sCommsAbstraction psCommsFunctions = new sCommsAbstraction();

这是您必须担心的另一件事.只要本机代码可以进行回调,该对象就需要继续存在.现在它没有,下一次垃圾收集将销毁它,因为垃圾收集器无法发现本机代码正在使用它.Kaboom 当本机代码进行回调时.您还没有看到那个错误,调试器现在使对象保持活动状态.这不会在生产中发生.

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.

如所写,您需要将此语句添加到 Main() 方法的底部:

As written, you need to add this statement to the bottom of your Main() method:

    GC.KeepAlive(psCommsFunctions);

将它存储在 static 变量中是更好的方法,只有当您知道本机代码不会这样做时才将其设置回 null不再进行回调.

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.

这篇关于从非托管代码回调到托管的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆