微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我应该如何将此C函数指针结构移植到C#.NET实现

如何解决我应该如何将此C函数指针结构移植到C#.NET实现

我正在将通常使用C / C ++ for WIN32编写的引导加载程序宿​​主库移植到C#类库(而不是必须与原始库一起使用interop,希望可以更轻松地使用和调试) )。作为对OOP不太熟悉的人,我正在尝试找出如何将库的此特定功能实现为C#.NET(VS2019,.NET Standard 2.0)

在原始的C库中,库源代码的头文件中具有以下结构:

typedef struct
{
    /* Function used to open the communications connection */
    int (*OpenConnection)(void);
    /* Function used to close the communications connection */
    int (*CloseConnection)(void);
    /* Function used to read data over the communications connection */
    int (*ReadData)(uint8_t*,int);
    /* Function used to write data over the communications connection */
    int (*WriteData)(uint8_t*,int);
    /* Value used to specify the maximum number of bytes that can be transfered at a time */
    unsigned int MaxTransferSize;
} CommunicationsData;

这由内部库函数调用,如下所示:

static CommunicationsData* g_comm;

int Bootloader_TransferData(uint8_t* inBuf,int inSize,uint8_t* outBuf,int outSize)
{
    int err = g_comm->WriteData(inBuf,inSize);

    if (CYRET_SUCCESS == err)
        err = g_comm->ReadData(outBuf,outSize);

    if (CYRET_SUCCESS != err)
        err |= CYRET_ERR_COMM_MASK;

    return err;
}

这个想法是库本身与通信协议无关,并且使用该库的应用程序是您编写OpenConnection()/ CloseConnection()/ ReadData()/ WriteData()的实现并提供值的地方用于MaxTransferSize。在将原始C库与互操作一起使用的C#应用​​程序中,操作如下:

class Bootloader_Utils{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int OpenConnection();
    
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int CloseConnection();
    
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int ReadData(IntPtr buffer,int size);
    
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate int WriteData(IntPtr buffer,int size);
    
    /// <summary>
    /// Structure used to pass communication data down to the unmanged native C code
    /// that handles the bootloading operations.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct CommunicationsData
    {
        /// <summary>
        /// Function used to open the communications connection
        /// </summary>
        public OpenConnection OpenConnection;
        /// <summary>
        /// Function used to close the communications connection
        /// </summary>
        public CloseConnection CloseConnection;
        /// <summary>
        /// Function used to read data over the communications connection
        /// </summary>
        public ReadData ReadData;
        /// <summary>
        /// Function used to write data over the communications connection
        /// </summary>
        public WriteData WriteData;
        /// <summary>
        /// Value used to specify the maximum number of bytes that can be transferred at a time
        /// </summary>
        public uint MaxTransferSize;
    };
}

然后,您将在应用程序代码中创建一个新的CommunicationsData对象并分配方法

Bootload_Utils.CommunicationsData comm_data = new Bootload_Utils.CommunicationsData();
    
comm_data.OpenConnection = OpenConnection;
comm_data.CloseConnection = CloseConnection;
comm_data.ReadData = ReadData;
comm_data.WriteData = WriteData;
comm_data.MaxTransferSize = 64;

然后在C#应用程序中定义这些方法,例如本例中的OpenConnection():

public int OpenConnection()
{
    int status = (int)ReturnCodes.CYRET_SUCCESS;

    if (ConnectionStatus == false)
    {
        try
        {
            serialPort.open();
            ConnectionStatus = true;
        }
        catch (Exception exc)
        {
            ConnectionStatus = false;
            SetText(tb_StatusLog," Error in opening serial port: " + exc.Message + "\r\n");

            serialPort.Close();
        }
    }
    return status;
}

如何在C#中复制此行为?我的想法是这样的:

public class CommunicationData
{
    delegate int OpenConnection();
    delegate int CloseConnection();
    delegate int ReadData(ref byte[] dataBuf,int numBytes);
    delegate int WriteData(ref byte[] dataBuf,int numBytes);
    int MaxTransferSize { get; set; }
}

然后我可以在库中创建此类的新实例并调用方法

CommunicationData g_Comm = new CommunicationData();
int err = g_Comm.OpenConnection();

但这不是很正确,因为它仍然需要OpenConnection()的定义,我想将其定义在Application中,而不是在库中。

在这里正确吗?如何在.NET类库中复制此功能

解决方法

如果在编写时由应用程序提供OpenConnection,则使用delegate可能是正确的方法。然后,您需要在应用程序中定义这些方法并填充结构。

或者,可以将CommunicationData设置为应用程序或某些其他类需要实现的interface,然后将 that 传递给库函数。或者也许将一个库包装在一个类中(其中g_comm成为一个字段),然后仅将接口传递给其构造函数。

,

我同意@numzero,这可能是您正在寻找的接口。但是,如果您想更接近原始实现,则:

public class CommunicationData
{
    public Func<int> OpenConnection { get; set; }       
    //etc
    
    int MaxTransferSize { get; set; }
}

您可以这样做:

var data = new CommunicationData();
data.OpenConnection = OpenConnection;
data.OpenConnection();

使用界面

//in your lib
public interface ICommunicationData
{
    int OpenConnection();
    int CloseConnection();
    int ReadData(byte[] dataBuf,int numBytes);
    int WriteData(byte[] dataBuf,int numBytes);
    int MaxTransferSize { get; set; }
}

//in your app
public class SerialCommunicationData : ICommunicationData
{
    public int MaxTransferSize { get; set; }

    public int CloseConnection()
    {
        return 1;
    }

    public int OpenConnection()
    {
        return 1;
    }

    public int ReadData(byte[] dataBuf,int numBytes)
    {
        return 1;
    }

    public int WriteData(byte[] dataBuf,int numBytes)
    {
        return 1;
    }
}


public class UsbCommunicationData : ICommunicationData
{
    public int MaxTransferSize { get; set; }

    public int CloseConnection()
    {
        return 1;
    }

    public int OpenConnection()
    {
        return 1;
    }

    public int ReadData(byte[] dataBuf,int numBytes)
    {
        return 1;
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。