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

C++/CLI调用C# Clipboard.GetText()触发System.OutOfMemoryException求助

问题解决:C++/CLI剪贴板传文本导致C# OutOfMemoryException

我开发的C++/CLI应用包含MFC界面,需要从TextBox获取文本后调用C#方法处理,采用剪贴板传递文本。但将少量文本复制到剪贴板后,C#中执行Clipboard.GetText()时立即触发System.OutOfMemoryException(异常来自C#)。

原代码

C++代码

bool onclick(CStringW text){
if (!OpenClipboard(hwnd)) return false;
    if (!EmptyClipboard())
    {
        CloseClipboard();
        return false;
    }

    bool result;
    CAutoDelGlobalAlloc hMem(::GlobalAlloc(GMEM_MOVEABLE, (text.GetLength() + 1) * sizeof(WCHAR)));
    if (hMem)
    {
        CGlobalLock<WCHAR> lock(hMem);
        WCHAR* pText = lock;
        if (pText)
        {
            wcsncpy_s(pText, text.GetLength() + 1, text.GetString(), _TRUNCATE);
            pText[text.GetLength()] = L'\0';
            ::SetClipboardData(CF_UNICODETEXT, hMem);
            result = true;
        }
    }
    
    CloseClipboard();
    csharp_object.Process();
    return result;
}

C# DLL代码

public class CSharp_object{
    public void Process(){
         var text = Clipboard.GetText();
         
    }
}

问题根源

核心问题是剪贴板内存的所有权管理错误:

  • 使用CAutoDelGlobalAlloc这种自动释放的句柄包装类,在SetClipboardData调用后,该类会自动释放内存句柄,但SetClipboardData要求调用方传递句柄后放弃所有权——剪贴板会接管这块内存的生命周期,原调用方不能再释放它。自动释放逻辑导致剪贴板拿到的是已被释放的无效内存,C#读取时触发内存异常。
  • 代码未检查SetClipboardData的返回值,无法确认数据是否成功写入剪贴板。

解决方案

  1. 移除自动释放的内存句柄包装:改用普通HGLOBAL,手动管理但不主动释放——剪贴板会在合适时机自行释放内存。
  2. 增加关键调用的错误检查:确认SetClipboardData执行成功。
  3. 可选:C#端明确指定文本格式:避免格式匹配问题。

修改后的C++代码

bool onclick(CStringW text){
    if (!OpenClipboard(hwnd)) return false;
    if (!EmptyClipboard())
    {
        CloseClipboard();
        return false;
    }

    bool result = false;
    HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, (text.GetLength() + 1) * sizeof(WCHAR));
    if (hMem)
    {
        WCHAR* pText = static_cast<WCHAR*>(::GlobalLock(hMem));
        if (pText)
        {
            wcscpy_s(pText, text.GetLength() + 1, text.GetString());
            ::GlobalUnlock(hMem);
            
            // 检查剪贴板数据是否设置成功
            if (::SetClipboardData(CF_UNICODETEXT, hMem) != nullptr)
            {
                result = true;
                // 注意:SetClipboardData后,hMem的所有权已转移给剪贴板,不能再释放
            }
            else
            {
                // 设置失败时,手动释放内存
                ::GlobalFree(hMem);
            }
        }
        else
        {
            ::GlobalFree(hMem);
        }
    }
    
    CloseClipboard();
    if (result)
    {
        csharp_object.Process();
    }
    return result;
}

修改后的C#代码(可选)

public class CSharp_object{
    public void Process(){
         var text = Clipboard.GetText(System.Windows.Forms.TextDataFormat.UnicodeText);
    }
}

补充说明

  • GMEM_ZEROINIT可选,确保内存初始化为0,避免残留垃圾数据。
  • wcscpy_s比wcsncpy_s更适合这里,因为已分配足够内存,无需截断逻辑。
  • 必须在CloseClipboard之后调用C#的Process,否则剪贴板处于锁定状态,C#无法读取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:24:04