11use crate :: Error ;
22
33use std:: ffi:: OsStr ;
4- use std:: fmt:: { self , Debug } ;
54use std:: iter;
6- use std:: ops:: Deref ;
75use std:: os:: windows:: ffi:: OsStrExt ;
8- use std:: ptr:: { self , NonNull } ;
96
10- use winapi :: {
11- shared :: {
12- ntdef :: ULONG ,
13- winerror :: { SUCCEEDED , S_FALSE , S_OK } ,
14- wtypesbase :: CLSCTX_INPROC_SERVER ,
15- } ,
16- um :: {
17- combaseapi :: { CoCreateInstance , CoInitializeEx , CoTaskMemFree } ,
18- objbase :: COINIT_MULTITHREADED ,
19- spellcheck :: {
20- IEnumSpellingError , ISpellChecker , ISpellCheckerFactory , SpellCheckerFactory ,
7+ use windows :: {
8+ core :: { HSTRING , PWSTR } ,
9+ Win32 :: {
10+ Foundation :: S_FALSE ,
11+ Globalization :: {
12+ IEnumSpellingError , ISpellChecker , ISpellCheckerFactory , ISpellingError ,
13+ SpellCheckerFactory ,
14+ } ,
15+ System :: Com :: {
16+ CoCreateInstance , CoInitializeEx , CoTaskMemFree , CLSCTX_INPROC_SERVER ,
17+ COINIT_MULTITHREADED ,
2118 } ,
22- unknwnbase:: IUnknown ,
2319 } ,
24- Class , Interface ,
2520} ;
2621
27- struct ComPtr < T > ( NonNull < T > ) ;
28-
29- impl < T > ComPtr < T > {
30- fn new ( p : * mut T ) -> ComPtr < T >
31- where
32- T : Interface ,
33- {
34- ComPtr ( NonNull :: new ( p) . unwrap ( ) )
35- }
36- }
37-
38- impl < T > Deref for ComPtr < T > {
39- type Target = T ;
40-
41- fn deref ( & self ) -> & T {
42- unsafe { & * self . 0 . as_ptr ( ) }
43- }
44- }
45-
46- impl < T > Debug for ComPtr < T > {
47- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
48- f. debug_tuple ( "ComPtr" )
49- . field ( & format_args ! ( "{:p}" , self . 0 . as_ptr( ) ) )
50- . finish ( )
51- }
52- }
53-
54- impl < T > Drop for ComPtr < T > {
55- fn drop ( & mut self ) {
56- unsafe {
57- let unknown = self . 0 . as_ptr ( ) as * mut IUnknown ;
58- ( * unknown) . Release ( ) ;
59- }
60- }
61- }
62-
6322fn wide_string ( s : & str ) -> Vec < u16 > {
6423 OsStr :: new ( s) . encode_wide ( ) . chain ( iter:: once ( 0 ) ) . collect ( )
6524}
@@ -75,53 +34,22 @@ fn utf16_offset_to_utf8(s: &str, utf16_units: usize) -> usize {
7534 s. len ( )
7635}
7736
78- fn create_factory ( ) -> Result < ComPtr < ISpellCheckerFactory > , Error > {
79- let hr = unsafe { CoInitializeEx ( ptr:: null_mut ( ) , COINIT_MULTITHREADED ) } ;
80- if hr != S_OK && hr != S_FALSE {
81- return Err ( Error :: Unavailable ) ;
82- }
83-
84- let mut obj = ptr:: null_mut ( ) ;
85- let hr = unsafe {
86- CoCreateInstance (
87- & SpellCheckerFactory :: uuidof ( ) ,
88- ptr:: null_mut ( ) ,
89- CLSCTX_INPROC_SERVER ,
90- & ISpellCheckerFactory :: uuidof ( ) ,
91- & mut obj,
92- )
93- } ;
94- if !SUCCEEDED ( hr) {
95- return Err ( Error :: Unavailable ) ;
96- }
97- Ok ( ComPtr :: new ( obj as * mut ISpellCheckerFactory ) )
98- }
37+ fn open_for_language ( bcp47 : & str ) -> Result < ISpellChecker , Error > {
38+ // S_OK / S_FALSE (already initialized) both succeed via windows::Result
39+ let _ = unsafe { CoInitializeEx ( None , COINIT_MULTITHREADED ) } ;
9940
100- fn open_for_language ( bcp47 : & str ) -> Result < ComPtr < ISpellChecker > , Error > {
101- let factory = create_factory ( ) ?;
102- let lang = wide_string ( bcp47) ;
103- let mut checker = ptr:: null_mut ( ) ;
104- let hr = unsafe { ( * factory) . CreateSpellChecker ( lang. as_ptr ( ) , & mut checker) } ;
105- if !SUCCEEDED ( hr) {
106- return Err ( Error :: Unavailable ) ;
41+ let factory: ISpellCheckerFactory = unsafe {
42+ CoCreateInstance ( & SpellCheckerFactory , None , CLSCTX_INPROC_SERVER )
10743 }
108- Ok ( ComPtr :: new ( checker) )
109- }
44+ . map_err ( |_| Error :: Unavailable ) ?;
11045
111- unsafe fn wide_ptr_to_string ( p : * mut u16 ) -> Option < String > {
112- if p. is_null ( ) {
113- return None ;
114- }
115- let mut len = 0usize ;
116- while * p. add ( len) != 0 {
117- len += 1 ;
118- }
119- String :: from_utf16 ( std:: slice:: from_raw_parts ( p, len) ) . ok ( )
46+ let tag = HSTRING :: from ( bcp47) ;
47+ unsafe { factory. CreateSpellChecker ( & tag) } . map_err ( |_| Error :: Unavailable )
12048}
12149
12250#[ derive( Debug ) ]
12351pub struct Checker {
124- checker : ComPtr < ISpellChecker > ,
52+ checker : ISpellChecker ,
12553}
12654
12755impl Checker {
@@ -142,27 +70,25 @@ impl Checker {
14270 return Vec :: new ( ) ;
14371 }
14472
145- let wide = wide_string ( word) ;
146- let mut enum_str = ptr:: null_mut ( ) ;
147- let hr = unsafe { ( * self . checker ) . Suggest ( wide. as_ptr ( ) , & mut enum_str) } ;
148- if !SUCCEEDED ( hr) || enum_str. is_null ( ) {
73+ let Ok ( enum_str) = ( unsafe { self . checker . Suggest ( & HSTRING :: from ( word) ) } ) else {
14974 return Vec :: new ( ) ;
150- }
151- let enum_str = ComPtr :: new ( enum_str) ;
75+ } ;
15276
15377 let mut out = Vec :: new ( ) ;
15478 while out. len ( ) < MAX {
155- let mut item: * mut u16 = ptr :: null_mut ( ) ;
156- let mut fetched: ULONG = 0 ;
157- let hr = unsafe { ( * enum_str) . Next ( 1 , & mut item, & mut fetched) } ;
158- if hr == S_FALSE || fetched == 0 || item. is_null ( ) {
79+ let mut item = [ PWSTR :: null ( ) ] ;
80+ let mut fetched = 0u32 ;
81+ let hr = unsafe { enum_str. Next ( & mut item, Some ( & mut fetched) ) } ;
82+ if fetched == 0 || item[ 0 ] . is_null ( ) {
15983 break ;
16084 }
161- if let Some ( s) = unsafe { wide_ptr_to_string ( item) } {
85+ if let Ok ( s) = unsafe { item[ 0 ] . to_string ( ) } {
16286 out. push ( s) ;
16387 }
164- unsafe { CoTaskMemFree ( item as * mut _ ) } ;
165- if !SUCCEEDED ( hr) && hr != S_FALSE {
88+ unsafe {
89+ CoTaskMemFree ( Some ( item[ 0 ] . as_ptr ( ) as * const _ ) ) ;
90+ }
91+ if hr. is_err ( ) && hr != S_FALSE {
16692 break ;
16793 }
16894 }
@@ -180,41 +106,27 @@ impl Checker {
180106
181107 let original = text. to_owned ( ) ;
182108 let wide = wide_string ( text) ;
183- let mut errors = ptr:: null_mut ( ) ;
184- let hr = unsafe { ( * self . checker ) . ComprehensiveCheck ( wide. as_ptr ( ) , & mut errors) } ;
185- if !SUCCEEDED ( hr) {
186- return ErrorIter {
187- original,
188- text : wide,
189- iter : None ,
190- } ;
191- }
192- let errors = ComPtr :: new ( errors) ;
109+ let iter = unsafe { self . checker . ComprehensiveCheck ( & HSTRING :: from ( text) ) } . ok ( ) ;
193110
194111 ErrorIter {
195112 original,
196113 text : wide,
197- iter : Some ( errors ) ,
114+ iter,
198115 }
199116 }
200117
201118 pub fn ignore ( & mut self , word : & str ) {
202119 if word. is_empty ( ) {
203120 return ;
204121 }
205-
206- let word = wide_string ( word) ;
207- let hr = unsafe { ( * self . checker ) . Ignore ( word. as_ptr ( ) ) } ;
208- if !SUCCEEDED ( hr) {
209- return ;
210- }
122+ let _ = unsafe { self . checker . Ignore ( & HSTRING :: from ( word) ) } ;
211123 }
212124}
213125
214126struct ErrorIter {
215127 original : String ,
216128 text : Vec < u16 > ,
217- iter : Option < ComPtr < IEnumSpellingError > > ,
129+ iter : Option < IEnumSpellingError > ,
218130}
219131
220132impl Iterator for ErrorIter {
@@ -223,35 +135,25 @@ impl Iterator for ErrorIter {
223135 fn next ( & mut self ) -> Option < SpellingError > {
224136 let iter = self . iter . as_ref ( ) ?;
225137
226- let mut err = ptr:: null_mut ( ) ;
227- if unsafe { ( * iter) . Next ( & mut err) } != S_FALSE {
228- let err = ComPtr :: new ( err) ;
229-
230- let mut start = 0 ;
231- let mut length = 0 ;
232-
233- unsafe {
234- ( * err) . get_Length ( & mut length) ;
235- ( * err) . get_StartIndex ( & mut start) ;
236- }
237-
238- let utf16_start = start as usize ;
239- let utf16_len = length as usize ;
138+ let mut err: Option < ISpellingError > = None ;
139+ let hr = unsafe { iter. Next ( & mut err) } ;
140+ if hr == S_FALSE {
141+ return None ;
142+ }
143+ let err = err?;
240144
241- let err_text =
242- String :: from_utf16 ( & self . text [ utf16_start..utf16_start + utf16_len ] ) . ok ( ) ?;
145+ let start = unsafe { err . StartIndex ( ) } . ok ( ) ? as usize ;
146+ let length = unsafe { err . Length ( ) } . ok ( ) ? as usize ;
243147
244- let byte_start = utf16_offset_to_utf8 ( & self . original , utf16_start) ;
245- let byte_end = utf16_offset_to_utf8 ( & self . original , utf16_start + utf16_len) ;
148+ let err_text = String :: from_utf16 ( & self . text [ start..start + length] ) . ok ( ) ?;
149+ let byte_start = utf16_offset_to_utf8 ( & self . original , start) ;
150+ let byte_end = utf16_offset_to_utf8 ( & self . original , start + length) ;
246151
247- return Some ( SpellingError {
248- text : err_text,
249- start : byte_start,
250- end : byte_end,
251- } ) ;
252- } else {
253- None
254- }
152+ Some ( SpellingError {
153+ text : err_text,
154+ start : byte_start,
155+ end : byte_end,
156+ } )
255157 }
256158}
257159
0 commit comments