Windows-rs WlanGetProfile got 0x00000490

#[inline]
fn width_slice_to_str(src: &[u16]) -> String {
    let position = src.iter().position(|&x| x == 0).unwrap_or(src.len());
    String::from_utf16_lossy(
        &src[..position]
    )
}

    #[test]
    fn test_get_profile() {
        use windows::{
            core::{Error, HRESULT},
            Win32::NetworkManagement::WiFi::*,
            Win32::Foundation::*,
        };

        let mut nego_ver = 0;
        let mut handle = HANDLE::default();
        
        let ret = unsafe { WlanOpenHandle(WLAN_API_VERSION_2_0, None, &mut nego_ver, &mut handle) };
        if ret != ERROR_SUCCESS.0 {
            panic!("WlanOpenHandle failed: {}", Error::from(HRESULT(ret as i32)));
        }

        let mut p_ifaces: *mut WLAN_INTERFACE_INFO_LIST = std::ptr::null_mut();
        let ret = unsafe { WlanEnumInterfaces(handle, None, &mut p_ifaces) };
        if ret != ERROR_SUCCESS.0 || p_ifaces.is_null() {
            unsafe { WlanFreeMemory(p_ifaces as _); }
            panic!("WlanEnumInterfaces failed: {}", Error::from(HRESULT(ret as i32)));
        }

        let list = unsafe { &*p_ifaces };
        let ifaces = unsafe {
            std::slice::from_raw_parts(
                &list.InterfaceInfo[0],
                list.dwNumberOfItems as _,
            )
        }
            .to_vec();
        unsafe { WlanFreeMemory(p_ifaces as _); }
        let guid = ifaces.first()
            .unwrap()
            .InterfaceGuid;

        let mut p_profiles: *mut WLAN_PROFILE_INFO_LIST = std::ptr::null_mut();
        let ret = unsafe {
            WlanGetProfileList(handle, &guid, None, &mut p_profiles)
        };
        if ret != ERROR_SUCCESS.0 || p_profiles.is_null() {
            unsafe { WlanFreeMemory(p_profiles as _); }
            panic!("WlanEnumInterfaces failed: {}", Error::from(HRESULT(ret as i32)));
        }

        let list = unsafe { &*p_profiles };
        let profiles = unsafe {
            std::slice::from_raw_parts(
                &list.ProfileInfo[0],
                list.dwNumberOfItems as _
            )
        }
            .iter()
            .map(|info| {
                let result = width_slice_to_str(&info.strProfileName);
                result
            })
            .collect::<Vec<_>>();
        unsafe { WlanFreeMemory(p_profiles as _); }

        for ssid in profiles {
            let name = OsString::from(&ssid)
                .encode_wide()
                .collect::<Vec<_>>();
            let mut xml = PWSTR::default();
            let ret: u32 = unsafe {
                WlanGetProfile(
                    handle,
                    &guid,
                    PCWSTR(name.as_ptr()),
                    None,
                    &mut xml,
                    None,
                    None,
                )
            };

            if ret == ERROR_SUCCESS.0 {
                match unsafe {
                    xml.to_string()
                } {
                    Ok(_) => println!("Got profile XML: {}", ssid),
                    Err(_) => println!("Failed to convert XML to string: {}", ssid),
                }
            }
            else {
                println!("WlanGetProfile failed {} for {}", Error::from(HRESULT(ret as i32)), ssid);
            }
        }
    }

When I execute the test, sometimes the output is could't find the element (0x00000490).

You're not appending a null character to name, so it will randomly have junk that may or may not terminate the string.

It's actually really annoying how much of a pain it is to get a valid PCWSTR in Rust...

2 Likes