c# - 我应该如何将这个 C 函数指针结构移植到 C# .NET 实现
问题描述
我正在将通常用 C/C++ 为 WIN32 编写的引导加载程序主机库移植到 C# 类库(而不是必须与原始库使用互操作,希望使其更易于使用和调试)。作为对 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() 的定义,我希望将其放在应用程序中,而不是库中。
我在正确的轨道上吗?如何在 .NET 类库中复制此功能?
解决方案
如果OpenConnection
要在您编写时由应用程序提供,则使用delegate
可能是正确的方法。然后您需要在应用程序中定义这些方法并填充结构。
或者,CommunicationData
可以使interface
您的应用程序或其他一些类需要实现,然后将其传递给库函数。或者也许将一个库包装在一个类中(g_comm
成为一个字段)并将接口仅传递给它的构造函数。
推荐阅读
- powershell - PowerShell 使用作业快速 Ping 子网
- java - 错误:- NetBeans IDE 8.2 中的空点异常
- string - 如何用随机替换词有效地替换字符串中的词?
- npm - 启动 npm 错误(npm install --save-dev webpack)
- c++ - 如何将空数组传递给地图?
- tableau-api - 无法从 Tableau 连接 Microsoft SQL Server
- java - 出现类似“java.lang.UnsupportedOperationException:Servlet 3.0 规范的第 4.4 节不允许调用此方法”之类的错误
- php - laravel,更新表结构,但使用 php artisan migrate 时获取错误表已经存在
- angular - 仅将选定的值作为参数传递给 Angular 下拉列表中的 Api 调用
- c++ - 使用两个线程和 system() 命令运行 shell 脚本:如何确保一个 shell 脚本先于另一个启动