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

将C#代码转C++/CLI时,托管对象句柄与Lambda表达式报错问题

C# SkiaSharp代码转C++/CLI的InstallPixels回调问题解决

错误原因分析

第一种写法的错误

  1. 委托类型不匹配:InstallPixels要求的是SKBitmapReleaseDelegate类型(签名为void(IntPtr, Object^)),但你用了Action<GCHandle>,签名完全不符。
  2. 委托初始化错误:静态方法的委托不需要传递实例对象(第一个参数应为nullptr),且你错误地将GCHandle作为委托构造参数传入,正确做法是将其作为context参数传递给InstallPixels。
  3. 值类型误用gcnew:SKImageInfo是值类型,无需用gcnew分配托管堆对象,直接声明栈实例即可。

第二种写法的错误

  1. 不必要的gcroot:gcroot用于在非托管代码中持有托管引用,此处纯托管环境下不需要,直接使用GCHandle即可。
  2. 成员访问符号错误:gcroot<GCHandle>是值类型,访问成员需用.而非->。
  3. Lambda签名不匹配:Lambda未匹配SKBitmapReleaseDelegate的双参数签名。

正确实现代码

方法1:静态回调方法+Context传递GCHandle

#include <SkiaSharp.h>
using namespace System::Runtime::InteropServices;
using namespace SkiaSharp;

static void ReleasePixelBuffer(IntPtr pixels, System::Object^ context)
{
    // 将context转换回GCHandle并释放
    GCHandle handle = safe_cast<GCHandle>(context);
    handle.Free();
}

static void Test()
{
    // 创建输出位图
    SKBitmap^ bitmap = gcnew SKBitmap();
    // SKImageInfo是值类型,直接栈上声明
    SKImageInfo info(input.cols, input.rows, SKColorType::Bgra8888);

    // 创建像素缓冲区
    array<System::Byte>^ buffer = gcnew array<System::Byte>(input.cols * input.rows * 4);
    GCHandle outputPtr = GCHandle::Alloc(buffer, GCHandleType::Pinned);

    // 调用InstallPixels,传递正确的委托和context
    bitmap->InstallPixels(
        info,
        outputPtr.AddrOfPinnedObject(),
        info.RowBytes,
        gcnew SKBitmapReleaseDelegate(&ReleasePixelBuffer),
        GCHandle::ToObject(outputPtr) // 将GCHandle包装为Object作为上下文传递
    );
}

方法2:Lambda表达式(C++/CLI支持捕获式Lambda转委托)

#include <SkiaSharp.h>
using namespace System::Runtime::InteropServices;
using namespace SkiaSharp;

static void Test()
{
    SKBitmap^ bitmap = gcnew SKBitmap();
    SKImageInfo info(input.cols, input.rows, SKColorType::Bgra8888);

    array<System::Byte>^ buffer = gcnew array<System::Byte>(input.cols * input.rows * 4);
    GCHandle outputPtr = GCHandle::Alloc(buffer, GCHandleType::Pinned);

    // 使用匹配签名的Lambda作为回调,直接捕获GCHandle
    bitmap->InstallPixels(
        info,
        outputPtr.AddrOfPinnedObject(),
        info.RowBytes,
        gcnew SKBitmapReleaseDelegate([outputPtr](IntPtr pixels, System::Object^) {
            outputPtr.Free();
        }),
        nullptr
    );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 14:50:22