想写一个函数获取 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; |