Repository: serialport/serialport-rs (language: rust)

Issue:
On the USB device running Windows, the product name of the non-UTF-8 device is garbled
- OS: win10(Code page 936)

**Note: It may be possible to return bytes instead of strings**

```rust
    let serial_list = serialport::available_ports();

    match serial_list {
        Ok(serial_list) => {
            println!("{:?}", serial_list.len());
            for s in serial_list {
                println!(
                    "{} {}",
                    s.port_name,
                    match s.port_type {
                        // serialport::SerialPortType::UsbPort(usb_info) => usb_info.product.unwrap(),
                        serialport::SerialPortType::UsbPort(usb_info) => {
                            format!("{:?}", usb_info.product.unwrap())
                        }
                        serialport::SerialPortType::PciPort => String::from("PciPort"),
                        serialport::SerialPortType::BluetoothPort => String::from("BluetoothPort"),
                        serialport::SerialPortType::Unknown => String::from("Unknown"),
                    },
                );
            }
        }
        Err(e) => {
            println!("{:?}", e);
            return;
        }
    }
```

```
4
COM27 "USB �����豸 (COM27)"
COM11 "USB �����豸 (COM11)"
COM12 "JLink CDC UART Port (COM12)"
COM10 "USB-SERIAL CH340 (COM10)"
```

![image](https://user-images.githubusercontent.com/12112251/185349835-98e0d321-a555-46a0-8553-8b83ee8f0ce9.png)



Discussion / hints:

Fix patch:
diff --git a/src/posix/tty.rs b/src/posix/tty.rs
index f97a065b..4d1a225e 100644
--- a/src/posix/tty.rs
+++ b/src/posix/tty.rs
@@ -79,7 +79,7 @@ struct OwnedFd(RawFd);
 
 impl Drop for OwnedFd {
     fn drop(&mut self) {
-        let _ = close(self.0);
+        close(self.0);
     }
 }
 
@@ -208,12 +208,9 @@ impl TTYPort {
             ioctl::tiocnxcl(self.fd)
         };
 
-        if let Err(err) = setting_result {
-            Err(err)
-        } else {
-            self.exclusive = exclusive;
-            Ok(())
-        }
+        setting_result?;
+        self.exclusive = exclusive;
+        Ok(())
     }
 
     fn set_pin(&mut self, pin: ioctl::SerialLines, level: bool) -> Result<()> {
diff --git a/src/windows/enumerate.rs b/src/windows/enumerate.rs
index 84c44169..20057858 100644
--- a/src/windows/enumerate.rs
+++ b/src/windows/enumerate.rs
@@ -4,7 +4,6 @@ use std::{mem, ptr};
 use regex::Regex;
 use winapi::shared::guiddef::*;
 use winapi::shared::minwindef::*;
-use winapi::shared::ntdef::CHAR;
 use winapi::shared::winerror::*;
 use winapi::um::cguid::GUID_NULL;
 use winapi::um::errhandlingapi::GetLastError;
@@ -220,29 +219,28 @@ impl PortDevice {
                 KEY_READ,
             )
         };
-        let mut port_name_buffer = [0u8; MAX_PATH];
+
+        let mut port_name_buffer = [0u16; MAX_PATH];
         let mut port_name_len = port_name_buffer.len() as DWORD;
-        let value_name = CString::new("PortName").unwrap();
+        let value_name: Vec<u16> = "PortName".encode_utf16().chain(Some(0)).collect();
+
         unsafe {
-            RegQueryValueExA(
+            RegQueryValueExW(
                 hkey,
                 value_name.as_ptr(),
                 ptr::null_mut(),
                 ptr::null_mut(),
-                port_name_buffer.as_mut_ptr(),
+                port_name_buffer.as_mut_ptr() as *mut u8,
                 &mut port_name_len,
             )
         };
         unsafe { RegCloseKey(hkey) };
 
-        let mut port_name = &port_name_buffer[0..port_name_len as usize];
-
-        // Strip any nul bytes from the end of the buffer
-        while port_name.last().map_or(false, |c| *c == b'\0') {
-            port_name = &port_name[..port_name.len() - 1];
-        }
+        let port_name = &port_name_buffer[0..port_name_len as usize];
 
-        String::from_utf8_lossy(port_name).into_owned()
+        String::from_utf16_lossy(port_name)
+            .trim_end_matches(0 as char)
+            .to_string()
     }
 
     // Determines the port_type for this device, and if it's a USB port populate the various fields.
@@ -260,30 +258,34 @@ impl PortDevice {
     // Retrieves a device property and returns it, if it exists. Returns None if the property
     // doesn't exist.
     fn property(&mut self, property_id: DWORD) -> Option<String> {
-        let mut result_buf: [CHAR; MAX_PATH] = [0; MAX_PATH];
+        let mut property_buf = [0u16; MAX_PATH];
+
         let res = unsafe {
-            SetupDiGetDeviceRegistryPropertyA(
+            SetupDiGetDeviceRegistryPropertyW(
                 self.hdi,
                 &mut self.devinfo_data,
                 property_id,
                 ptr::null_mut(),
-                result_buf.as_mut_ptr() as PBYTE,
-                (result_buf.len() - 1) as DWORD,
+                property_buf.as_mut_ptr() as PBYTE,
+                property_buf.len() as DWORD,
                 ptr::null_mut(),
             )
         };
+
         if res == FALSE {
             if unsafe { GetLastError() } != ERROR_INSUFFICIENT_BUFFER {
                 return None;
             }
         }
-        let end_of_buffer = result_buf.len() - 1;
-        result_buf[end_of_buffer] = 0;
-        Some(unsafe {
-            CStr::from_ptr(result_buf.as_ptr())
-                .to_string_lossy()
-                .into_owned()
-        })
+
+        // Using the unicode version of 'SetupDiGetDeviceRegistryProperty' seems to report the
+        // entire mfg registry string. This typically includes some driver information that we should discard.
+        // Example string: 'FTDI5.inf,%ftdi%;FTDI'
+        String::from_utf16_lossy(&property_buf)
+            .trim_end_matches(0 as char)
+            .split(';')
+            .last()
+            .map(str::to_string)
     }
 }
 


Test patch: