使用扩展的Node-API接口创建和销毁临界区作用域及访问字符串内容
==================================

Node-API扩展接口napi\_open\_critical\_scope用于打开临界区作用域，napi\_close\_critical\_scope用于关闭临界区作用域。

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/59/v3/jdJXwQeOSj6WN4p8Xg_nxA/caution_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073810Z&HW-CC-Expire=86400&HW-CC-Sign=7CD0A80E3C3904F4C615232F6CBB727ED65D72A7DDB8E6027B850C44FAEC7D51)

非临界接口不能在临界区作用域使用，且同一执行环境中只能打开一个临界区作用域。建议仅在需要临界接口时打开临界区作用域，使用后应及时关闭。

#### 场景介绍

调用临界接口前，必须通过napi\_open\_critical\_scope打开临界区作用域，并在临界区作用域内进行调用。

关闭临界区作用域后，请勿使用临界接口及其返回结果，否则可能导致程序崩溃或数据损坏。

#### 临界区作用域的打开、关闭及临界接口的使用

| 接口 | 描述 | 临界区作用域外执行的状态码 |
| :-- | :-- | :-- |
| napi\_open\_critical\_scope | 打开临界区作用域 | NA |
| napi\_close\_critical\_scope | 关闭临界区作用域 | napi\_generic\_failure |
| napi\_get\_buffer\_string\_utf16\_in\_critical\_scope | 获取ArkTS String的UTF-16编码内存缓冲区数据 | napi\_generic\_failure |

![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/f/v3/ut1kYeBTRPCXFLK4kKNW4A/caution_3.0-zh-cn.png?HW-CC-KV=V1&HW-CC-Date=20260612T073810Z&HW-CC-Expire=86400&HW-CC-Sign=05523BB5E808B9168DA60410791B6E2FDFC7FAFDA46A737848668A71D5CF7FCF)

1.当ArkTS String以UTF-16编码存储时，napi\_get\_buffer\_string\_utf16\_in\_critical\_scope才能正确获取其内存缓冲区，否则该函数返回错误。

2.napi\_create\_string\_utf16和napi\_create\_string\_utf8的功能是将输入数据以指定编码传递给虚拟机。这些函数不控制字符串在虚拟机的内部存储编码方式。

#### 示例代码

*   模块注册
    
    // napi\_init.cpp
    #include <string>
    #include <string\_view>
    #include <vector>
    
    #include "napi/native\_api.h"
    
       // 使用C++的RAII机制管理临界区作用域，避免遗漏关闭
       // 仅用作示例，也可以通过其他方式进行封装，或直接使用原始接口
       class MyCriticalScope
    {
       napi\_env env\_{};
       napi\_critical\_scope scope\_{};
    
    public:
       explicit MyCriticalScope(napi\_env env) : env\_(env)
       {
          if (napi\_open\_critical\_scope(env, &scope\_) != napi\_ok)
          {
                // 失败时，进行一些必要的错误处理，或维护信息补充，此处省略。
                // 常见失败原因：env不是有效的Node-API执行上下文（如：env参数为nullptr）
          }
       }
       ~MyCriticalScope()
       {
          Close();
       }
       inline void Close()
       {
          if (scope\_ == nullptr)
          {
                return;
          }
          // 在析构函数中，关闭临界区作用域
          if (napi\_close\_critical\_scope(env\_, scope\_) != napi\_ok)
          {
                // 失败时，进行一些必要的错误处理，或维护信息补充，此处省略。
                // 常见失败原因：
                // 1. 重复关闭临界区作用域。
                // 2. env不是有效的Node-API执行上下文（如：空指针）。
                // 3. scope不是有效的临界区作用域句柄（如：空指针）。
          }
          scope\_ = nullptr;
       }
    };
    
    // 二次封装的方法，用于在获取ArkTS字符串底层缓冲区失败时，回落到拷贝
    static std::vector<char16\_t> GetValueStringUtf16(napi\_env env, napi\_value value)
    {
       size\_t strLength{};
       if (napi\_get\_value\_string\_utf16(env, value, nullptr, 0, &strLength) != napi\_ok) {
          return {};
       }
       /\* Node-API接口要求缓冲区长度大于字符串内容长度，用于写入c字符串结束标记。
          因此，需要获取完整字符串内容时，缓冲区大小应为字符串长度 + 1。 \*/
       std::vector<char16\_t> result(strLength + 1);
       if (napi\_get\_value\_string\_utf16(env, value, result.data(), result.size(), &strLength) != napi\_ok) {
          return {};
       }
       return result;
    }
    
    static napi\_value NAPI\_Global\_getBufferStringUtf16(napi\_env env, napi\_callback\_info info)
    {
       napi\_value args\[1\]{};
       size\_t argc = 1;
       napi\_get\_cb\_info(env, info, &argc, args, /\* thisVar \*/ nullptr, /\* data \*/ nullptr);
       // 传入参数小于要求的最低参数数量
       if (argc < 1) {
          return nullptr;
       }
       napi\_valuetype argType;
    
       // 传入参数类型不是字符串
       if (napi\_typeof(env, args\[0\], &argType) != napi\_ok || argType != napi\_string) {
          return nullptr;
       }
    
       uint32\_t returnCode = 0;
       {
          \[\[maybe\_unused\]\] MyCriticalScope scope(env);
          size\_t bufSize{};
          const char16\_t \*buf{};
          std::vector<char16\_t> copied{}; // 预留，用以获取缓冲区失败时回落
          std::u16string\_view str;
    
          if (napi\_get\_buffer\_string\_utf16\_in\_critical\_scope(env, args\[0\], &buf, &bufSize) == napi\_ok)
          {
                str = std::u16string\_view(buf, bufSize);
          } else {
                scope.Close();
                copied = GetValueStringUtf16(env, args\[0\]);
                str = std::u16string\_view(copied.data(), copied.size());
                returnCode |= (1 << 1);
          }
    
          // do something with str
          if (str == u"测试字符串") {
                returnCode |= 1;
          }
       }
    
       napi\_value returnResult{};
       napi\_create\_int32(env, returnCode, &returnResult);
       return returnResult;
    }
    
    // 模块注册
    EXTERN\_C\_START
    static napi\_value Init(napi\_env env, napi\_value exports)
    {
       std::vector<napi\_property\_descriptor> desc{{"getBufferStringUtf16", nullptr, NAPI\_Global\_getBufferStringUtf16,
                                                    nullptr, nullptr, nullptr, napi\_default, nullptr}};
       napi\_define\_properties(env, exports, desc.size(), desc.data());
       return exports;
    }
    EXTERN\_C\_END
    
    static napi\_module demoModule = {
       .nm\_version = 1,
       .nm\_flags = 0,
       .nm\_filename = nullptr,
       .nm\_register\_func = Init,
       .nm\_modname = "entry",
       .nm\_priv = ((void \*)0),
       .reserved = {0},
    };
    
    extern "C" \_\_attribute\_\_((constructor)) void RegisterEntryModule(void)
    {
       napi\_module\_register(&demoModule);
    }
    
*   接口声明
    
    // index.d.ts
    export const getBufferStringUtf16: (str: string) => number;
    
*   ArkTS代码示例
    
    // index.ets
    import testNapi from "libentry.so"
    
    const makeTest = (str: string) => {
       console.info(\`status code of get buffer on "${str}": ${testNapi.getBufferStringUtf16(str)}\`);
    }
    
    makeTest("hello world"); // 预期结果: 2或0
    makeTest("你好");        // 预期结果: 0或2
    makeTest("测试字符串");   // 预期结果: 1或3