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

开发TSF文本服务遇TF_E_NOLOCK错误:ec中cookie无效如何解决?

TF_E_NOLOCK Error When Calling ITfContext.GetStart() in TSF Edit Session

我来帮你分析下这个问题的根源和解决办法:

问题根源

你遇到的TF_E_NOLOCK错误,核心原因是你在错误的时机访问了无效的编辑Cookie。TSF的EditSession是异步执行机制:当你调用context.RequestEditSession()后,TSF会在合适的时机(比如当前没有其他编辑锁冲突时)才会调用你的EditSession.DoEditSession()方法,并传入有效的ec(编辑Cookie)。而你在OnTestKeyDown里调用RequestEditSession后立刻访问editSession.EditCookie,这时候DoEditSession大概率还没执行,EditCookie还是默认的0,自然是无效的,导致后续GetStart调用失败。

此外,所有TSF上下文的编辑操作(比如GetStart、SetText)都应该放在DoEditSession方法内部执行——因为只有在这个方法里,TSF才确保了当前线程持有正确的编辑锁,ec是有效的。

修复方案

我们需要重构EditSession,把编辑逻辑移到DoEditSession内部,并通过构造函数传递需要的上下文和数据:

1. 重构EditSession类

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class EditSession : BaseObject, ITfEditSession
{
    private readonly ITfContext _targetContext;
    private readonly string _textToInsert;

    // 通过构造函数传入需要的上下文和要插入的文本
    public EditSession(ITfContext targetContext, string textToInsert)
    {
        _targetContext = targetContext;
        _textToInsert = textToInsert;
    }

    public HRESULT DoEditSession(uint ec)
    {
        // 所有上下文操作都在这里执行,ec是TSF传入的有效编辑Cookie
        HRESULT res = _targetContext.GetStart(ec, out var range);
        if (res.Failed)
        {
            Debug.WriteLine($"GetStart failed: {(ManagerReturnValues)res.Code}");
            return res;
        }

        char[] charArray = _textToInsert.ToCharArray();
        res = range.SetText(ec, 0, charArray, charArray.Length);
        Debug.WriteLine($"SetText result: {(ManagerReturnValues)res.Code}");

        return res;
    }
}

2. 修改KeyEventSink的OnTestKeyDown方法

public HRESULT OnTestKeyDown(ITfContext pic, UIntPtr wParam, IntPtr lParam, out bool pfEaten)
{
    pfEaten = false;
    uint vkCode = wParam.ToUInt32();
    char nonVirtualKey = (char)MapVirtualKey(vkCode, 2);
    
    Debug.WriteLine(nonVirtualKey);
    if (nonVirtualKey == 'F')
    {
        HRESULT res = _threadMgr.GetFocus(out var documentMgr);
        if (res.Failed)
        {
            return res;
        }

        res = documentMgr.GetTop(out var context);
        if (res.Failed)
        {
            return res;
        }

        // 创建EditSession时传入上下文和要插入的文本
        var editSession = new EditSession(context, "་");
        res = context.RequestEditSession(_clientId, editSession, TF_ES.TF_ES_READWRITE, out var phrSession);
        
        HRESULT phrSessionHresult = new HRESULT { Code = phrSession };
        if (phrSessionHresult.Succeeded)
        {
            pfEaten = true; // 标记按键已被处理
        }
        
        return S_OK();
    }

    return S_OK();
}

关键说明

  • 异步执行逻辑:RequestEditSession只是发起一个编辑请求,TSF会在后台合适的时机执行DoEditSession,所以你不能在请求后立刻访问EditSession的内部状态。
  • 锁上下文有效性:只有在DoEditSession方法内,ec才是有效的编辑Cookie,TSF已经处理了锁的获取和释放,避免了并发冲突。
  • 结果判断:RequestEditSession返回的phrSession是会话执行的最终结果,可以用来判断编辑操作是否成功完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 22:37:46