You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#中调用含缓冲区指针参数的Nvidia Omniverse C API遇崩溃

解决.NET Core调用Nvidia Omniverse omniClientWriteFileEx崩溃问题

你遇到的崩溃问题,核心出在C#与C API的类型封送不匹配、结构传递方式错误这两个关键点上,下面逐一分析你的方案问题,并给出正确实现:

方案1的致命错误

  1. 结构类型映射错误:OmniClientContent的Buffer字段用Byte[]完全错误——C#数组无法直接映射到C的void*指针,CLR封送时会生成数组的包装对象,而API期望的是原始内存地址,直接导致内存访问越界崩溃。
  2. 笔误问题:代码中Buffer = content明显是错误,应该指向读取到的data数组。

方案2的核心问题

  1. 变量名冲突:var content = await dssHttpContent.ReadAsByteArrayAsync();与后续var content = new OmniClientContent重名,编译阶段就会报错。
  2. 结构传递方式错误:C API的content参数是const OmniClientContent*(指针传递),而你用值传递结构,CLR会拷贝结构值后传递,API无法正确读取缓冲区信息。
  3. 内存管理隐患:分配的非托管内存Marshal.AllocHGlobal未在合适时机释放,且如果API是异步处理,提前释放会直接导致崩溃。
  4. 字符集未指定:Omniverse的C API默认使用UTF-8字符串,未指定字符集会导致字符串封送错误。

正确实现步骤

1. 匹配C API的结构与函数定义

根据Omniverse的C API契约,先修正DllImport和结构定义:

// 注意指定UTF-8字符集,匹配C API的字符串编码
[DllImport(dllPath, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Utf8)]
static extern ulong omniClientWriteFileEx(
    string url,
    ref OmniClientContent content,  // 用ref对应C的指针传递
    IntPtr userData,
    [MarshalAs(UnmanagedType.FunctionPtr)] OmniClientWriteCallback callback,
    string message);

// 对应C的size_t类型,兼容32/64位平台
[StructLayout(LayoutKind.Sequential)]
private struct OmniClientContent
{
    public UIntPtr Size;
    public IntPtr Buffer;
}

// 定义回调委托(如果API是异步模式)
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void OmniClientWriteCallback(
    IntPtr userData,
    ulong result,
    ulong bytesWritten,
    ulong totalBytes);

2. 同步模式下的正确调用(API同步处理)

public async Task UploadUsingCApiAsync(string url, HttpContent httpContent)
{
    var data = await httpContent.ReadAsByteArrayAsync().ConfigureAwait(false);
    IntPtr buffer = IntPtr.Zero;

    try
    {
        // 分配非托管内存
        buffer = Marshal.AllocHGlobal(data.Length);
        Marshal.Copy(data, 0, buffer, data.Length);

        var content = new OmniClientContent
        {
            Size = (UIntPtr)data.Length,
            Buffer = buffer
        };

        // 调用API,必须用ref传递结构
        ulong result = omniClientWriteFileEx(url, ref content, IntPtr.Zero, null, string.Empty);

        // 检查API返回码,0通常表示成功
        if (result != 0)
        {
            throw new InvalidOperationException($"OmniClient调用失败,错误码:{result}");
        }
    }
    finally
    {
        // 同步调用完成后释放内存
        if (buffer != IntPtr.Zero)
        {
            Marshal.FreeHGlobal(buffer);
        }
    }
}

3. 异步模式下的正确调用(API异步处理)

如果omniClientWriteFileEx是异步执行(通过回调返回结果),需要在回调中释放内存:

public async Task<ulong> UploadUsingCApiAsync(string url, HttpContent httpContent)
{
    var data = await httpContent.ReadAsByteArrayAsync().ConfigureAwait(false);
    IntPtr buffer = Marshal.AllocHGlobal(data.Length);
    Marshal.Copy(data, 0, buffer, data.Length);

    var tcs = new TaskCompletionSource<ulong>();

    // 定义回调函数,在回调中释放内存并完成Task
    OmniClientWriteCallback callback = (userData, result, bytesWritten, totalBytes) =>
    {
        try
        {
            if (result != 0)
            {
                tcs.SetException(new InvalidOperationException($"上传失败,错误码:{result}"));
            }
            else
            {
                tcs.SetResult(totalBytes);
            }
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    };

    var content = new OmniClientContent
    {
        Size = (UIntPtr)data.Length,
        Buffer = buffer
    };

    // 启动异步上传
    ulong initResult = omniClientWriteFileEx(url, ref content, IntPtr.Zero, callback, string.Empty);
    if (initResult != 0)
    {
        Marshal.FreeHGlobal(buffer);
        throw new InvalidOperationException($"启动上传失败,错误码:{initResult}");
    }

    // 等待异步完成
    return await tcs.Task.ConfigureAwait(false);
}

关键注意事项

  • 结构传递方式:必须用ref传递OmniClientContent,对应C API的指针参数,否则API无法正确读取缓冲区信息。
  • size_t类型兼容:用UIntPtr代替int,避免64位平台下缓冲区大小被截断。
  • 字符集设置:CharSet.Utf8必须指定,否则字符串封送会导致API解析错误。
  • 异步内存管理:异步模式下,缓冲区必须在回调中释放,不能提前释放,否则API处理时会访问已释放的内存。

内容的提问来源于stack exchange,提问作者S7H

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 21:37:39