c# - 将结构内的整数指针编码为回调

标签 c# .net c callback marshalling

我有一个用于回调的 C 结构,我需要将其编码到 C# .NET:

struct CTMDeviceInfo {
    enum CTMDeviceType eDeviceType;
    char *             szDeviceModel;
    char *             szDeviceSubModel;
    int32_t *          piDeviceID;
};

这是我的 C# 版本:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CTMDeviceInfo
{
    public CTMDeviceType deviceType;

    [MarshalAs(UnmanagedType.LPStr)]
    public string deviceModel;

    [MarshalAs(UnmanagedType.LPStr)]
    public string deviceSubModel;

    public IntPtr deviceId;
};

在另一个结构中使用:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CTMDeviceError
{
    public CTMDeviceInfo deviceInfo;

    [MarshalAs(UnmanagedType.I4)]
    public Int32 resultCode;

    [MarshalAs(UnmanagedType.I4)]
    public Int32 extendedResultCode;

    public IntPtr denomination;

    public IntPtr changeDue;
}; 

我的问题是“IntPtr deviceId”在每次回调时并不总是返回正确的值。

我期望整数值为 5、15 或 16,但它不断返回随机值,例如 106、865412、652272 等。

我不知道我做错了什么。不过,我所做的是防止使用 GCHandle 对托管代码中的回调进行垃圾收集。

以下是我的操作顺序:

从我的非托管代码中,我有这个 CDECL 回调方法:

void ctm_add_device_error_event_handler(CTMDeviceErrorCallback);

typedef void (CTMDeviceErrorCallback) (struct CTMEventInfo, struct CTMDeviceError );

这是我的托管代码:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void OnDeviceErrorCallBack(CTMEventInfo evtInfo, CTMDeviceError deviceError);

[DllImport("libctmclient-0.dll", EntryPoint = "ctm_add_device_error_event_handler", CallingConvention = CallingConvention.Cdecl)]
public static extern void AddDeviceErrorEventHandler([MarshalAs(UnmanagedType.FunctionPtr)] OnDeviceErrorCallBack deviceErrorCallBack);

OnDeviceErrorCallBack deviceErrorCallback;
GCHandle deviceErrorCallbackGCHandle;

deviceErrorCallback = new OnDeviceErrorCallBack(OnDeviceError);
deviceErrorCallbackGCHandle = GCHandle.Alloc(deviceErrorCallback);
AddDeviceErrorEventHandler(deviceErrorCallback);

这是处理回调的地方:

public void OnDeviceError(CTMEventInfo evtInfo, CTMDeviceError deviceError)
{
    int nDeviceId = Marshal.ReadInt32(deviceError.deviceInfo.deviceId);
}

我尝试使用unsafe直接使用指针,但问题还是一样。

public unsafe int *deviceId; //instead of IntPtr

int nDeviceId = 0;

unsafe
{    
    nDeviceId = *(deviceError.deviceInfo.deviceId);
}

我确信我的非托管代码返回了正确的值,因为我有日志,但当它到达我的托管代码时,不知何故返回了另一个值。 就好像它正在阅读不同的引用文献或其他东西。

希望能帮助我,因为我现在被困了一段时间。 谢谢!

最佳答案

使用以下 C# 结构。您可以在稍后的代码中从指针获取两个字符串。 :

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct CTMDeviceInfo
{
    public CTMDeviceType deviceType;

    public IntPtr deviceModel;

    public IntPtr deviceSubModel;

    public IntPtr deviceId;
};

关于c# - 将结构内的整数指针编码为回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42785337/

相关文章:

c# - 如何让ServiceProvider对手动创建的对象调用Dispose?

.net - 如何设置socket.connect()调用的时间? [复制]

python - SWIG 包装 C 库引发异常的最优雅方式

c# - Asp.Net Core 1.0.0 : Npgsql. EntityFrameworkCore.PostgreSQL 迁移错误

c# - Linq to Entities 子查询填充数组?

c# - 从单行数据表中提取值

c - 如何使用 Visual Studio 2010 进行 C 开发?

c++ - 将 c_str() 分配给字符串

c# - 异步并等待 : multiple await expressions

.net - 使用 .net 通过 HTTPS 将 xml 发布到 Paypal Reporting API 时出错