想写一个函数获取 windows 某个进程的命令行
得到了 cmdline 变量,是一个 Vec<u16>,想直接通过 Ok(env.create_string_utf16(&cmdline)?) 这样返回,但是 [napi] 宏展开报错了
error[E0277]: the trait bound `Env: NapiValue` is not satisfied --> lib/addon/addon.rs:15:1 | 15 | #[napi] | ^^^^^^^ the trait `NapiValue` is not implemented for `Env` | = help: the following other types implement trait `NapiValue`: JsArrayBuffer JsTypedArray JsDataView JsBuffer Date JsFunction JsGlobal JsTimeout and 10 others = note: required for `Env` to implement `FromNapiValue` = note: this error originates in the attribute macro `napi` (in Nightly builds, run with -Z macro-backtrace for more info)
我的理解是不支持返回 JsString 这个类型?那怎么办?
下面这样写是可以的,但是效率不高,这里会把 utf-16 decode 成 utf-8, 然后 node.js 里面又要把 utf-8 转为 utf-16, 是没有必要的开销
pub fn get_process_cmdline (env: napi::Env, pid: u32) -> anyhow::Result<String> { ...
Ok(String::from_utf16_lossy(&cmdline));
}
use std::{ mem, ptr, mem::transmute, slice, ffi::c_void }; use napi_derive::napi; use napi::{ bindgen_prelude::Utf16String, JsString }; use anyhow::format_err; use windows::core::s; #[napi] pub fn get_process_cmdline (env: napi::Env, pid: u32) -> anyhow::Result<JsString> { use windows::{ Win32::{ System::{ Threading::{ OpenProcess, PROCESS_QUERY_INFORMATION, PROCESS_BASIC_INFORMATION, PROCESS_VM_READ, RTL_USER_PROCESS_PARAMETERS }, Diagnostics::Debug::ReadProcessMemory, },}, Wdk::System::Threading::{ NtQueryInformationProcess, ProcessBasicInformation } }; let handle = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid) }?; // https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess let mut pbi: PROCESS_BASIC_INFORMATION = Default::default(); let status = unsafe { NtQueryInformationProcess( handle, ProcessBasicInformation, &mut pbi as *mut _ as *mut c_void, mem::size_of_val(&pbi) as u32, ptr::null_mut())}?; // ReadProcessMemory(进程 handle, 要读取的内存地址, 输出 buffer, 要读取的字节数, 已读取的字节数 (可选, 传入指针)) // https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-readprocessmemory // 将 pbi.PebBaseAddress 读到 peb 中 let mut peb: RTL_USER_PROCESS_PARAMETERS = Default::default(); unsafe { ReadProcessMemory( handle, pbi.PebBaseAddress as *mut c_void, &mut peb as *mut _ as *mut c_void, mem::size_of_val(&peb), None) }?; let mut cmdline = vec![0u16; (peb.CommandLine.Length / 2) as usize]; unsafe { ReadProcessMemory( handle, peb.CommandLine.Buffer.as_ptr() as *mut c_void, cmdline.as_mut_ptr() as *mut _, peb.CommandLine.Length as usize, None) }?; // 这里会把 utf-16 decode 成 utf-8, 然后 node.js 里面又要把 utf-8 转为 utf-16, 是没有必要的开销 // Ok(String::from_utf16_lossy(&cmdline)); // 想这样直接 return utf16 string Ok(env.create_string_utf16(&cmdline)?) }
![]() | 1 PTLin 2023-09-15 09:34:54 +08:00 JsString 没实现 ToNapiValue 所以不能返回,Utf16String 转换也有开销,要是你想要无开销的可以自己实现个类型然后实现 ToNapiValue ,在里面调用 napi_create_string_utf16 |
![]() | 4 SHF OP 已解决,参数列表里类型不能写 env: napi::Env, 否则宏展开会报错,直接写 Env 就可以了,现在功能已经完美可用 ```rust #[napi] pub fn get_process_cmdline (env: Env, pid: u32) -> anyhow::Result<JsString> { ... Ok(env.create_string_utf16(&cmdline)?) } ``` |
![]() | 6 SHF OP 需要在文件前面提前导入 use napi::Env; |