Callback from Unmanaged code to managed

痞子三分冷 提交于 2021-02-09 02:54:36

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!