nick_name/windows/
nick_name.rs

1use std::ffi::{CStr, OsStr};
2use std::os::windows::ffi::{OsStrExt, OsStringExt};
3use std::{
4    ffi::OsString,
5    fmt::{Debug, Formatter},
6};
7use winapi::shared::minwindef::DWORD;
8use winapi::shared::minwindef::MAKEWORD;
9use winapi::um::iptypes::MAX_HOSTNAME_LEN;
10use winapi::um::l2cmn::L2_PROFILE_MAX_NAME_LENGTH;
11#[cfg(not(miri))]
12use winapi::um::sysinfoapi::GetComputerNameExW;
13#[cfg(not(miri))]
14use winapi::um::sysinfoapi::{ComputerNamePhysicalDnsHostname, SetComputerNameExW};
15use winapi::um::winnt;
16pub struct NickName {}
17
18impl Debug for NickName {
19    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
20        f.debug_struct("NickName").finish()
21    }
22}
23
24impl NickName {
25    pub fn new() -> crate::Result<Self> {
26        Ok(Self {})
27    }
28
29    /// computer name change only on windows reboot
30    /// This is not show on settings
31    /// This is show on %COMPUTERNAME%
32    /// get NetBIOS name
33    /// This is just like get_a
34    pub fn get_w(&self) -> crate::Result<String> {
35        unsafe {
36            // バッファサイズを定義
37            let mut buffer: [winnt::WCHAR; L2_PROFILE_MAX_NAME_LENGTH + 1] =
38                [0; L2_PROFILE_MAX_NAME_LENGTH + 1];
39            let mut size: DWORD = buffer.len() as DWORD;
40
41            // GetComputerNameWを呼び出してコンピュータ名を取得
42            if winapi::um::winbase::GetComputerNameW(buffer.as_mut_ptr(), &mut size) != 0 {
43                // Null終端のWCHARバッファをOsStringに変換
44                let os_string = OsString::from_wide(&buffer[..(size as usize)]);
45
46                // OsStringをStringに変換
47                let computer_name = os_string.to_string_lossy();
48
49                Ok(computer_name.into())
50            } else {
51                Err(std::io::Error::last_os_error().into())
52            }
53        }
54    }
55
56    /// computer name change only on windows reboot
57    /// This is not show on settings
58    /// This is show on %COMPUTERNAME%
59    /// get NetBIOS name
60    /// This is just like get_w
61    pub fn get_a(&self) -> crate::Result<String> {
62        unsafe {
63            // バッファサイズを定義
64            let mut buffer: [winnt::CHAR; L2_PROFILE_MAX_NAME_LENGTH + 1] =
65                [0; L2_PROFILE_MAX_NAME_LENGTH + 1];
66            let mut size: DWORD = buffer.len() as DWORD;
67
68            // GetComputerNameAを呼び出してコンピュータ名を取得
69            if winapi::um::winbase::GetComputerNameA(buffer.as_mut_ptr(), &mut size) != 0 {
70                // Null終端のCHARバッファをOsStringに変換
71                let computer_name = String::from_utf8_lossy(std::slice::from_raw_parts(
72                    buffer.as_ptr() as *const u8,
73                    size as usize,
74                ));
75                Ok(computer_name.into())
76            } else {
77                Err(std::io::Error::last_os_error().into())
78            }
79        }
80    }
81
82    /// computer name change only on windows reboot
83    /// This is show on settings
84    /// This is show on %COMPUTERNAME%
85    /// DNS Host Name
86    pub fn get_hostname(&self) -> crate::Result<String> {
87        unsafe {
88            #[cfg_attr(miri, allow(unused_assignments))]
89            let mut size: DWORD = 0;
90
91            // DNS では長い名前が許可されるため、
92            // サイズを取得する。
93            // 必ず失敗する
94            #[cfg(not(miri))]
95            let result = GetComputerNameExW(
96                ComputerNamePhysicalDnsHostname,
97                std::ptr::null_mut(),
98                &mut size,
99            );
100            #[cfg(miri)]
101            let result = 0;
102            #[cfg(miri)]
103            {
104                size = 8;
105            }
106            if result != 0 {
107                return Err(crate::Error::RuntimeError("unreachable".into()));
108            }
109
110            // バッファサイズを定義
111            let mut buffer = Vec::with_capacity(size as usize);
112            let _remaining = buffer.spare_capacity_mut();
113            buffer.set_len(size as usize);
114
115            // GetComputerNameExWを呼び出してコンピュータ名を取得
116            #[cfg(not(miri))]
117            let ret = GetComputerNameExW(
118                ComputerNamePhysicalDnsHostname,
119                buffer.as_mut_ptr(),
120                &mut size,
121            );
122            #[cfg(miri)]
123            let ret = 1;
124            #[cfg(miri)]
125            {
126                buffer = vec![104, 111, 115, 116, 110, 97, 109, 101];
127                size = 8;
128            }
129            if ret != 0 {
130                // Null終端のWCHARバッファをOsStringに変換
131                let os_string = OsString::from_wide(&buffer[..(size as usize)]);
132
133                // OsStringをStringに変換
134                let computer_name = os_string.to_string_lossy();
135
136                Ok(computer_name.into())
137            } else {
138                Err(std::io::Error::last_os_error().into())
139            }
140        }
141    }
142
143    /// computer name change only on windows reboot
144    /// This is show on settings pc name
145    /// This is show on %COMPUTERNAME%
146    /// but not official fn
147    pub fn get_hostname_non_official(&self) -> crate::Result<String> {
148        unsafe {
149            // 初期化
150            let mut wsadata: winapi::um::winsock2::WSADATA = std::mem::zeroed();
151            if winapi::um::winsock2::WSAStartup(MAKEWORD(2, 2), &mut wsadata) != 0 {
152                return Err(std::io::Error::last_os_error().into());
153            }
154
155            // ホスト名取得
156            let mut buffer: [i8; MAX_HOSTNAME_LEN] = std::mem::zeroed();
157            if winapi::um::winsock2::gethostname(buffer.as_mut_ptr(), buffer.len() as i32) != 0 {
158                winapi::um::winsock2::WSACleanup();
159                return Err(std::io::Error::last_os_error().into());
160            }
161
162            // クリーンアップ
163            winapi::um::winsock2::WSACleanup();
164
165            // i8からStringに変換
166            let c_str = CStr::from_ptr(buffer.as_ptr());
167            let hostname = c_str.to_string_lossy().into_owned();
168            Ok(hostname)
169        }
170    }
171
172    /// computer name change only on windows reboot
173    pub fn get(&self) -> crate::Result<String> {
174        self.get_hostname()
175    }
176
177    /// computer name change only on windows reboot
178    /// This is not show on settings
179    /// This is show on %COMPUTERNAME%
180    /// set NetBIOS name
181    /// This is just like set_a
182    pub fn set_w<S: Into<String>>(&self, nickname: S) -> crate::Result<()> {
183        let nickname: String = nickname.into();
184        unsafe {
185            let mut buffer = OsStr::new(&nickname).encode_wide().collect::<Vec<_>>();
186            buffer.push(0);
187
188            // GetComputerNameWを呼び出してコンピュータ名を取得
189            if winapi::um::sysinfoapi::SetComputerNameW(buffer.as_ptr()) != 0 {
190                Ok(())
191            } else {
192                Err(std::io::Error::last_os_error().into())
193            }
194        }
195    }
196
197    /// computer name change only on windows reboot
198    /// This is not show on settings
199    /// This is show on %COMPUTERNAME%
200    /// set NetBIOS name
201    /// This is just like set_w
202    pub fn set_a<S: Into<String>>(&self, nickname: S) -> crate::Result<()> {
203        let nickname: String = nickname.into();
204        unsafe {
205            // Convert OsStr to a String and obtain a slice of UTF-16 code units
206            let cow = OsStr::new(&nickname).to_string_lossy();
207            let mut buffer = cow.encode_utf16().map(|u| u as i8).collect::<Vec<i8>>();
208            buffer.push(0);
209
210            // SetComputerNameAを呼び出してコンピュータ名を設定
211            if winapi::um::sysinfoapi::SetComputerNameA(buffer.as_ptr()) != 0 {
212                Ok(())
213            } else {
214                Err(std::io::Error::last_os_error().into())
215            }
216        }
217    }
218
219    /// computer name change only on windows reboot
220    /// This is show on settings
221    /// This is show on %COMPUTERNAME%
222    /// DNS Host Name
223    pub fn set_hostname<S: Into<String>>(&self, nickname: S) -> crate::Result<()> {
224        let nickname: String = nickname.into();
225
226        let mut buffer = OsStr::new(&nickname).encode_wide().collect::<Vec<_>>();
227        buffer.push(0);
228
229        // SetComputerNameExWを呼び出してコンピュータ名を設定
230        #[cfg(not(miri))]
231        if unsafe { SetComputerNameExW(ComputerNamePhysicalDnsHostname, buffer.as_ptr()) } != 0 {
232            Ok(())
233        } else {
234            Err(std::io::Error::last_os_error().into())
235        }
236
237        #[cfg(miri)]
238        Ok(())
239    }
240
241    /// computer name change only on windows reboot
242    /// change windows and wsl name
243    pub fn set<S: Into<String>>(&self, nickname: S) -> crate::Result<()> {
244        self.set_hostname(nickname)
245    }
246}