简体   繁体   English

从非托管代码回调到托管代码

[英]Callback from Unmanaged code to managed

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'. 从非托管我得到我的托管方法'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 我的无限代码存在于此处 - 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);
}

Your delegate declaration is not a match for the pFTransceive function pointer declaration. 您的委托声明与pFTransceive函数指针声明不匹配。 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. 请注意必需的属性以匹配C / C ++程序中使用的默认调用约定。 And the short argument types to match uint16_t .` 短的参数类型匹配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. 当本机代码进行回调时Kaboom。 You are not seeing that bug yet, the debugger keeps the object alive right now. 你还没有看到那个bug,调试器现在让对象保持活着状态。 That is not going to happen in production. 这不会发生在生产中。

As written, you need to add this statement to the bottom of your Main() method: 如上所述,您需要将此语句添加到Main()方法的底部:

    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. 将它存储在静态变量中是更好的方法,只有在您知道本机代码不再进行回调的事实时才将其设置为null

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM