Best way to read/write Windows UTF-16 strings

When accessing DLL functions on Windows I need to be able to read Windows UTF-16 strings they return and to pass in the same kind of strings.

For passing a string into a DLL I'm using this (which is something I got off the internet -- possibly this forum):

pub type Wchar = u16;
pub fn win16_for_str(s: &str) -> Vec<Wchar> {
    OsStr::new(s).encode_wide().chain(iter::once(0)).collect()
}

To use this I do let arg = win16_for_str("text"); let reply = win_func(arg.as_ptr());

But when I get a string returned from Windows (i.e., as a *const u16) I made my own (although based on ideas I found online). Is this a sane and reasonable function? BTW I want to get a String back no matter what.

pub fn str_for_pwin16(p: *const Wchar) -> String {
    if p.is_null() {
        return String::new();
    }
    unsafe {
        let mut size = 0;
        while size < MAX_TEXT_LEN { // e.g., 65_000, 100_000, ...
            if *p.offset(size) == 0 {
                break;
            }
            size += 1;
        }
        size += 1;
        let slice = slice::from_raw_parts(p, size as usize);
        let result = OsString::from_wide(slice).into_string();
        if result.is_ok() {
            return result.unwrap();
        }
        return result.unwrap_err().to_string_lossy().to_string();
    }
}

Thanks.

1 Like

I'm not experienced with Windows, but I'd hope that OsStr and OsString would meet your needs.

I suggest to use https://crates.io/crates/widestring crate to make your work with utf-16 and windows more simple.

2 Likes

Thanks, I've now switched to using that crate!

another crate https://github.com/lifthrasiir/rust-encoding

I prefer to keep things simple by using simple ToWide and FromWide traits that add convenient methods to all sorts of stringy types.

https://github.com/retep998/wio-rs/blob/master/src/wide.rs

1 Like