1use std::{fmt::Display, marker::PhantomData, mem, ptr};
2
3use windows::{
4 core::{PCWSTR, PWSTR},
5 Win32::{Globalization::lstrlenW, System::Com},
6};
7
8pub struct CoTaskMemPWSTR<'a>(PWSTR, PhantomData<&'a PWSTR>);
11
12pub struct CoTaskMemRef<'a>(PCWSTR, PhantomData<&'a PCWSTR>);
15
16impl CoTaskMemRef<'_> {
17 pub fn as_pcwstr(&self) -> &PCWSTR {
18 &self.0
19 }
20}
21
22impl<'a> From<&'a CoTaskMemPWSTR<'a>> for CoTaskMemRef<'a> {
23 fn from(value: &'a CoTaskMemPWSTR<'a>) -> Self {
24 Self(PCWSTR::from_raw(value.0.as_ptr()), PhantomData)
25 }
26}
27
28pub struct CoTaskMemMut<'a>(&'a PWSTR);
31
32impl<'a> CoTaskMemMut<'a> {
33 pub fn as_pwstr(&mut self) -> &'a PWSTR {
34 self.0
35 }
36}
37
38impl<'a> From<&'a mut CoTaskMemPWSTR<'a>> for CoTaskMemMut<'a> {
39 fn from(value: &'a mut CoTaskMemPWSTR<'a>) -> Self {
40 Self(&value.0)
41 }
42}
43
44impl<'a> CoTaskMemPWSTR<'a> {
45 pub fn as_mut(&'a mut self) -> CoTaskMemMut<'a> {
47 From::from(self)
48 }
49
50 pub fn as_ref(&'a self) -> CoTaskMemRef<'a> {
52 From::from(self)
53 }
54
55 pub fn take(&mut self) -> PWSTR {
57 let result = self.0;
58 self.0 = PWSTR::null();
59 result
60 }
61}
62
63impl Drop for CoTaskMemPWSTR<'_> {
64 fn drop(&mut self) {
65 if !self.0.is_null() {
66 unsafe {
67 Com::CoTaskMemFree(Some(self.0.as_ptr() as *mut _ as *const _));
68 }
69 }
70 }
71}
72
73impl Default for CoTaskMemPWSTR<'_> {
74 fn default() -> Self {
75 Self(PWSTR::null(), PhantomData)
76 }
77}
78
79impl From<PWSTR> for CoTaskMemPWSTR<'_> {
80 fn from(value: PWSTR) -> Self {
81 Self(value, PhantomData)
82 }
83}
84
85impl From<&str> for CoTaskMemPWSTR<'_> {
86 fn from(value: &str) -> Self {
87 match value {
88 "" => Default::default(),
89 value => {
90 let encoded: Vec<_> = value.encode_utf16().chain(std::iter::once(0)).collect();
91
92 unsafe {
93 let mut buffer =
94 Com::CoTaskMemAlloc(encoded.len() * mem::size_of::<u16>()) as *mut u16;
95 let result = PWSTR::from_raw(buffer);
96
97 for char in encoded {
98 *buffer = char;
99 buffer = buffer.add(1);
100 }
101
102 Self(result, PhantomData)
103 }
104 }
105 }
106 }
107}
108
109impl Display for CoTaskMemPWSTR<'_> {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 let value = string_from_pcwstr(self.as_ref().as_pcwstr());
112 f.write_str(value.as_str())
113 }
114}
115
116pub fn string_from_pcwstr(source: &PCWSTR) -> String {
118 if source.0.is_null() {
119 String::new()
120 } else {
121 let len = unsafe { lstrlenW(*source) };
122
123 if len > 0 {
124 unsafe {
125 let buffer = ptr::slice_from_raw_parts(source.0, len as usize);
126 String::from_utf16_lossy(&*buffer)
127 }
128 } else {
129 String::new()
130 }
131 }
132}
133
134pub fn take_pwstr(source: PWSTR) -> String {
137 CoTaskMemPWSTR::from(source).to_string()
138}
139
140pub fn pwstr_from_str(source: &str) -> PWSTR {
142 CoTaskMemPWSTR::from(source).take()
143}