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}