1

I'm using the winapi to grab a list of the current processes running on the system, here's my code:

use winapi::um::tlhelp32::{Process32Next, Process32First, CreateToolhelp32Snapshot, TH32CS_SNAPPROCESS, PROCESSENTRY32};
use winapi::um::winnt::HANDLE;
use winapi::um::handleapi::CloseHandle;
use std::mem::size_of;

...

fn get_processes() {
    let h_process_snap: HANDLE;
    // really, rust?
    let mut pe32 = &mut PROCESSENTRY32{
        dwSize: 0,
        cntUsage: 0,
        th32ProcessID: 0,
        th32DefaultHeapID: 0,
        th32ModuleID: 0,
        cntThreads: 0,
        th32ParentProcessID: 0,
        pcPriClassBase: 0,
        dwFlags: 0,
        szExeFile: [0; 260],
    };

    unsafe {
        h_process_snap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    }

    pe32.dwSize = size_of::<PROCESSENTRY32>() as u32;

    unsafe {
        if Process32First(h_process_snap, pe32) == 0 {
            CloseHandle(h_process_snap);
            println!("can't get a process snapshot");
            // TODO: return
        }

        while Process32Next(h_process_snap, pe32) != 0 {
            println!("{:?}", pe32.szExeFile);
        }
    }
}

...

Now I'm trying to print the actual name of the process, in C++, this can be done using cout or wcout.

When I use println!("{:?}", pe32.szExeFile);, this is what I get:

[115, 117, 112, 101, 114, 102, 52, 45, 114, 117, 115, 116, 46, 101, 120, 101, 0, 116, 46, 101, 120, 101, 0, 98, 108, 101, 83, 104, 101, 108, 108, 46, 69, 120, 112, 101, 114, 105, 101, 110, 99, 101, 115, 46, 84, 101, 120, 116, 73, 110, 112, 117, 116, 46, 73, 110, 112, 117, 116, 65, 112, 112, 46, 101, 120, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

I don't really understand how to work with this, how can I print the pe32.szExeFile as a Unicode string in rust?

see also: https://docs.rs/winapi/0.3.6/winapi/um/tlhelp32/struct.PROCESSENTRY32.html

Stef
  • 185
  • 4
  • 15
  • 2
    Use the wide-character version and construct an `OsString`. If you need to display the entry choose the lossy conversion to UTF-8. You are dealing with path names that aren't under your control so don't expect valid Unicode. – IInspectable Sep 12 '21 at 00:55
  • @IInspectable Thanks for your answer. I've read up on `OsString`, and found the [function](https://doc.rust-lang.org/std/ffi/struct.OsString.html#method.to_string_lossy) you are referring to. I'm just having trouble converting the `array [i8; 260]` that `pe32.szExeFile` returns into an OsString. I can use `OsString::from();` for strings, but I don't understand how to use a [WideChar](https://docs.rs/widestring/0.4.3/widestring/type.WideChar.html) in this context. Could you elaborate? – Stef Sep 12 '21 at 10:18
  • 1
    Call the explicit Unicode versions (e.g. [Process32FirstW](https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-process32firstw) instead of `Process32First`). That'll populate `u16` arrays (rather than `u8`), which can be passed into [from_wide](https://doc.rust-lang.org/std/os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide) to construct an `OsString`. Rustc conveniently compiles .natvis visualizers into the PDB's, and `OsString` objects display properly in a debugger that understands PDB's and .natvis files (such as Visual Studio or WinDbg). – IInspectable Sep 12 '21 at 12:35
  • 1
    That said, Rust and Windows are probably not ever going to be best friends, unfortunately. Pretty much every call into system APIs is going to be more or less tedious. Using the [windows crate](https://crates.io/crates/windows) rather than the [winapi crate](https://crates.io/crates/winapi) makes this a bit less tedious, though not much. – IInspectable Sep 12 '21 at 12:39
  • @IInspectable Thanks for elaborating! The Process32FirstW and from_wide fixed my issues. – Stef Sep 12 '21 at 17:04

1 Answers1

0

Thanks to @IInspectable, I used the explicit Unicode versions, e.g. Process32FirstW, and from_wide to print the values in readable format:

let os_string = OsString::from_wide(&pe32.szExeFile[..]);
// ExeFile names have a lot of trailing 0's, remove them...
let exe_files: String = os_string.into_string().unwrap().replace("\u{0}", "");
println!("{:?}", exe_files);
Stef
  • 185
  • 4
  • 15