PdhAddCounterW - 在宏调用中没有规则期望这个标记

问题描述 投票:0回答:1

我正在编写一个程序来收集性能计数器。该程序是用

Rust
编写的,并使用
windows
crate.

以下是代码的相关部分。

let mut query = 0;
PdhOpenQueryW(None, 0, &mut query);
let query_path = CString::new("\\Processor(0)\\% Processor Time");
let mut counter = 0;
PdhAddCounterW(
    query,
    w!(query_path.as_ptr()),
    0,
    &mut counter,
);

编译器消息是:

error: no rules expected the token `query_path`
  --> src\main.rs:12:16
   |
12 |             w!(query_path.as_ptr()),
   |                ^^^^^^^^^^ no rules expected this token in macro call
   |
note: while trying to match meta-variable `$s:literal`
  --> C:\Users\T9SAU2\.cargo\registry\src\github.com-1ecc6299db9ec823\windows-0.48.0\src\core\strings\literals.rs:12:6

我想解释一下我对Rust中

String
的分析和理解,请让我知道我哪里错了。

当我导航到

C:\Users\T9SAU2\.cargo\registry\src\github.com-1ecc6299db9ec823\windows-0.48.0\src\core\strings\literals.rs:12:6
时,相关的代码和注释是-

/// A literal UTF-16 wide string with a trailing null terminator.
#[macro_export]
macro_rules! w {
    ($s:literal) => {{
        const INPUT: &[u8] = $s.as_bytes();
        const OUTPUT_LEN: usize = $crate::core::utf16_len(INPUT) + 1;

输入应该是一个 UTF-16 空终止字符串。

PdhAddCounterW()
的函数签名是:

pub unsafe fn PdhAddCounterW<P0>(
    hquery: isize,
    szfullcounterpath: P0,
    dwuserdata: usize,
    phcounter: *mut isize
) -> u32
where
    P0: IntoParam<PCWSTR>,

链接-https://microsoft.github.io/windows-docs-rs/doc/windows/Win32/System/Performance/fn.PdhAddCounterW.html

参数

szfullcounterpath
的类型是
IntoParam\<PCWSTR\>
PCWSTR
定义为:

pub struct PCWSTR(pub *const u16);

指向 16 位 Unicode 字符的以 null 结尾的常量字符串的指针。

A

String
在 Rust 中不是空终止的并且是 UTF-8。基本定义是:

pub struct String {
    vec: Vec<u8>,
}

基本上,一个无符号的 8 位向量。这行不通。

参数

szfullcounterpath
应该是指向
u16
的空终止向量的指针。

str
是另一种类型,是有效的字符串切片。这种类型有一个有趣的功能
encode_utf16
。另一个 StackOverflow 帖子 证实了这一点。

但是,当我使用下面的时候,我仍然得到同样的错误:

let mut v: Vec<u16> = query_path.encode_utf16().collect();
v.push(0);

我参考了博客Rust #8: Strings。从这里,我了解了

OsString
CString

OsString
上的 Rust 文档指出:

在 Windows 上,字符串通常是非零 16 位值的任意序列,在有效时被解释为 UTF-16。
...
...在 Windows 上,正如刚刚讨论的那样,字符串是基于 16 位值的,字符串实际上也存储为 8 位值序列,编码为 UTF-8 的不太严格的变体。这对于理解处理容量和长度值时很有用。

Windows 上的

OsString
是UTF-16,但没有提及任何有关空终止的信息。此外,它存储为
u8
的序列,因此我不确定是否可以在不将其操作为
u16
并添加空终止符的情况下使用它。

CString
是一种表示拥有的、C 兼容的、以 null 结尾的字符串的类型,中间没有
nul
字节。它是一个 Box 类型,因此是一个智能指针,但是一个
u8
的数组。智能指针可以转换为原始指针,但仍然需要将其更改为
u16
。如果我必须使用它,我需要遍历框类型并使用移位从
u8
转换为
u16
.

我相信最简单的选择是字符串切片,但我收到同样的错误。

我错过了什么?

windows winapi rust performancecounter
1个回答
2
投票

w!
宏只能应用于字符串文字。因此,您的代码应为:

// ...
let mut counter = 0;
PdhAddCounterW(
    query,
    w!("\\Processor(0)\\% Processor Time"),
    0,
    &mut counter,
);

如果您确实需要在运行时构造一个 UTF-16 编码的字符串,因此不能使用

w!
宏,有几个选项。由于 Rust 不提供使用 UTF-16 编码的字符串类型,因此它们都遵循几乎相同的模式:

  • 构造字符串(使用 Rust 的原生 UTF-8 编码)
  • 从 UTF-8 转码到 UTF-16
  • (可选)附加一个零终止符

虽然您可以手动执行此操作,例如

let utf16 = text.encode_utf16().chain(once(0)).collect::<Vec<_>>();

使用

windows
箱子提供的工具要方便得多。所有字符串处理都以
HSTRING
类型为中心,它可以从几乎任何 Rust 字符串类型构造,也可以传递给期望
IntoParam<PCWSTR>
.

的函数

如果

query_path
是在运行时构造的,你可以把你的代码改成read

let mut query = 0;
PdhOpenQueryW(None, 0, &mut query);
let query_path = String::from("\\Processor(0)\\% Processor Time");
let mut counter = 0;
PdhAddCounterW(
    query,
    &HSTRING::from(&query_path),
    0,
    &mut counter,
);

impl From
的所有
HSTRING
从UTF-8转换为UTF-16,并附加一个零终止符。

© www.soinside.com 2019 - 2024. All rights reserved.