1#[cfg(all(feature = "winapi", target_os = "windows"))]
2use windows::Win32::{
3 Foundation::CloseHandle,
4 System::Diagnostics::ToolHelp::{
5 CreateToolhelp32Snapshot, Process32FirstW, Process32NextW, PROCESSENTRY32W,
6 TH32CS_SNAPPROCESS,
7 },
8};
9
10#[cfg(all(feature = "winapi", target_os = "windows"))]
12pub fn get_process_id_by_name(name: &str) -> Option<u32> {
13 unsafe {
14 let h_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
15 let Ok(h_snapshot) = h_snapshot else {
16 return None;
17 };
18 let mut pe = PROCESSENTRY32W {
19 dwSize: std::mem::size_of::<PROCESSENTRY32W>() as u32,
20 ..Default::default()
21 };
22 let ret = Process32FirstW(h_snapshot, &mut pe);
23 loop {
24 if ret.is_err() {
25 break;
26 }
27 let end_pos = pe.szExeFile.iter().position(|p| *p == 0);
28 let Some(end_pos) = end_pos else {
29 break;
30 };
31 let process_name = String::from_utf16_lossy(&pe.szExeFile[0..end_pos]);
32 if process_name == name {
33 let _ = CloseHandle(h_snapshot);
34 return Some(pe.th32ProcessID);
35 }
36 let ret = Process32NextW(h_snapshot, &mut pe);
37 if ret.is_err() {
38 break;
39 }
40 }
41 let _ = CloseHandle(h_snapshot);
42 }
43 None
44}
45
46#[cfg(all(feature = "winapi", target_os = "windows"))]
48#[derive(Debug)]
49pub enum ServStatus {
50 Uninstalled,
51 Running,
52 Paused,
53 Stoped,
54 StartPending,
55 StopPending,
56 PausePending,
57 ContinuePending,
58 Unknow,
59}
60
61#[cfg(all(feature = "winapi", target_os = "windows"))]
63pub fn sc_query(service_name: &str) -> Result<ServStatus, windows::core::Error> {
64 use windows::{
65 core::PWSTR,
66 Win32::System::Services::{
67 CloseServiceHandle, OpenSCManagerW, OpenServiceW, QueryServiceStatus,
68 SC_MANAGER_CONNECT, SERVICE_CONTINUE_PENDING, SERVICE_PAUSED, SERVICE_PAUSE_PENDING,
69 SERVICE_QUERY_STATUS, SERVICE_RUNNING, SERVICE_START_PENDING, SERVICE_STATUS,
70 SERVICE_STOPPED, SERVICE_STOP_PENDING,
71 },
72 };
73
74 unsafe {
75 let h_sc = OpenSCManagerW(None, None, SC_MANAGER_CONNECT)?;
76 let mut service_name: Vec<u16> = service_name.encode_utf16().chain([0]).collect();
77 let service_name = PWSTR::from_raw(service_name.as_mut_ptr());
78
79 let h_service = OpenServiceW(h_sc, service_name, SERVICE_QUERY_STATUS);
80 let Ok(h_service) = h_service else {
81 let err = h_service.unwrap_err();
82 if err.code().0 == 0x80070424u32 as i32 {
83 return Ok(ServStatus::Uninstalled);
84 }
85 return Err(err);
86 };
87 let mut s_status = SERVICE_STATUS::default();
88 QueryServiceStatus(h_service, &mut s_status)?;
89
90 let _ = CloseServiceHandle(h_service);
91 let _ = CloseServiceHandle(h_sc);
92
93 let status = match s_status.dwCurrentState {
94 SERVICE_RUNNING => ServStatus::Running,
95 SERVICE_PAUSED => ServStatus::Paused,
96 SERVICE_STOPPED => ServStatus::Stoped,
97 SERVICE_CONTINUE_PENDING => ServStatus::ContinuePending,
98 SERVICE_START_PENDING => ServStatus::StartPending,
99 SERVICE_PAUSE_PENDING => ServStatus::PausePending,
100 SERVICE_STOP_PENDING => ServStatus::StopPending,
101 _ => ServStatus::Unknow,
102 };
103 Ok(status)
104 }
105}
106
107#[cfg(all(feature = "winapi", target_os = "windows"))]
109pub fn runas(
110 exe_path: &str,
111 args: Option<Vec<String>>,
112 wait: bool,
113) -> Result<(), windows::core::Error> {
114 use windows::{
115 core::{w, PCWSTR},
116 Win32::{
117 System::{
118 Com::{
119 CoInitializeEx, CoUninitialize, COINIT_APARTMENTTHREADED,
120 COINIT_DISABLE_OLE1DDE,
121 },
122 Threading::{WaitForSingleObject, INFINITE},
123 },
124 UI::{
125 Shell::{
126 ShellExecuteExW, SEE_MASK_NOCLOSEPROCESS, SEE_MASK_UNICODE, SHELLEXECUTEINFOW,
127 },
128 WindowsAndMessaging::SW_SHOWNORMAL,
129 },
130 },
131 };
132
133 unsafe {
134 let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
136
137 let mut sei: SHELLEXECUTEINFOW = SHELLEXECUTEINFOW::default();
139 sei.cbSize = std::mem::size_of::<SHELLEXECUTEINFOW>() as u32;
140 sei.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_UNICODE;
141 sei.lpVerb = w!("runas");
142 sei.lpFile = PCWSTR::from_raw(w!("cmd.exe").as_ptr());
144 let shell_switch = "/C"; let script_path_quoted = format!("\"{}\"", exe_path);
149 let args_str = if let Some(args) = args {
151 args.into_iter()
152 .map(|arg| format!("\"{}\"", arg))
153 .collect::<Vec<_>>()
154 .join(" ")
155 } else {
156 String::new()
157 };
158
159 let params_str = format!("{} \"{} {}\"", shell_switch, script_path_quoted, args_str);
162
163 let mut params_w: Vec<u16> = params_str.encode_utf16().collect();
165 params_w.push(0);
166 sei.lpParameters = PCWSTR::from_raw(params_w.leak().as_mut_ptr());
167 sei.nShow = SW_SHOWNORMAL.0;
168
169 ShellExecuteExW(&mut sei)?;
170 if wait {
171 WaitForSingleObject(sei.hProcess, INFINITE);
173 }
174 CoUninitialize();
175 Ok(())
176 }
177}
178
179#[cfg(all(feature = "winapi", target_os = "windows"))]
180pub fn current_is_admin() -> Result<bool, windows::core::Error> {
181 use windows::Win32::{
182 Foundation::HANDLE,
183 Security::{GetTokenInformation, TokenElevation, TOKEN_ELEVATION, TOKEN_QUERY},
184 System::Threading::{GetCurrentProcess, OpenProcessToken},
185 };
186 unsafe {
187 let mut token_handle = HANDLE::default();
188 OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token_handle)?;
189 let mut token_info = TOKEN_ELEVATION::default();
190
191 let mut return_len = 0;
192 GetTokenInformation(
193 token_handle,
194 TokenElevation,
195 Some(&mut token_info as *mut _ as *mut std::ffi::c_void),
196 std::mem::size_of::<TOKEN_ELEVATION>() as u32,
197 &mut return_len,
198 )?;
199
200 CloseHandle(token_handle)?;
201
202 return Ok(token_info.TokenIsElevated == 1);
203 }
204}
205#[cfg(all(feature = "winapi", target_os = "windows"))]
207pub fn enable_virtual_terminal() -> Result<(), windows::core::Error> {
208 use windows::Win32::System::Console::{
209 GetConsoleMode, GetStdHandle, SetConsoleMode, CONSOLE_MODE,
210 ENABLE_VIRTUAL_TERMINAL_PROCESSING, STD_OUTPUT_HANDLE,
211 };
212 unsafe {
213 let handle = GetStdHandle(STD_OUTPUT_HANDLE).unwrap();
214 let mut mode = CONSOLE_MODE::default();
215 let _ = GetConsoleMode(handle, &mut mode)?;
216 let _ = SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)?;
217 Ok(())
218 }
219}
220
221#[cfg(all(feature = "winapi", target_os = "windows"))]
223pub fn msi_install(path: &str, args: Option<&str>) -> Result<(), windows::core::Error> {
224 use windows::{
225 core::PCWSTR, Win32::System::ApplicationInstallationAndServicing::MsiInstallProductW,
226 };
227
228 let msi_path_wide: Vec<u16> = path.encode_utf16().chain([0]).collect();
229 let msi_args = if args.is_some() {
230 let args = args.unwrap();
231 let args: Vec<u16> = args.encode_utf16().chain([0]).collect();
232 args
233 } else {
234 Vec::new()
235 };
236
237 let msi_args = if msi_args.is_empty() {
238 PCWSTR::null()
239 } else {
240 PCWSTR::from_raw(msi_args.as_ptr())
241 };
242
243 let result = unsafe {
244 MsiInstallProductW(
245 PCWSTR(msi_path_wide.as_ptr()),
246 msi_args, )
248 };
249 if result != 0 {
250 return Err(windows::core::Error::from_win32());
251 }
252 Ok(())
253}
254
255#[cfg(all(feature = "winapi", target_os = "windows"))]
257pub fn msi_get_version(name: &str) -> Result<String, windows::core::Error> {
258 use windows::{
259 core::{HRESULT, PWSTR},
260 Win32::System::ApplicationInstallationAndServicing::{
261 MsiEnumProductsW, MsiGetProductInfoW, INSTALLPROPERTY_PRODUCTNAME,
262 INSTALLPROPERTY_VERSIONSTRING,
263 },
264 };
265
266 unsafe {
267 let mut prod_code: Vec<u16> = Vec::new();
268 prod_code.resize(0xff, 0);
269 let prod_code = PWSTR::from_raw(prod_code.as_mut_ptr());
270 let mut idx = 0;
271 let mut ret = MsiEnumProductsW(idx, prod_code);
272 loop {
273 if ret != 0 {
274 break;
275 }
276 idx += 1;
277 let mut buf: Vec<u16> = Vec::new();
278 buf.resize(0xff, 0);
279 let prod_name = PWSTR::from_raw(buf.as_mut_ptr());
280 let mut len = 0xff;
281 let name_ret = MsiGetProductInfoW(
282 prod_code,
283 INSTALLPROPERTY_PRODUCTNAME,
284 Some(prod_name),
285 Some(&mut len),
286 );
287 if name_ret != 0 {
288 continue;
289 }
290 let prod_name = prod_name.to_string().unwrap_or_default();
291 if prod_name == name {
292 let mut buf: Vec<u16> = Vec::new();
293 buf.resize(0xff, 0);
294 let buf = PWSTR::from_raw(buf.as_mut_ptr());
295 let mut len = 0xff;
296 let ret = MsiGetProductInfoW(
297 prod_code,
298 INSTALLPROPERTY_VERSIONSTRING,
299 Some(buf),
300 Some(&mut len),
301 );
302 if ret != 0 {
303 return Err(windows::core::Error::from_win32());
304 }
305 let version = buf.to_string().unwrap_or_default();
306 return Ok(version);
307 }
308 ret = MsiEnumProductsW(idx, prod_code);
309 }
310 Err(windows::core::Error::from_hresult(HRESULT::from_win32(1)))
311 }
312}
313
314#[test]
315#[cfg(all(feature = "winapi", target_os = "windows"))]
316fn test_get_process_id_by_name() {
317 let ret = get_process_id_by_name("Notepad.exe");
318 println!("{:?}", ret);
319}
320
321#[test]
322#[cfg(all(feature = "winapi", target_os = "windows"))]
323fn test_sc_query() {
324 let ret = sc_query("slmd");
325 println!("{:?}", ret);
326}