Я звоню в стороннюю библиотеку, написанную на C, из приложения NetCore.
Проблема в том, что для того, чтобы использовать эту библиотеку, мне сначала нужно сделать вызов и настроить сложную структуру, которая впоследствии должна быть передана всем последующим вызовам.
void createCtx(modbus_t ** ctx)
{
*ctx = modbus_new_tcp("192.168.1.175", 502);
//configure the context here ....
int res = modbus_connect(*ctx);
}
int pollData(modbus_t * ctx)
{
//....
modbus_read_bits(ctx, addr, 1, tab_rp_bits);
//....
}
Мой подход заключается в создании объекта modbus_t в приложении вызывающей стороны (C #), настройке его путем однократного вызова createCtx и последующей его передаче в pollData через регулярные промежутки времени.
Я читал о StructLayout, но, поскольку мне не нужен доступ к данным в объекте modbusContext, я просто хотел бы зарезервировать кусок памяти для контекста и позволить C # не обращать внимания на то, что внутри.
Это то, что я придумал
static IntPtr modbusContext;
static class ModbusDriver
{
[DllImport("modbusdriver",EntryPoint = "createCtx")]
public static extern void CreateCtx(ref IntPtr modbusContext);
[DllImport("modbusdriver",EntryPoint = "pollData")]
public static extern uint PollData(IntPtr modbusContext)
}
static void Main(string[] args)
{
int ctxSize = ModbusDriver.GetCtxSize();
modbusContext = Marshal.AllocHGlobal(80 * Marshal.SizeOf(typeof(byte))); //<--- 80 is the result of sizeof(modbus_t)
ModbusDriver.CreateCtx(ref modbusContext);
while(true)
{
ModbusDriver.PollData(modbusContext);
Thread.Sleep(1000);
}
}
}
Все это работает, но на самом деле это не так, особенно потому, что структура modbus_t довольно сложна
struct modbus_t {
/* Slave address */
int slave;
/* Socket or file descriptor */
int s;
int debug;
int error_recovery;
struct timeval response_timeout;
struct timeval byte_timeout;
struct timeval indication_timeout;
const modbus_backend_t *backend;
void *backend_data;
};
typedef struct _modbus_backend {
unsigned int backend_type;
unsigned int header_length;
unsigned int checksum_length;
unsigned int max_adu_length;
int (*set_slave) (modbus_t *ctx, int slave);
int (*build_request_basis) (modbus_t *ctx, int function, int addr,
int nb, uint8_t *req);
int (*build_response_basis) (sft_t *sft, uint8_t *rsp);
int (*prepare_response_tid) (const uint8_t *req, int *req_length);
int (*send_msg_pre) (uint8_t *req, int req_length);
ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length);
int (*receive) (modbus_t *ctx, uint8_t *req);
ssize_t (*recv) (modbus_t *ctx, uint8_t *rsp, int rsp_length);
int (*check_integrity) (modbus_t *ctx, uint8_t *msg,
const int msg_length);
int (*pre_check_confirmation) (modbus_t *ctx, const uint8_t *req,
const uint8_t *rsp, int rsp_length);
int (*connect) (modbus_t *ctx);
void (*close) (modbus_t *ctx);
int (*flush) (modbus_t *ctx);
int (*select) (modbus_t *ctx, fd_set *rset, struct timeval *tv, int msg_length);
void (*free) (modbus_t *ctx);
} modbus_backend_t;
Итак, мой вопрос, правильный ли мой подход?
В частности, modbus_t содержит указатели. Мне удалось сохранить структуру modbus_t в C #, и она, кажется, работает, но действительно ли безопасно предположить, что память, на которую ссылаются указатели, содержащиеся в структуре, не будет повреждена между вызовами? Это не правильно.