winsafe\kernel/funcs.rs
1#![allow(non_snake_case)]
2
3use crate::co;
4use crate::decl::*;
5use crate::guard::*;
6use crate::kernel::{ffi, privs::*};
7
8/// [`CopyFile`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-copyfilew)
9/// function.
10///
11/// # Related functions
12///
13/// * [`DeleteFile`](crate::DeleteFile)
14/// * [`MoveFile`](crate::MoveFile)
15/// * [`MoveFileEx`](crate::MoveFileEx)
16/// * [`ReplaceFile`](crate::ReplaceFile)
17pub fn CopyFile(existing_file: &str, new_file: &str, fail_if_exists: bool) -> SysResult<()> {
18 bool_to_sysresult(unsafe {
19 ffi::CopyFileW(
20 WString::from_str(existing_file).as_ptr(),
21 WString::from_str(new_file).as_ptr(),
22 fail_if_exists as _,
23 )
24 })
25}
26
27/// [`CreateDirectory`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectoryw)
28/// function.
29pub fn CreateDirectory(
30 path_name: &str,
31 security_attributes: Option<&SECURITY_ATTRIBUTES>,
32) -> SysResult<()> {
33 bool_to_sysresult(unsafe {
34 ffi::CreateDirectoryW(
35 WString::from_str(path_name).as_ptr(),
36 security_attributes.map_or(std::ptr::null_mut(), |sa| pcvoid(sa)),
37 )
38 })
39}
40
41/// [`CreateProcess`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw)
42/// function.
43#[must_use]
44pub fn CreateProcess(
45 application_name: Option<&str>,
46 command_line: Option<&str>,
47 process_attrs: Option<&SECURITY_ATTRIBUTES>,
48 thread_attrs: Option<&SECURITY_ATTRIBUTES>,
49 inherit_handles: bool,
50 creation_flags: co::CREATE,
51 environment_vars: &[(&str, &str)],
52 current_dir: Option<&str>,
53 si: &mut STARTUPINFO,
54) -> SysResult<CloseHandlePiGuard> {
55 let mut buf_cmd_line = WString::from_opt_str(command_line);
56 let mut pi = PROCESS_INFORMATION::default();
57
58 let mut _env_buf = WString::new();
59 let env_ptr = if environment_vars.is_empty() {
60 std::ptr::null_mut()
61 } else {
62 let env_buf = WString::from_str_vec(
63 &environment_vars
64 .iter()
65 .map(|(name, val)| format!("{}={}", name, val))
66 .collect::<Vec<_>>(),
67 );
68 env_buf.as_ptr() as _
69 };
70
71 unsafe {
72 bool_to_sysresult(ffi::CreateProcessW(
73 WString::from_opt_str(application_name).as_ptr(),
74 buf_cmd_line.as_mut_ptr(),
75 pcvoid_or_null(process_attrs),
76 pcvoid_or_null(thread_attrs),
77 inherit_handles as _,
78 (creation_flags | co::CREATE::UNICODE_ENVIRONMENT).raw(), // environment is always UTF-16
79 env_ptr,
80 WString::from_opt_str(current_dir).as_ptr(),
81 pvoid(si),
82 pvoid(&mut pi),
83 ))
84 .map(|_| CloseHandlePiGuard::new(pi))
85 }
86}
87
88/// [`DeleteFile`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-deletefilew)
89/// function.
90///
91/// # Related functions
92///
93/// * [`CopyFile`](crate::CopyFile)
94/// * [`MoveFile`](crate::MoveFile)
95/// * [`MoveFileEx`](crate::MoveFileEx)
96/// * [`ReplaceFile`](crate::ReplaceFile)
97pub fn DeleteFile(file_name: &str) -> SysResult<()> {
98 bool_to_sysresult(unsafe { ffi::DeleteFileW(WString::from_str(file_name).as_ptr()) })
99}
100
101/// [`ExitProcess`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitprocess)
102/// function.
103pub fn ExitProcess(exit_code: u32) {
104 unsafe { ffi::ExitProcess(exit_code) }
105}
106
107/// [`ExitThread`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitthread)
108/// function.
109pub fn ExitThread(exit_code: u32) {
110 unsafe { ffi::ExitThread(exit_code) }
111}
112
113/// [`ExpandEnvironmentStrings`](https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-expandenvironmentstringsw)
114/// function.
115///
116/// # Examples
117///
118/// ```no_run
119/// use winsafe::{self as w, prelude::*};
120///
121/// let expanded = w::ExpandEnvironmentStrings(
122/// "Os %OS%, home %HOMEPATH% and temp %TEMP%",
123/// )?;
124///
125/// println!("{}", expanded);
126/// # w::SysResult::Ok(())
127/// ```
128#[must_use]
129pub fn ExpandEnvironmentStrings(src: &str) -> SysResult<String> {
130 let wsrc = WString::from_str(src);
131 let mut buf_sz =
132 match unsafe { ffi::ExpandEnvironmentStringsW(wsrc.as_ptr(), std::ptr::null_mut(), 0) } {
133 0 => return Err(GetLastError()),
134 n => n,
135 }; // includes terminating null count
136
137 loop {
138 let mut buf = WString::new_alloc_buf(buf_sz as _);
139 let required_sz = match unsafe {
140 ffi::ExpandEnvironmentStringsW(wsrc.as_ptr(), buf.as_mut_ptr(), buf_sz)
141 } {
142 0 => return Err(GetLastError()),
143 n => n,
144 }; // plus terminating null count
145
146 if required_sz <= buf_sz {
147 return Ok(buf.to_string());
148 }
149
150 buf_sz = required_sz; // includes terminating null count; set the new buffer size to try again
151 }
152}
153
154/// [`FileTimeToSystemTime`](https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-filetimetosystemtime)
155/// function.
156///
157/// Note that the system time is UTC. In order to convert to local time, you
158/// must also pass the returned `SYSTEMTIME` to
159/// [`SystemTimeToTzSpecificLocalTime`](crate::SystemTimeToTzSpecificLocalTime).
160///
161/// # Related functions
162///
163/// * [`GetLocalTime`](crate::GetLocalTime)
164/// * [`GetSystemTime`](crate::GetSystemTime)
165/// * [`SystemTimeToFileTime`](crate::SystemTimeToFileTime)
166/// * [`SystemTimeToTzSpecificLocalTime`](crate::SystemTimeToTzSpecificLocalTime)
167#[must_use]
168pub fn FileTimeToSystemTime(ft: &FILETIME) -> SysResult<SYSTEMTIME> {
169 let mut st = SYSTEMTIME::default();
170 bool_to_sysresult(unsafe { ffi::FileTimeToSystemTime(pcvoid(ft), pvoid(&mut st)) }).map(|_| st)
171}
172
173/// [`FlushProcessWriteBuffers`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-flushprocesswritebuffers)
174/// function.
175pub fn FlushProcessWriteBuffers() {
176 unsafe { ffi::FlushProcessWriteBuffers() }
177}
178
179/// [`FormatMessage`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-formatmessagew)
180/// function.
181///
182/// You don't need to call this function: all error types implement the
183/// [`SystemError`](crate::prelude::SystemError) trait which will automatically
184/// call `FormatMessage`.
185///
186/// # Safety
187///
188/// Incorrect usage of the flags and formatting string may lead to memory
189/// corruption.
190#[must_use]
191pub unsafe fn FormatMessage(
192 flags: co::FORMAT_MESSAGE,
193 source: Option<*mut std::ffi::c_void>,
194 message_id: u32,
195 lang_id: LANGID,
196 args: &[*mut std::ffi::c_void],
197) -> SysResult<String> {
198 let mut ptr_buf = std::ptr::null_mut::<u16>();
199
200 let nchars = match unsafe {
201 ffi::FormatMessageW(
202 flags.raw(),
203 source.unwrap_or(std::ptr::null_mut()),
204 message_id,
205 u16::from(lang_id) as _,
206 &mut ptr_buf as *mut *mut _ as _, // pass pointer to pointer
207 0,
208 vec_ptr(args) as _,
209 )
210 } as _
211 {
212 0 => Err(GetLastError()),
213 nchars => Ok(nchars),
214 }?;
215
216 let final_wstr = WString::from_wchars_count(ptr_buf, nchars as _);
217 let _ = unsafe { LocalFreeGuard::new(HLOCAL::from_ptr(ptr_buf as _)) }; // free returned pointer
218 Ok(final_wstr.to_string())
219}
220
221/// [`GetBinaryType`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getbinarytypew)
222/// function.
223#[must_use]
224pub fn GetBinaryType(application_name: &str) -> SysResult<co::SCS> {
225 let mut binary_type = co::SCS::default();
226 bool_to_sysresult(unsafe {
227 ffi::GetBinaryTypeW(WString::from_str(application_name).as_ptr(), binary_type.as_mut())
228 })
229 .map(|_| binary_type)
230}
231
232/// [`GetCommandLine`](https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getcommandlinew)
233/// function.
234///
235/// For an example, see [`CommandLineToArgv`](crate::CommandLineToArgv).
236#[must_use]
237pub fn GetCommandLine() -> String {
238 unsafe { WString::from_wchars_nullt(ffi::GetCommandLineW()) }.to_string()
239}
240
241/// [`GetComputerName`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcomputernamew)
242/// function.
243#[must_use]
244pub fn GetComputerName() -> SysResult<String> {
245 let mut buf = WString::new_alloc_buf(MAX_COMPUTERNAME_LENGTH + 1);
246 let mut sz = buf.buf_len() as u32;
247
248 bool_to_sysresult(unsafe { ffi::GetComputerNameW(buf.as_mut_ptr(), &mut sz) })
249 .map(|_| buf.to_string())
250}
251
252/// [`GetCurrentDirectory`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getcurrentdirectory)
253/// function.
254#[must_use]
255pub fn GetCurrentDirectory() -> SysResult<String> {
256 let mut buf_sz = match unsafe { ffi::GetCurrentDirectoryW(0, std::ptr::null_mut()) } {
257 0 => return Err(GetLastError()),
258 n => n,
259 }; // includes terminating null count
260
261 loop {
262 let mut buf = WString::new_alloc_buf(buf_sz as _);
263 let returned_chars = match unsafe { ffi::GetCurrentDirectoryW(buf_sz, buf.as_mut_ptr()) } {
264 0 => return Err(GetLastError()),
265 n => n,
266 };
267
268 if returned_chars < buf_sz {
269 return Ok(buf.to_string());
270 }
271
272 buf_sz = returned_chars; // includes terminating null count; set the new buffer size to try again
273 }
274}
275
276/// [`GetCurrentProcessId`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocessid)
277/// function.
278#[must_use]
279pub fn GetCurrentProcessId() -> u32 {
280 unsafe { ffi::GetCurrentProcessId() }
281}
282
283/// [`GetCurrentThreadId`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentthreadid)
284/// function.
285#[must_use]
286pub fn GetCurrentThreadId() -> u32 {
287 unsafe { ffi::GetCurrentThreadId() }
288}
289
290/// [`GetDriveType`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdrivetypew)
291/// function.
292#[must_use]
293pub fn GetDriveType(root_path_name: Option<&str>) -> co::DRIVE {
294 unsafe {
295 co::DRIVE::from_raw(ffi::GetDriveTypeW(WString::from_opt_str(root_path_name).as_ptr()))
296 }
297}
298
299/// [`GetDiskFreeSpaceEx`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdiskfreespaceexw)
300/// function.
301pub fn GetDiskFreeSpaceEx(
302 directory_name: Option<&str>,
303 free_bytes_available_to_caller: Option<&mut u64>,
304 total_number_of_bytes: Option<&mut u64>,
305 total_number_of_free_bytes: Option<&mut u64>,
306) -> SysResult<()> {
307 bool_to_sysresult(unsafe {
308 ffi::GetDiskFreeSpaceExW(
309 WString::from_opt_str(directory_name).as_ptr(),
310 free_bytes_available_to_caller.map_or(std::ptr::null_mut(), |n| n),
311 total_number_of_bytes.map_or(std::ptr::null_mut(), |n| n),
312 total_number_of_free_bytes.map_or(std::ptr::null_mut(), |n| n),
313 )
314 })
315}
316
317/// [`GetDiskSpaceInformation`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getdiskspaceinformationw)
318/// function.
319#[must_use]
320pub fn GetDiskSpaceInformation(root_path: &str) -> SysResult<DISK_SPACE_INFORMATION> {
321 let mut disk_space_info = DISK_SPACE_INFORMATION::default();
322 match unsafe {
323 co::ERROR::from_raw(ffi::GetDiskSpaceInformationW(
324 WString::from_str(root_path).as_ptr(),
325 pvoid(&mut disk_space_info),
326 ))
327 } {
328 co::ERROR::SUCCESS | co::ERROR::MORE_DATA => Ok(disk_space_info),
329 err => Err(err),
330 }
331}
332
333/// [`GetEnvironmentStrings`](https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getenvironmentstringsw)
334/// function.
335///
336/// Returns the parsed strings, and automatically frees the retrieved
337/// environment block with
338/// [`FreeEnvironmentStrings`](https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-freeenvironmentstringsw).
339///
340/// # Examples
341///
342/// Retrieving and printing the key/value pairs of all environment strings:
343///
344/// ```no_run
345/// use winsafe::{self as w, prelude::*};
346///
347/// let env_vars = w::GetEnvironmentStrings()?;
348/// for (k, v) in env_vars.iter() {
349/// println!("{} = {}", k, v);
350/// }
351/// # w::SysResult::Ok(())
352/// ```
353#[must_use]
354pub fn GetEnvironmentStrings() -> SysResult<Vec<(String, String)>> {
355 ptr_to_sysresult(unsafe { ffi::GetEnvironmentStringsW() } as _).map(|ptr| {
356 let vec_entries = unsafe { parse_multi_z_str(ptr as _, None) };
357 unsafe {
358 ffi::FreeEnvironmentStringsW(ptr);
359 }
360 vec_entries
361 .iter()
362 .map(|env_str| {
363 let mut pair = env_str.split("="); // assumes correctly formatted pairs
364 let key = pair.next().unwrap();
365 let val = pair.next().unwrap();
366 (key.to_owned(), val.to_owned())
367 })
368 .collect()
369 })
370}
371
372/// [`GetFileAttributes`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesw)
373/// function.
374///
375/// # Examples
376///
377/// Checking whether a file or folder exists:
378///
379/// ```no_run
380/// use winsafe::{self as w, prelude::*};
381///
382/// let file_exists = w::GetFileAttributes("C:\\Temp\\test.txt").is_ok();
383/// ```
384///
385/// Retrieving various information about a file or folder path:
386///
387/// ```no_run
388/// use winsafe::{self as w, prelude::*, co};
389///
390/// let flags = w::GetFileAttributes("C:\\Temp\\test.txt")?;
391///
392/// let is_compressed = flags.has(co::FILE_ATTRIBUTE::COMPRESSED);
393/// let is_directory = flags.has(co::FILE_ATTRIBUTE::DIRECTORY);
394/// let is_encrypted = flags.has(co::FILE_ATTRIBUTE::ENCRYPTED);
395/// let is_hidden = flags.has(co::FILE_ATTRIBUTE::HIDDEN);
396/// let is_temporary = flags.has(co::FILE_ATTRIBUTE::TEMPORARY);
397/// # w::SysResult::Ok(())
398/// ```
399#[must_use]
400pub fn GetFileAttributes(file_name: &str) -> SysResult<co::FILE_ATTRIBUTE> {
401 const INVALID: u32 = INVALID_FILE_ATTRIBUTES as u32;
402 match unsafe { ffi::GetFileAttributesW(WString::from_str(file_name).as_ptr()) } {
403 INVALID => Err(GetLastError()),
404 flags => Ok(unsafe { co::FILE_ATTRIBUTE::from_raw(flags) }),
405 }
406}
407
408/// [`GetFileAttributesEx`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesexw)
409/// function.
410///
411/// This function uses `GET_FILEEX_INFO_LEVELS::GetFileExInfoStandard` flag,
412/// which is the only available flag.
413pub fn GetFileAttributesEx(file: &str) -> SysResult<WIN32_FILE_ATTRIBUTE_DATA> {
414 let mut wfad = WIN32_FILE_ATTRIBUTE_DATA::default();
415 bool_to_sysresult(unsafe {
416 ffi::GetFileAttributesExW(WString::from_str(file).as_ptr(), 0, pvoid(&mut wfad))
417 })
418 .map(|_| wfad)
419}
420
421/// [`GetFirmwareType`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getfirmwaretype)
422/// function.
423#[must_use]
424pub fn GetFirmwareType() -> SysResult<co::FIRMWARE_TYPE> {
425 let mut ft = co::FIRMWARE_TYPE::default();
426 bool_to_sysresult(unsafe { ffi::GetFirmwareType(ft.as_mut()) }).map(|_| ft)
427}
428
429/// [`GetLargePageMinimum`](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-getlargepageminimum)
430/// function.
431#[must_use]
432pub fn GetLargePageMinimum() -> usize {
433 unsafe { ffi::GetLargePageMinimum() }
434}
435
436/// [`GetLastError`](https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror)
437/// function.
438///
439/// This function is automatically called every time a
440/// [`SysResult`](crate::SysResult) evaluates to `Err`, so it's unlikely that
441/// you ever need to call it.
442#[must_use]
443pub fn GetLastError() -> co::ERROR {
444 unsafe { co::ERROR::from_raw(ffi::GetLastError()) }
445}
446
447/// [`GetLocalTime`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlocaltime)
448/// function.
449///
450/// This function retrieves local time; for UTC time use
451/// [`GetSystemTime`](crate::GetSystemTime).
452///
453/// # Related functions
454///
455/// * [`FileTimeToSystemTime`](crate::FileTimeToSystemTime)
456/// * [`GetSystemTime`](crate::GetSystemTime)
457/// * [`SystemTimeToFileTime`](crate::SystemTimeToFileTime)
458/// * [`SystemTimeToTzSpecificLocalTime`](crate::SystemTimeToTzSpecificLocalTime)
459#[must_use]
460pub fn GetLocalTime() -> SYSTEMTIME {
461 let mut st = SYSTEMTIME::default();
462 unsafe {
463 ffi::GetLocalTime(pvoid(&mut st));
464 }
465 st
466}
467
468/// [`GetLogicalDrives`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrives)
469/// function.
470#[must_use]
471pub fn GetLogicalDrives() -> u32 {
472 unsafe { ffi::GetLogicalDrives() }
473}
474
475/// [`GetLogicalDriveStrings`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlogicaldrivestringsw)
476/// function.
477#[must_use]
478pub fn GetLogicalDriveStrings() -> SysResult<Vec<String>> {
479 let len = match unsafe { ffi::GetLogicalDriveStringsW(0, std::ptr::null_mut()) } {
480 0 => Err(GetLastError()),
481 len => Ok(len),
482 }?;
483
484 let mut buf = WString::new_alloc_buf(len as usize + 1); // room for terminating null
485
486 unsafe {
487 bool_to_sysresult(ffi::GetLogicalDriveStringsW(len, buf.as_mut_ptr()) as _)
488 .map(|_| parse_multi_z_str(buf.as_ptr(), Some(buf.buf_len())))
489 }
490}
491
492/// [`GetLongPathName`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getlongpathnamew)
493/// function.
494#[must_use]
495pub fn GetLongPathName(short_path: &str) -> SysResult<String> {
496 let short_path_w = WString::from_str(short_path);
497 let path_sz =
498 match unsafe { ffi::GetLongPathNameW(short_path_w.as_ptr(), std::ptr::null_mut(), 0) } {
499 0 => return Err(GetLastError()),
500 len => len,
501 };
502
503 let mut path_buf = WString::new_alloc_buf(path_sz as _);
504 match unsafe { ffi::GetLongPathNameW(short_path_w.as_ptr(), path_buf.as_mut_ptr(), path_sz) } {
505 0 => Err(GetLastError()),
506 _ => Ok(path_buf.to_string()),
507 }
508}
509
510/// [`GetNativeSystemInfo`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getnativesysteminfo)
511/// function.
512#[must_use]
513pub fn GetNativeSystemInfo() -> SYSTEM_INFO {
514 let mut si = SYSTEM_INFO::default();
515 unsafe {
516 ffi::GetNativeSystemInfo(pvoid(&mut si));
517 }
518 si
519}
520
521/// [`GetPrivateProfileSection`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprivateprofilesectionw)
522/// function.
523///
524/// # Examples
525///
526/// Reading all key/value pairs of a section from an INI file:
527///
528/// ```no_run
529/// use winsafe::{self as w, prelude::*};
530///
531/// let pairs = w::GetPrivateProfileSection(
532/// "MySection",
533/// "C:\\Temp\\foo.ini",
534/// )?;
535///
536/// for (key, val) in pairs.iter() {
537/// println!("{} = {}", key, val);
538/// }
539/// # w::SysResult::Ok(())
540/// ```
541///
542/// # Related functions
543///
544/// * [`GetPrivateProfileSectionNames`](crate::GetPrivateProfileSectionNames)
545/// * [`GetPrivateProfileString`](crate::GetPrivateProfileString)
546/// * [`WritePrivateProfileString`](crate::WritePrivateProfileString)
547#[must_use]
548pub fn GetPrivateProfileSection(
549 section_name: &str,
550 file_name: &str,
551) -> SysResult<Vec<(String, String)>> {
552 let mut buf_sz = WString::SSO_LEN; // start with no string heap allocation
553 loop {
554 let mut buf = WString::new_alloc_buf(buf_sz);
555 let returned_chars = unsafe {
556 // Char count without terminating null.
557 ffi::GetPrivateProfileSectionW(
558 WString::from_str(section_name).as_ptr(),
559 buf.as_mut_ptr(),
560 buf.buf_len() as _,
561 WString::from_str(file_name).as_ptr(),
562 )
563 } + 1 + 1; // plus terminating null count, plus weird extra count
564
565 if GetLastError() == co::ERROR::FILE_NOT_FOUND {
566 return Err(co::ERROR::FILE_NOT_FOUND);
567 } else if (returned_chars as usize) < buf_sz {
568 // to break, must have at least 1 char gap
569 return Ok(unsafe { parse_multi_z_str(buf.as_ptr(), Some(buf.buf_len())) }
570 .iter()
571 .map(|line| match line.split_once('=') {
572 Some((key, val)) => (key.to_owned(), val.to_owned()),
573 None => (String::new(), String::new()),
574 })
575 .collect());
576 }
577
578 buf_sz *= 2; // double the buffer size to try again
579 }
580}
581
582/// [`GetPrivateProfileSectionNames`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprivateprofilesectionnamesw)
583/// function.
584///
585/// # Examples
586///
587/// Reading all section names from an INI file:
588///
589/// ```no_run
590/// use winsafe::{self as w, prelude::*};
591///
592/// let sections = w::GetPrivateProfileSectionNames(
593/// Some("C:\\Temp\\foo.ini"),
594/// )?;
595///
596/// for section in sections.iter() {
597/// println!("{}", section);
598/// }
599/// # w::SysResult::Ok(())
600/// ```
601///
602/// # Related functions
603///
604/// * [`GetPrivateProfileSection`](crate::GetPrivateProfileSection)
605/// * [`GetPrivateProfileString`](crate::GetPrivateProfileString)
606/// * [`WritePrivateProfileString`](crate::WritePrivateProfileString)
607#[must_use]
608pub fn GetPrivateProfileSectionNames(file_name: Option<&str>) -> SysResult<Vec<String>> {
609 let mut buf_sz = WString::SSO_LEN; // start with no string heap allocation
610 loop {
611 let mut buf = WString::new_alloc_buf(buf_sz);
612
613 // Char count without terminating null.
614 let returned_chars = unsafe {
615 ffi::GetPrivateProfileSectionNamesW(
616 buf.as_mut_ptr(),
617 buf.buf_len() as _,
618 WString::from_opt_str(file_name).as_ptr(),
619 )
620 } + 1 + 1; // plus terminating null count, plus weird extra count
621
622 if GetLastError() == co::ERROR::FILE_NOT_FOUND {
623 return Err(co::ERROR::FILE_NOT_FOUND);
624 } else if (returned_chars as usize) < buf_sz {
625 // To break, must have at least 1 char gap.
626 return Ok(unsafe { parse_multi_z_str(buf.as_ptr(), Some(buf.buf_len())) });
627 }
628
629 buf_sz *= 2; // double the buffer size to try again
630 }
631}
632
633/// [`GetPrivateProfileString`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprivateprofilestringw)
634/// function.
635///
636/// # Examples
637///
638/// Reading from an INI file:
639///
640/// ```no_run
641/// use winsafe::{self as w, prelude::*};
642///
643/// let val = w::GetPrivateProfileString(
644/// "MySection",
645/// "MyKey",
646/// "C:\\Temp\\foo.ini",
647/// )?.unwrap_or("not found!".to_owned());
648///
649/// println!("{}", val);
650/// # w::SysResult::Ok(())
651/// ```
652///
653/// # Related functions
654///
655/// * [`GetPrivateProfileSection`](crate::GetPrivateProfileSection)
656/// * [`GetPrivateProfileSectionNames`](crate::GetPrivateProfileSectionNames)
657/// * [`WritePrivateProfileString`](crate::WritePrivateProfileString)
658#[must_use]
659pub fn GetPrivateProfileString(
660 section_name: &str,
661 key_name: &str,
662 file_name: &str,
663) -> SysResult<Option<String>> {
664 let mut buf_sz = WString::SSO_LEN; // start with no string heap allocation
665 loop {
666 let mut buf = WString::new_alloc_buf(buf_sz);
667 unsafe {
668 // Char count without terminating null.
669 ffi::GetPrivateProfileStringW(
670 WString::from_str(section_name).as_ptr(),
671 WString::from_str(key_name).as_ptr(),
672 std::ptr::null_mut(),
673 buf.as_mut_ptr(),
674 buf.buf_len() as _,
675 WString::from_str(file_name).as_ptr(),
676 );
677 }
678
679 match GetLastError() {
680 co::ERROR::SUCCESS => {
681 return Ok(Some(buf.to_string()));
682 },
683 co::ERROR::MORE_DATA => {
684 buf_sz *= 2; // double the buffer size to try again
685 },
686 co::ERROR::FILE_NOT_FOUND => {
687 return Ok(None);
688 },
689 e => {
690 return Err(e);
691 },
692 }
693 }
694}
695
696/// [`GetStartupInfo`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getstartupinfow)
697/// function.
698#[must_use]
699pub fn GetStartupInfo<'a, 'b>() -> STARTUPINFO<'a, 'b> {
700 let mut si = STARTUPINFO::default();
701 unsafe {
702 ffi::GetStartupInfoW(pvoid(&mut si));
703 }
704 si
705}
706
707/// [`GetSystemDirectory`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemdirectoryw)
708/// function.
709#[must_use]
710pub fn GetSystemDirectory() -> SysResult<String> {
711 let mut buf = WString::new_alloc_buf(MAX_PATH + 1);
712 let nchars = match unsafe { ffi::GetSystemDirectoryW(buf.as_mut_ptr(), buf.buf_len() as _) } {
713 0 => return Err(GetLastError()),
714 n => n,
715 } as usize;
716
717 if nchars > buf.buf_len() {
718 buf = WString::new_alloc_buf(nchars);
719 if unsafe { ffi::GetSystemDirectoryW(buf.as_mut_ptr(), buf.buf_len() as _) } == 0 {
720 return Err(GetLastError());
721 }
722 }
723
724 Ok(buf.to_string())
725}
726
727/// [`GetSystemFileCacheSize`](https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-getsystemfilecachesize)
728/// function.
729///
730/// Returns minimum and maximum size of file cache (in bytes), and enabled cache
731/// limit flags, respectively.
732#[must_use]
733pub fn GetSystemFileCacheSize() -> SysResult<(usize, usize, co::FILE_CACHE)> {
734 let (mut min, mut max) = (0usize, 0usize);
735 let mut flags = co::FILE_CACHE::default();
736 bool_to_sysresult(unsafe { ffi::GetSystemFileCacheSize(&mut min, &mut max, flags.as_mut()) })
737 .map(|_| (min, max, flags))
738}
739
740/// [`GetSystemInfo`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo)
741/// function.
742#[must_use]
743pub fn GetSystemInfo() -> SYSTEM_INFO {
744 let mut si = SYSTEM_INFO::default();
745 unsafe {
746 ffi::GetSystemInfo(pvoid(&mut si));
747 }
748 si
749}
750
751/// [`GetSystemTime`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtime)
752/// function.
753///
754/// This function retrieves UTC time; for local time use
755/// [`GetLocalTime`](crate::GetLocalTime).
756///
757/// # Related functions
758///
759/// * [`FileTimeToSystemTime`](crate::FileTimeToSystemTime)
760/// * [`GetLocalTime`](crate::GetLocalTime)
761/// * [`SystemTimeToFileTime`](crate::SystemTimeToFileTime)
762/// * [`SystemTimeToTzSpecificLocalTime`](crate::SystemTimeToTzSpecificLocalTime)
763#[must_use]
764pub fn GetSystemTime() -> SYSTEMTIME {
765 let mut st = SYSTEMTIME::default();
766 unsafe {
767 ffi::GetSystemTime(pvoid(&mut st));
768 }
769 st
770}
771
772/// [`GetSystemTimeAsFileTime`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime)
773/// function.
774#[must_use]
775pub fn GetSystemTimeAsFileTime() -> FILETIME {
776 let mut ft = FILETIME::default();
777 unsafe {
778 ffi::GetSystemTimeAsFileTime(pvoid(&mut ft));
779 }
780 ft
781}
782
783/// [`GetSystemTimePreciseAsFileTime`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime)
784/// function.
785#[must_use]
786pub fn GetSystemTimePreciseAsFileTime() -> FILETIME {
787 let mut ft = FILETIME::default();
788 unsafe {
789 ffi::GetSystemTimePreciseAsFileTime(pvoid(&mut ft));
790 }
791 ft
792}
793
794/// [`GetSystemTimes`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getsystemtimes)
795/// function.
796///
797/// Returns idle, kernel and user times.
798///
799/// # Examples
800///
801/// Retrieving just the kernel time:
802///
803/// ```no_run
804/// use winsafe::{self as w, prelude::*};
805///
806/// let (_, kernel_time, _) = w::GetSystemTimes()?;
807/// # w::SysResult::Ok(())
808/// ```
809#[must_use]
810pub fn GetSystemTimes() -> SysResult<(FILETIME, FILETIME, FILETIME)> {
811 let mut idle_time = FILETIME::default();
812 let mut kernel_time = FILETIME::default();
813 let mut user_time = FILETIME::default();
814
815 bool_to_sysresult(unsafe {
816 ffi::GetSystemTimes(pvoid(&mut idle_time), pvoid(&mut kernel_time), pvoid(&mut user_time))
817 })
818 .map(|_| (idle_time, kernel_time, user_time))
819}
820
821/// [`GetTempFileName`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettempfilenamew)
822/// function.
823#[must_use]
824pub fn GetTempFileName(path_name: &str, prefix: &str, unique: u32) -> SysResult<String> {
825 let mut buf = WString::new_alloc_buf(MAX_PATH + 1);
826 bool_to_sysresult(unsafe {
827 ffi::GetTempFileNameW(
828 WString::from_str(path_name).as_ptr(),
829 WString::from_str(prefix).as_ptr(),
830 unique,
831 buf.as_mut_ptr(),
832 )
833 } as _)
834 .map(|_| buf.to_string())
835}
836
837/// [`GetTempPath`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppathw)
838/// function.
839#[must_use]
840pub fn GetTempPath() -> SysResult<String> {
841 let mut buf = WString::new_alloc_buf(MAX_PATH + 1);
842 bool_to_sysresult(unsafe { ffi::GetTempPathW(buf.buf_len() as _, buf.as_mut_ptr()) } as _)
843 .map(|_| buf.to_string())
844}
845
846/// [`GetTickCount64`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64)
847/// function.
848#[must_use]
849pub fn GetTickCount64() -> u64 {
850 unsafe { ffi::GetTickCount64() }
851}
852
853/// [`GetVolumeInformation`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationw)
854/// function.
855///
856/// # Examples
857///
858/// ```no_run
859/// use winsafe::{self as w, prelude::*, co};
860///
861/// let mut name = String::new();
862/// let mut serial_no = 0u32;
863/// let mut max_comp_len = 0u32;
864/// let mut sys_flags = co::FILE_VOL::default();
865/// let mut sys_name = String::new();
866///
867/// w::GetVolumeInformation(
868/// Some("C:\\"),
869/// Some(&mut name),
870/// Some(&mut serial_no),
871/// Some(&mut max_comp_len),
872/// Some(&mut sys_flags),
873/// Some(&mut sys_name),
874/// )?;
875///
876/// println!("Name: {}", name);
877/// println!("Serial no: {:#010x}", serial_no);
878/// println!("Max comp len: {}", max_comp_len);
879/// println!("Sys flags: {:?}", sys_flags);
880/// println!("Sys name: {}", sys_name);
881/// # w::SysResult::Ok(())
882/// ```
883pub fn GetVolumeInformation(
884 root_path_name: Option<&str>,
885 name: Option<&mut String>,
886 serial_number: Option<&mut u32>,
887 max_component_len: Option<&mut u32>,
888 file_system_flags: Option<&mut co::FILE_VOL>,
889 file_system_name: Option<&mut String>,
890) -> SysResult<()> {
891 let (mut name_buf, name_buf_sz) = match name {
892 None => (WString::new(), 0),
893 Some(_) => (WString::new_alloc_buf(MAX_PATH + 1), MAX_PATH + 1),
894 };
895 let (mut sys_name_buf, sys_name_buf_sz) = match file_system_name {
896 None => (WString::new(), 0),
897 Some(_) => (WString::new_alloc_buf(MAX_PATH + 1), MAX_PATH + 1),
898 };
899
900 bool_to_sysresult(unsafe {
901 ffi::GetVolumeInformationW(
902 WString::from_opt_str(root_path_name).as_ptr(),
903 match name {
904 Some(_) => name_buf.as_mut_ptr(),
905 None => std::ptr::null_mut(),
906 },
907 name_buf_sz as _,
908 serial_number.map_or(std::ptr::null_mut(), |n| n),
909 max_component_len.map_or(std::ptr::null_mut(), |m| m),
910 file_system_flags.map_or(std::ptr::null_mut(), |f| f.as_mut()),
911 match file_system_name {
912 Some(_) => sys_name_buf.as_mut_ptr(),
913 None => std::ptr::null_mut(),
914 },
915 sys_name_buf_sz as _,
916 )
917 })
918 .map(|_| {
919 if let Some(name) = name {
920 *name = name_buf.to_string();
921 }
922 if let Some(sys_name) = file_system_name {
923 *sys_name = sys_name_buf.to_string();
924 }
925 })
926}
927
928/// [`GetVolumePathName`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumepathnamew)
929/// function.
930#[must_use]
931pub fn GetVolumePathName(file_name: &str) -> SysResult<String> {
932 let mut buf = WString::new_alloc_buf(MAX_PATH + 1);
933 bool_to_sysresult(unsafe {
934 ffi::GetVolumePathNameW(
935 WString::from_str(file_name).as_ptr(),
936 buf.as_mut_ptr(),
937 buf.buf_len() as _,
938 )
939 } as _)
940 .map(|_| buf.to_string())
941}
942
943/// [`GlobalMemoryStatusEx`](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-globalmemorystatusex)
944/// function.
945#[must_use]
946pub fn GlobalMemoryStatusEx() -> SysResult<MEMORYSTATUSEX> {
947 let mut msx = MEMORYSTATUSEX::default();
948 bool_to_sysresult(unsafe { ffi::GlobalMemoryStatusEx(pvoid(&mut msx)) }).map(|_| msx)
949}
950
951/// [`HIBYTE`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms632656(v=vs.85))
952/// macro.
953///
954/// # Related functions
955///
956/// * [`HIDWORD`](crate::HIDWORD)
957/// * [`HIWORD`](crate::HIWORD)
958/// * [`LOBYTE`](crate::LOBYTE)
959/// * [`LODWORD`](crate::LODWORD)
960/// * [`LOWORD`](crate::LOWORD)
961/// * [`MAKEDWORD`](crate::MAKEDWORD)
962/// * [`MAKEQWORD`](crate::MAKEQWORD)
963/// * [`MAKEWORD`](crate::MAKEWORD)
964#[must_use]
965pub const fn HIBYTE(v: u16) -> u8 {
966 (v >> 8 & 0xff) as _
967}
968
969/// Returns the high-order `u32` of an `u64`.
970///
971/// # Related functions
972///
973/// * [`HIBYTE`](crate::HIBYTE)
974/// * [`HIWORD`](crate::HIWORD)
975/// * [`LOBYTE`](crate::LOBYTE)
976/// * [`LODWORD`](crate::LODWORD)
977/// * [`LOWORD`](crate::LOWORD)
978/// * [`MAKEDWORD`](crate::MAKEDWORD)
979/// * [`MAKEQWORD`](crate::MAKEQWORD)
980/// * [`MAKEWORD`](crate::MAKEWORD)
981#[must_use]
982pub const fn HIDWORD(v: u64) -> u32 {
983 (v >> 32 & 0xffff_ffff) as _
984}
985
986/// [`HIWORD`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms632657(v=vs.85))
987/// macro.
988///
989/// # Related functions
990///
991/// * [`HIBYTE`](crate::HIBYTE)
992/// * [`HIDWORD`](crate::HIDWORD)
993/// * [`LOBYTE`](crate::LOBYTE)
994/// * [`LODWORD`](crate::LODWORD)
995/// * [`LOWORD`](crate::LOWORD)
996/// * [`MAKEDWORD`](crate::MAKEDWORD)
997/// * [`MAKEQWORD`](crate::MAKEQWORD)
998/// * [`MAKEWORD`](crate::MAKEWORD)
999#[must_use]
1000pub const fn HIWORD(v: u32) -> u16 {
1001 (v >> 16 & 0xffff) as _
1002}
1003
1004/// [`IsDebuggerPresent`](https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-isdebuggerpresent)
1005/// function.
1006#[must_use]
1007pub fn IsDebuggerPresent() -> bool {
1008 unsafe { ffi::IsDebuggerPresent() != 0 }
1009}
1010
1011/// [`IsNativeVhdBoot`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-isnativevhdboot)
1012/// function.
1013#[must_use]
1014pub fn IsNativeVhdBoot() -> SysResult<bool> {
1015 let mut is_native = 0;
1016 bool_to_sysresult(unsafe { ffi::IsNativeVhdBoot(&mut is_native) }).map(|_| is_native != 0)
1017}
1018
1019/// [`IsWindows10OrGreater`](https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindows10orgreater)
1020/// function.
1021#[must_use]
1022pub fn IsWindows10OrGreater() -> SysResult<bool> {
1023 IsWindowsVersionOrGreater(
1024 HIBYTE(co::WIN32::WINNT_WINTHRESHOLD.raw()) as _,
1025 LOBYTE(co::WIN32::WINNT_WINTHRESHOLD.raw()) as _,
1026 0,
1027 )
1028}
1029
1030/// [`IsWindows7OrGreater`](https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindows7orgreater)
1031/// function.
1032#[must_use]
1033pub fn IsWindows7OrGreater() -> SysResult<bool> {
1034 IsWindowsVersionOrGreater(
1035 HIBYTE(co::WIN32::WINNT_WIN7.raw()) as _,
1036 LOBYTE(co::WIN32::WINNT_WIN7.raw()) as _,
1037 0,
1038 )
1039}
1040
1041/// [`IsWindows8OrGreater`](https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindows8orgreater)
1042/// function.
1043#[must_use]
1044pub fn IsWindows8OrGreater() -> SysResult<bool> {
1045 IsWindowsVersionOrGreater(
1046 HIBYTE(co::WIN32::WINNT_WIN8.raw()) as _,
1047 LOBYTE(co::WIN32::WINNT_WIN8.raw()) as _,
1048 0,
1049 )
1050}
1051
1052/// [`IsWindows8Point1OrGreater`](https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindows8point1orgreater)
1053/// function.
1054#[must_use]
1055pub fn IsWindows8Point1OrGreater() -> SysResult<bool> {
1056 IsWindowsVersionOrGreater(
1057 HIBYTE(co::WIN32::WINNT_WINBLUE.raw()) as _,
1058 LOBYTE(co::WIN32::WINNT_WINBLUE.raw()) as _,
1059 0,
1060 )
1061}
1062
1063/// [`IsWindowsServer`](https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindowsserver)
1064/// function.
1065#[must_use]
1066pub fn IsWindowsServer() -> SysResult<bool> {
1067 let mut osvi = OSVERSIONINFOEX::default();
1068 osvi.wProductType = co::VER_NT::WORKSTATION;
1069 let cond_mask = VerSetConditionMask(0, co::VER_MASK::PRODUCT_TYPE, co::VER_COND::EQUAL);
1070 VerifyVersionInfo(&mut osvi, co::VER_MASK::PRODUCT_TYPE, cond_mask).map(|b| !b)
1071}
1072
1073/// [`IsWindowsVersionOrGreater`](https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindowsversionorgreater)
1074/// function.
1075#[must_use]
1076pub fn IsWindowsVersionOrGreater(
1077 major_version: u16,
1078 minor_version: u16,
1079 service_pack_major: u16,
1080) -> SysResult<bool> {
1081 let mut osvi = OSVERSIONINFOEX::default();
1082 let cond_mask = VerSetConditionMask(
1083 VerSetConditionMask(
1084 VerSetConditionMask(0, co::VER_MASK::MAJORVERSION, co::VER_COND::GREATER_EQUAL),
1085 co::VER_MASK::MINORVERSION,
1086 co::VER_COND::GREATER_EQUAL,
1087 ),
1088 co::VER_MASK::SERVICEPACKMAJOR,
1089 co::VER_COND::GREATER_EQUAL,
1090 );
1091
1092 osvi.dwMajorVersion = major_version as _;
1093 osvi.dwMinorVersion = minor_version as _;
1094 osvi.wServicePackMajor = service_pack_major;
1095
1096 VerifyVersionInfo(
1097 &mut osvi,
1098 co::VER_MASK::MAJORVERSION | co::VER_MASK::MINORVERSION | co::VER_MASK::SERVICEPACKMAJOR,
1099 cond_mask,
1100 )
1101}
1102
1103/// [`IsWindowsVistaOrGreater`](https://learn.microsoft.com/en-us/windows/win32/api/versionhelpers/nf-versionhelpers-iswindowsvistaorgreater)
1104/// function.
1105#[must_use]
1106pub fn IsWindowsVistaOrGreater() -> SysResult<bool> {
1107 IsWindowsVersionOrGreater(
1108 HIBYTE(co::WIN32::WINNT_VISTA.raw()) as _,
1109 LOBYTE(co::WIN32::WINNT_VISTA.raw()) as _,
1110 0,
1111 )
1112}
1113
1114/// [`LOBYTE`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms632658(v=vs.85))
1115/// macro.
1116///
1117/// # Related functions
1118///
1119/// * [`HIBYTE`](crate::HIBYTE)
1120/// * [`HIDWORD`](crate::HIDWORD)
1121/// * [`HIWORD`](crate::HIWORD)
1122/// * [`LODWORD`](crate::LODWORD)
1123/// * [`LOWORD`](crate::LOWORD)
1124/// * [`MAKEDWORD`](crate::MAKEDWORD)
1125/// * [`MAKEQWORD`](crate::MAKEQWORD)
1126/// * [`MAKEWORD`](crate::MAKEWORD)
1127#[must_use]
1128pub const fn LOBYTE(v: u16) -> u8 {
1129 (v & 0xff) as _
1130}
1131
1132/// Returns the low-order `u32` of an `u64`.
1133///
1134/// # Related functions
1135///
1136/// * [`HIBYTE`](crate::HIBYTE)
1137/// * [`HIDWORD`](crate::HIDWORD)
1138/// * [`HIWORD`](crate::HIWORD)
1139/// * [`LOBYTE`](crate::LOBYTE)
1140/// * [`LOWORD`](crate::LOWORD)
1141/// * [`MAKEDWORD`](crate::MAKEDWORD)
1142/// * [`MAKEQWORD`](crate::MAKEQWORD)
1143/// * [`MAKEWORD`](crate::MAKEWORD)
1144#[must_use]
1145pub const fn LODWORD(v: u64) -> u32 {
1146 (v & 0xffff_ffff) as _
1147}
1148
1149/// [`LOWORD`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms632659(v=vs.85))
1150/// macro.
1151///
1152/// # Related functions
1153///
1154/// * [`HIBYTE`](crate::HIBYTE)
1155/// * [`HIDWORD`](crate::HIDWORD)
1156/// * [`HIWORD`](crate::HIWORD)
1157/// * [`LOBYTE`](crate::LOBYTE)
1158/// * [`LODWORD`](crate::LODWORD)
1159/// * [`MAKEDWORD`](crate::MAKEDWORD)
1160/// * [`MAKEQWORD`](crate::MAKEQWORD)
1161/// * [`MAKEWORD`](crate::MAKEWORD)
1162#[must_use]
1163pub const fn LOWORD(v: u32) -> u16 {
1164 (v & 0xffff) as _
1165}
1166
1167/// Function analog to
1168/// [`MAKELONG`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms632660(v=vs.85)),
1169/// [`MAKEWPARAM`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makewparam),
1170/// and
1171/// [`MAKELPARAM`](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-makelparam)
1172/// macros.
1173///
1174/// # Related functions
1175///
1176/// * [`HIBYTE`](crate::HIBYTE)
1177/// * [`HIDWORD`](crate::HIDWORD)
1178/// * [`HIWORD`](crate::HIWORD)
1179/// * [`LOBYTE`](crate::LOBYTE)
1180/// * [`LODWORD`](crate::LODWORD)
1181/// * [`LOWORD`](crate::LOWORD)
1182/// * [`MAKEQWORD`](crate::MAKEQWORD)
1183/// * [`MAKEWORD`](crate::MAKEWORD)
1184#[must_use]
1185pub const fn MAKEDWORD(lo: u16, hi: u16) -> u32 {
1186 ((lo as u32 & 0xffff) | ((hi as u32 & 0xffff) << 16)) as _
1187}
1188
1189/// Similar to [`MAKEDWORD`](crate::MAKEDWORD), but for `u64`.
1190///
1191/// # Related functions
1192///
1193/// * [`HIBYTE`](crate::HIBYTE)
1194/// * [`HIDWORD`](crate::HIDWORD)
1195/// * [`HIWORD`](crate::HIWORD)
1196/// * [`LOBYTE`](crate::LOBYTE)
1197/// * [`LODWORD`](crate::LODWORD)
1198/// * [`LOWORD`](crate::LOWORD)
1199/// * [`MAKEDWORD`](crate::MAKEDWORD)
1200/// * [`MAKEWORD`](crate::MAKEWORD)
1201#[must_use]
1202pub const fn MAKEQWORD(lo: u32, hi: u32) -> u64 {
1203 ((lo as u64 & 0xffff_ffff) | ((hi as u64 & 0xffff_ffff) << 32)) as _
1204}
1205
1206/// [`MAKEWORD`](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms632663(v=vs.85))
1207/// macro.
1208///
1209/// # Related functions
1210///
1211/// * [`HIBYTE`](crate::HIBYTE)
1212/// * [`HIDWORD`](crate::HIDWORD)
1213/// * [`HIWORD`](crate::HIWORD)
1214/// * [`LOBYTE`](crate::LOBYTE)
1215/// * [`LODWORD`](crate::LODWORD)
1216/// * [`LOWORD`](crate::LOWORD)
1217/// * [`MAKEDWORD`](crate::MAKEDWORD)
1218/// * [`MAKEQWORD`](crate::MAKEQWORD)
1219#[must_use]
1220pub const fn MAKEWORD(lo: u8, hi: u8) -> u16 {
1221 (lo as u16 & 0xff) | ((hi as u16 & 0xff) << 8) as u16
1222}
1223
1224/// [`MoveFile`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefilew)
1225/// function.
1226///
1227/// # Related functions
1228///
1229/// * [`CopyFile`](crate::CopyFile)
1230/// * [`DeleteFile`](crate::DeleteFile)
1231/// * [`MoveFileEx`](crate::MoveFileEx)
1232/// * [`ReplaceFile`](crate::ReplaceFile)
1233pub fn MoveFile(existing_file: &str, new_file: &str) -> SysResult<()> {
1234 bool_to_sysresult(unsafe {
1235 ffi::MoveFileW(
1236 WString::from_str(existing_file).as_ptr(),
1237 WString::from_str(new_file).as_ptr(),
1238 )
1239 })
1240}
1241
1242/// [`MoveFileEx`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexw)
1243/// function.
1244///
1245/// # Related functions
1246///
1247/// * [`CopyFile`](crate::CopyFile)
1248/// * [`DeleteFile`](crate::DeleteFile)
1249/// * [`MoveFile`](crate::MoveFile)
1250/// * [`ReplaceFile`](crate::ReplaceFile)
1251pub fn MoveFileEx(
1252 existing_file: &str,
1253 new_file: Option<&str>,
1254 flags: co::MOVEFILE,
1255) -> SysResult<()> {
1256 bool_to_sysresult(unsafe {
1257 ffi::MoveFileExW(
1258 WString::from_str(existing_file).as_ptr(),
1259 WString::from_opt_str(new_file).as_ptr(),
1260 flags.raw(),
1261 )
1262 })
1263}
1264
1265/// [`MulDiv`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-muldiv)
1266/// function.
1267#[must_use]
1268pub fn MulDiv(number: i32, numerator: i32, denominator: i32) -> i32 {
1269 unsafe { ffi::MulDiv(number, numerator, denominator) }
1270}
1271
1272/// [`MultiByteToWideChar`](https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar)
1273/// function.
1274///
1275/// If `multi_byte_str` doesn't have a terminating null, the resulting
1276/// `Vec<u16>` also won't include one.
1277///
1278/// # Related functions
1279///
1280/// * [`WideCharToMultiByte`](crate::WideCharToMultiByte)
1281#[must_use]
1282pub fn MultiByteToWideChar(
1283 code_page: co::CP,
1284 flags: co::MBC,
1285 multi_byte_str: &[u8],
1286) -> SysResult<Vec<u16>> {
1287 let num_bytes = match unsafe {
1288 ffi::MultiByteToWideChar(
1289 code_page.raw() as _,
1290 flags.raw(),
1291 vec_ptr(multi_byte_str),
1292 multi_byte_str.len() as _,
1293 std::ptr::null_mut(),
1294 0,
1295 )
1296 } {
1297 0 => Err(GetLastError()),
1298 num_bytes => Ok(num_bytes),
1299 }?;
1300
1301 let mut buf = vec![0u16; num_bytes as _];
1302
1303 bool_to_sysresult(unsafe {
1304 ffi::MultiByteToWideChar(
1305 code_page.raw() as _,
1306 flags.raw(),
1307 vec_ptr(multi_byte_str),
1308 multi_byte_str.len() as _,
1309 buf.as_mut_ptr(),
1310 num_bytes as _,
1311 )
1312 })
1313 .map(|_| buf)
1314}
1315
1316/// [`OutputDebugString`](https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-outputdebugstringw)
1317/// function.
1318pub fn OutputDebugString(output_string: &str) {
1319 unsafe { ffi::OutputDebugStringW(WString::from_str(output_string).as_ptr()) }
1320}
1321
1322/// [`QueryPerformanceCounter`](https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter)
1323/// function.
1324///
1325/// # Examples
1326///
1327/// ```no_run
1328/// use winsafe::{self as w, prelude::*};
1329///
1330/// let freq = w::QueryPerformanceFrequency()?;
1331/// let t0 = w::QueryPerformanceCounter()?;
1332///
1333/// // perform some operation...
1334///
1335/// let duration_ms =
1336/// ((w::QueryPerformanceCounter()? - t0) as f64 / freq as f64) * 1000.0;
1337///
1338/// println!("Operation lasted {:.2} ms", duration_ms);
1339/// # w::SysResult::Ok(())
1340/// ```
1341///
1342/// # Related functions
1343///
1344/// * [`QueryPerformanceFrequency`](crate::QueryPerformanceFrequency)
1345#[must_use]
1346pub fn QueryPerformanceCounter() -> SysResult<i64> {
1347 let mut perf_count = 0i64;
1348 bool_to_sysresult(unsafe { ffi::QueryPerformanceCounter(&mut perf_count) }).map(|_| perf_count)
1349}
1350
1351/// [`QueryPerformanceFrequency`](https://learn.microsoft.com/en-us/windows/win32/api/profileapi/nf-profileapi-queryperformancecounter)
1352/// function.
1353///
1354/// # Related functions
1355///
1356/// * [`QueryPerformanceCounter`](crate::QueryPerformanceCounter)
1357#[must_use]
1358pub fn QueryPerformanceFrequency() -> SysResult<i64> {
1359 let mut freq = 0i64;
1360 bool_to_sysresult(unsafe { ffi::QueryPerformanceFrequency(&mut freq) }).map(|_| freq)
1361}
1362
1363/// [`QueryUnbiasedInterruptTime`](https://learn.microsoft.com/en-us/windows/win32/api/realtimeapiset/nf-realtimeapiset-queryunbiasedinterrupttime)
1364/// function.
1365#[must_use]
1366pub fn QueryUnbiasedInterruptTime() -> SysResult<u64> {
1367 let mut t = 0u64;
1368 bool_to_sysresult(unsafe { ffi::QueryUnbiasedInterruptTime(&mut t) }).map(|_| t)
1369}
1370
1371/// [`ReplaceFile`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-replacefilew)
1372/// function.
1373///
1374/// # Related functions
1375///
1376/// * [`CopyFile`](crate::CopyFile)
1377/// * [`DeleteFile`](crate::DeleteFile)
1378/// * [`MoveFile`](crate::MoveFile)
1379pub fn ReplaceFile(
1380 replaced: &str,
1381 replacement: &str,
1382 backup: Option<&str>,
1383 flags: co::REPLACEFILE,
1384) -> SysResult<()> {
1385 bool_to_sysresult(unsafe {
1386 ffi::ReplaceFileW(
1387 WString::from_str(replaced).as_ptr(),
1388 WString::from_str(replacement).as_ptr(),
1389 WString::from_opt_str(backup).as_ptr(),
1390 flags.raw(),
1391 std::ptr::null_mut(),
1392 std::ptr::null_mut(),
1393 )
1394 })
1395}
1396
1397/// [`SetCurrentDirectory`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcurrentdirectory)
1398/// function.
1399pub fn SetCurrentDirectory(path_name: &str) -> SysResult<()> {
1400 bool_to_sysresult(unsafe { ffi::SetCurrentDirectoryW(WString::from_str(path_name).as_ptr()) })
1401}
1402
1403/// [`SetFileAttributes`](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileattributesw)
1404/// function.
1405pub fn SetFileAttributes(file_name: &str, attributes: co::FILE_ATTRIBUTE) -> SysResult<()> {
1406 bool_to_sysresult(unsafe {
1407 ffi::SetFileAttributesW(WString::from_str(file_name).as_ptr(), attributes.raw())
1408 })
1409}
1410
1411/// [`SetLastError`](https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-setlasterror)
1412/// function.
1413pub fn SetLastError(err_code: co::ERROR) {
1414 unsafe { ffi::SetLastError(err_code.raw()) }
1415}
1416
1417/// [`SetThreadStackGuarantee`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee)
1418/// function.
1419///
1420/// Returns the size of the previous stack.
1421pub fn SetThreadStackGuarantee(stack_size_in_bytes: u32) -> SysResult<u32> {
1422 let mut sz = stack_size_in_bytes;
1423 bool_to_sysresult(unsafe { ffi::SetThreadStackGuarantee(&mut sz) }).map(|_| sz)
1424}
1425
1426/// [`Sleep`](https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep)
1427/// function.
1428pub fn Sleep(milliseconds: u32) {
1429 unsafe { ffi::Sleep(milliseconds) }
1430}
1431
1432/// [`SwitchToThread`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-switchtothread)
1433/// function.
1434pub fn SwitchToThread() -> SysResult<()> {
1435 bool_to_sysresult(unsafe { ffi::SwitchToThread() })
1436}
1437
1438/// [`SystemTimeToFileTime`](https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-systemtimetofiletime)
1439/// function.
1440///
1441/// # Related functions
1442///
1443/// * [`FileTimeToSystemTime`](crate::FileTimeToSystemTime)
1444/// * [`GetLocalTime`](crate::GetLocalTime)
1445/// * [`GetSystemTime`](crate::GetSystemTime)
1446/// * [`SystemTimeToTzSpecificLocalTime`](crate::SystemTimeToTzSpecificLocalTime)
1447#[must_use]
1448pub fn SystemTimeToFileTime(st: &SYSTEMTIME) -> SysResult<FILETIME> {
1449 let mut ft = FILETIME::default();
1450 bool_to_sysresult(unsafe { ffi::SystemTimeToFileTime(pcvoid(st), pvoid(&mut ft)) }).map(|_| ft)
1451}
1452
1453/// [`SystemTimeToTzSpecificLocalTime`](https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-systemtimetotzspecificlocaltime)
1454/// function.
1455///
1456/// # Related functions
1457///
1458/// * [`FileTimeToSystemTime`](crate::FileTimeToSystemTime)
1459/// * [`GetLocalTime`](crate::GetLocalTime)
1460/// * [`GetSystemTime`](crate::GetSystemTime)
1461/// * [`SystemTimeToFileTime`](crate::SystemTimeToFileTime)
1462#[must_use]
1463pub fn SystemTimeToTzSpecificLocalTime(
1464 time_zone: Option<&TIME_ZONE_INFORMATION>,
1465 universal_time: &SYSTEMTIME,
1466) -> SysResult<SYSTEMTIME> {
1467 let mut local_time = SYSTEMTIME::default();
1468 bool_to_sysresult(unsafe {
1469 ffi::SystemTimeToTzSpecificLocalTime(
1470 time_zone.map_or(std::ptr::null(), |lp| pcvoid(lp)),
1471 pcvoid(universal_time),
1472 pvoid(&mut local_time),
1473 )
1474 })
1475 .map(|_| local_time)
1476}
1477
1478/// [`VerifyVersionInfo`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-verifyversioninfow)
1479/// function.
1480#[must_use]
1481pub fn VerifyVersionInfo(
1482 osvix: &mut OSVERSIONINFOEX,
1483 type_mask: co::VER_MASK,
1484 condition_mask: u64,
1485) -> SysResult<bool> {
1486 match unsafe { ffi::VerifyVersionInfoW(pvoid(osvix), type_mask.raw(), condition_mask) } {
1487 0 => match GetLastError() {
1488 co::ERROR::OLD_WIN_VERSION => Ok(false),
1489 err => Err(err),
1490 },
1491 _ => Ok(true),
1492 }
1493}
1494
1495/// [`VerSetConditionMask`](https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-versetconditionmask)
1496/// function.
1497#[must_use]
1498pub fn VerSetConditionMask(
1499 condition_mask: u64,
1500 type_mask: co::VER_MASK,
1501 condition: co::VER_COND,
1502) -> u64 {
1503 unsafe { ffi::VerSetConditionMask(condition_mask, type_mask.raw(), condition.raw()) }
1504}
1505
1506/// [`WideCharToMultiByte`](https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-widechartomultibyte)
1507/// function.
1508///
1509/// If `wide_char_str` doesn't have a terminating null, the resulting `Vec<u8>`
1510/// also won't include one.
1511///
1512/// # Related functions
1513///
1514/// * [`MultiByteToWideChar`](crate::MultiByteToWideChar)
1515#[must_use]
1516pub fn WideCharToMultiByte(
1517 code_page: co::CP,
1518 flags: co::WC,
1519 wide_char_str: &[u16],
1520 default_char: Option<u8>,
1521 used_default_char: Option<&mut bool>,
1522) -> SysResult<Vec<u8>> {
1523 let mut default_char_buf = default_char.unwrap_or_default();
1524
1525 let num_bytes = match unsafe {
1526 ffi::WideCharToMultiByte(
1527 code_page.raw() as _,
1528 flags.raw(),
1529 vec_ptr(wide_char_str),
1530 wide_char_str.len() as _,
1531 std::ptr::null_mut(),
1532 0,
1533 &mut default_char_buf,
1534 std::ptr::null_mut(),
1535 )
1536 } {
1537 0 => Err(GetLastError()),
1538 num_bytes => Ok(num_bytes),
1539 }?;
1540
1541 let mut u8_buf = vec![0u8; num_bytes as _];
1542 let mut bool_buf = 0;
1543
1544 bool_to_sysresult(unsafe {
1545 ffi::WideCharToMultiByte(
1546 code_page.raw() as _,
1547 flags.raw(),
1548 vec_ptr(wide_char_str),
1549 wide_char_str.len() as _,
1550 u8_buf.as_mut_ptr() as _,
1551 num_bytes as _,
1552 &mut default_char_buf,
1553 &mut bool_buf,
1554 )
1555 })
1556 .map(|_| {
1557 if let Some(used_default_char) = used_default_char {
1558 *used_default_char = bool_buf != 0;
1559 }
1560 u8_buf
1561 })
1562}
1563
1564/// [`WritePrivateProfileString`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-writeprivateprofilestringw)
1565/// function.
1566///
1567/// # Examples
1568///
1569/// Writing value into an INI file:
1570///
1571/// ```no_run
1572/// use winsafe::{self as w, prelude::*};
1573///
1574/// w::WritePrivateProfileString(
1575/// "MySection",
1576/// Some("MyKey"),
1577/// Some("new value"),
1578/// "C:\\Temp\\foo.ini",
1579/// )?;
1580/// # w::SysResult::Ok(())
1581/// ```
1582///
1583/// # Related functions
1584///
1585/// * [`GetPrivateProfileSection`](crate::GetPrivateProfileSection)
1586/// * [`GetPrivateProfileSectionNames`](crate::GetPrivateProfileSectionNames)
1587/// * [`GetPrivateProfileString`](crate::GetPrivateProfileString)
1588pub fn WritePrivateProfileString(
1589 section_name: &str,
1590 key_name: Option<&str>,
1591 new_val: Option<&str>,
1592 file_name: &str,
1593) -> SysResult<()> {
1594 bool_to_sysresult(unsafe {
1595 ffi::WritePrivateProfileStringW(
1596 WString::from_str(section_name).as_ptr(),
1597 WString::from_opt_str(key_name).as_ptr(),
1598 WString::from_opt_str(new_val).as_ptr(),
1599 WString::from_str(file_name).as_ptr(),
1600 )
1601 })
1602}