zouni 0.2.1

Variety of functions that `std` does not offer or `std` offers but are not satisfiable
Documentation
use std::os::windows::ffi::OsStrExt;
use windows::{
    core::{HRESULT, PCWSTR},
    Win32::{
        Foundation::{GlobalFree, HGLOBAL, MAX_PATH},
        Globalization::lstrlenW,
        System::{
            Com::{CoInitializeEx, CoUninitialize, COINIT_APARTMENTTHREADED},
            Memory::{GlobalAlloc, GlobalLock, GlobalUnlock, GMEM_MOVEABLE},
        },
    },
};

pub(crate) fn decode_wide(wide: &[u16]) -> String {
    let len = unsafe { lstrlenW(PCWSTR::from_raw(wide.as_ptr())) } as usize;
    let w_str_slice = unsafe { std::slice::from_raw_parts(wide.as_ptr(), len) };
    String::from_utf16_lossy(w_str_slice)
}

pub(crate) fn encode_wide(string: impl AsRef<std::ffi::OsStr>) -> Vec<u16> {
    string.as_ref().encode_wide().chain(std::iter::once(0)).collect()
}

pub(crate) fn prefixed(path: impl AsRef<std::ffi::OsStr>) -> String {
    if path.as_ref().len() >= MAX_PATH as usize {
        if let Some(stripped) = path.as_ref().to_str().unwrap().strip_prefix("\\\\") {
            format!("\\\\?\\UNC\\{}", stripped)
        } else {
            format!("\\\\?\\{}", path.as_ref().to_str().unwrap())
        }
    } else {
        path.as_ref().to_string_lossy().to_string()
    }
}

pub(crate) struct ComGuard;

impl ComGuard {
    pub fn new() -> Self {
        let _ = unsafe { CoInitializeEx(None, COINIT_APARTMENTTHREADED) };
        Self
    }
}

impl Drop for ComGuard {
    fn drop(&mut self) {
        unsafe { CoUninitialize() };
    }
}

pub(crate) struct GlobalMemory {
    handle: HGLOBAL,
}

impl GlobalMemory {
    pub fn new(size: usize) -> Result<Self, String> {
        match unsafe { GlobalAlloc(GMEM_MOVEABLE, size) } {
            Ok(handle) => Ok(Self {
                handle,
            }),
            Err(_) => Err("Failed to allocate global memory".to_string()),
        }
    }

    pub fn lock(&self) -> Result<*mut u8, String> {
        let ptr = unsafe { GlobalLock(self.handle) } as *mut u8;
        if ptr.is_null() {
            Err("Failed to lock global memory".to_string())
        } else {
            Ok(ptr)
        }
    }

    pub fn unlock(&self) {
        let _ = unsafe { GlobalUnlock(self.handle) };
    }

    pub fn handle(&self) -> HGLOBAL {
        self.handle
    }
}

impl Drop for GlobalMemory {
    fn drop(&mut self) {
        if !self.handle.is_invalid() {
            match unsafe { GlobalFree(Some(self.handle)) } {
                Ok(_) => {}
                Err(e) => {
                    if e.code() != HRESULT(0x00000000) {
                        eprintln!("Error freeing global memory: {:?}", e);
                    }
                }
            }
        }
    }
}