1 /*
2 * ITfCategoryMgr implementation
3 *
4 * Copyright 2009 Aric Stewart, CodeWeavers
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22 #ifdef __REACTOS__
23 #include <wchar.h>
24 #endif
25
26 #define COBJMACROS
27
28 #include "wine/debug.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #include "shlwapi.h"
34 #include "winerror.h"
35 #include "objbase.h"
36
37
38 #include "msctf.h"
39 #include "msctf_internal.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
42
43 typedef struct tagCategoryMgr {
44 ITfCategoryMgr ITfCategoryMgr_iface;
45 LONG refCount;
46 } CategoryMgr;
47
impl_from_ITfCategoryMgr(ITfCategoryMgr * iface)48 static inline CategoryMgr *impl_from_ITfCategoryMgr(ITfCategoryMgr *iface)
49 {
50 return CONTAINING_RECORD(iface, CategoryMgr, ITfCategoryMgr_iface);
51 }
52
CategoryMgr_Destructor(CategoryMgr * This)53 static void CategoryMgr_Destructor(CategoryMgr *This)
54 {
55 TRACE("destroying %p\n", This);
56 HeapFree(GetProcessHeap(),0,This);
57 }
58
CategoryMgr_QueryInterface(ITfCategoryMgr * iface,REFIID iid,LPVOID * ppvOut)59 static HRESULT WINAPI CategoryMgr_QueryInterface(ITfCategoryMgr *iface, REFIID iid, LPVOID *ppvOut)
60 {
61 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
62 *ppvOut = NULL;
63
64 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCategoryMgr))
65 {
66 *ppvOut = &This->ITfCategoryMgr_iface;
67 }
68
69 if (*ppvOut)
70 {
71 ITfCategoryMgr_AddRef(iface);
72 return S_OK;
73 }
74
75 WARN("unsupported interface: %s\n", debugstr_guid(iid));
76 return E_NOINTERFACE;
77 }
78
CategoryMgr_AddRef(ITfCategoryMgr * iface)79 static ULONG WINAPI CategoryMgr_AddRef(ITfCategoryMgr *iface)
80 {
81 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
82 return InterlockedIncrement(&This->refCount);
83 }
84
CategoryMgr_Release(ITfCategoryMgr * iface)85 static ULONG WINAPI CategoryMgr_Release(ITfCategoryMgr *iface)
86 {
87 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
88 ULONG ret;
89
90 ret = InterlockedDecrement(&This->refCount);
91 if (ret == 0)
92 CategoryMgr_Destructor(This);
93 return ret;
94 }
95
96 /*****************************************************
97 * ITfCategoryMgr functions
98 *****************************************************/
99
CategoryMgr_RegisterCategory(ITfCategoryMgr * iface,REFCLSID rclsid,REFGUID rcatid,REFGUID rguid)100 static HRESULT WINAPI CategoryMgr_RegisterCategory ( ITfCategoryMgr *iface,
101 REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
102 {
103 WCHAR fullkey[110];
104 WCHAR buf[39];
105 WCHAR buf2[39];
106 ULONG res;
107 HKEY tipkey,catkey,itmkey;
108 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
109
110 static const WCHAR ctg[] = {'C','a','t','e','g','o','r','y',0};
111 static const WCHAR itm[] = {'I','t','e','m',0};
112 static const WCHAR fmt[] = {'%','s','\\','%','s',0};
113 static const WCHAR fmt2[] = {'%','s','\\','%','s','\\','%','s','\\','%','s',0};
114
115 TRACE("(%p) %s %s %s\n",This,debugstr_guid(rclsid), debugstr_guid(rcatid), debugstr_guid(rguid));
116
117 StringFromGUID2(rclsid, buf, 39);
118 swprintf(fullkey,fmt,szwSystemTIPKey,buf);
119
120 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
121 &tipkey ) != ERROR_SUCCESS)
122 return E_FAIL;
123
124 StringFromGUID2(rcatid, buf, 39);
125 StringFromGUID2(rguid, buf2, 39);
126 swprintf(fullkey,fmt2,ctg,ctg,buf,buf2);
127
128 res = RegCreateKeyExW(tipkey, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
129 NULL, &catkey, NULL);
130 RegCloseKey(catkey);
131
132 if (!res)
133 {
134 swprintf(fullkey,fmt2,ctg,itm,buf2,buf);
135 res = RegCreateKeyExW(tipkey, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
136 NULL, &itmkey, NULL);
137
138 RegCloseKey(itmkey);
139 }
140
141 RegCloseKey(tipkey);
142
143 if (!res)
144 return S_OK;
145 else
146 return E_FAIL;
147 }
148
CategoryMgr_UnregisterCategory(ITfCategoryMgr * iface,REFCLSID rclsid,REFGUID rcatid,REFGUID rguid)149 static HRESULT WINAPI CategoryMgr_UnregisterCategory ( ITfCategoryMgr *iface,
150 REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
151 {
152 WCHAR fullkey[110];
153 WCHAR buf[39];
154 WCHAR buf2[39];
155 HKEY tipkey;
156 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
157
158 static const WCHAR ctg[] = {'C','a','t','e','g','o','r','y',0};
159 static const WCHAR itm[] = {'I','t','e','m',0};
160 static const WCHAR fmt[] = {'%','s','\\','%','s',0};
161 static const WCHAR fmt2[] = {'%','s','\\','%','s','\\','%','s','\\','%','s',0};
162
163 TRACE("(%p) %s %s %s\n",This,debugstr_guid(rclsid), debugstr_guid(rcatid), debugstr_guid(rguid));
164
165 StringFromGUID2(rclsid, buf, 39);
166 swprintf(fullkey,fmt,szwSystemTIPKey,buf);
167
168 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
169 &tipkey ) != ERROR_SUCCESS)
170 return E_FAIL;
171
172 StringFromGUID2(rcatid, buf, 39);
173 StringFromGUID2(rguid, buf2, 39);
174 swprintf(fullkey,fmt2,ctg,ctg,buf,buf2);
175 RegDeleteTreeW(tipkey, fullkey);
176 swprintf(fullkey,fmt2,ctg,itm,buf2,buf);
177 RegDeleteTreeW(tipkey, fullkey);
178
179 RegCloseKey(tipkey);
180 return S_OK;
181 }
182
CategoryMgr_EnumCategoriesInItem(ITfCategoryMgr * iface,REFGUID rguid,IEnumGUID ** ppEnum)183 static HRESULT WINAPI CategoryMgr_EnumCategoriesInItem ( ITfCategoryMgr *iface,
184 REFGUID rguid, IEnumGUID **ppEnum)
185 {
186 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
187 FIXME("STUB:(%p)\n",This);
188 return E_NOTIMPL;
189 }
190
CategoryMgr_EnumItemsInCategory(ITfCategoryMgr * iface,REFGUID rcatid,IEnumGUID ** ppEnum)191 static HRESULT WINAPI CategoryMgr_EnumItemsInCategory ( ITfCategoryMgr *iface,
192 REFGUID rcatid, IEnumGUID **ppEnum)
193 {
194 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
195 FIXME("STUB:(%p)\n",This);
196 return E_NOTIMPL;
197 }
198
CategoryMgr_FindClosestCategory(ITfCategoryMgr * iface,REFGUID rguid,GUID * pcatid,const GUID ** ppcatidList,ULONG ulCount)199 static HRESULT WINAPI CategoryMgr_FindClosestCategory ( ITfCategoryMgr *iface,
200 REFGUID rguid, GUID *pcatid, const GUID **ppcatidList, ULONG ulCount)
201 {
202 static const WCHAR fmt[] = { '%','s','\\','%','s','\\','C','a','t','e','g','o','r','y','\\','I','t','e','m','\\','%','s',0};
203
204 WCHAR fullkey[120];
205 WCHAR buf[39];
206 HKEY key;
207 HRESULT hr = S_FALSE;
208 INT index = 0;
209 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
210
211 TRACE("(%p)\n",This);
212
213 if (!pcatid || (ulCount && ppcatidList == NULL))
214 return E_INVALIDARG;
215
216 StringFromGUID2(rguid, buf, 39);
217 swprintf(fullkey,fmt,szwSystemTIPKey,buf,buf);
218 *pcatid = GUID_NULL;
219
220 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ, &key ) !=
221 ERROR_SUCCESS)
222 return S_FALSE;
223
224 while (1)
225 {
226 HRESULT hr2;
227 ULONG res;
228 GUID guid;
229 WCHAR catid[39];
230 DWORD cName;
231
232 cName = 39;
233 res = RegEnumKeyExW(key, index, catid, &cName, NULL, NULL, NULL, NULL);
234 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
235 index ++;
236
237 hr2 = CLSIDFromString(catid, &guid);
238 if (FAILED(hr2)) continue;
239
240 if (ulCount)
241 {
242 ULONG j;
243 BOOL found = FALSE;
244 for (j = 0; j < ulCount; j++)
245 if (IsEqualGUID(&guid, ppcatidList[j]))
246 {
247 found = TRUE;
248 *pcatid = guid;
249 hr = S_OK;
250 break;
251 }
252 if (found) break;
253 }
254 else
255 {
256 *pcatid = guid;
257 hr = S_OK;
258 break;
259 }
260 }
261
262 return hr;
263 }
264
CategoryMgr_RegisterGUIDDescription(ITfCategoryMgr * iface,REFCLSID rclsid,REFGUID rguid,const WCHAR * pchDesc,ULONG cch)265 static HRESULT WINAPI CategoryMgr_RegisterGUIDDescription (
266 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid,
267 const WCHAR *pchDesc, ULONG cch)
268 {
269 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
270 FIXME("STUB:(%p)\n",This);
271 return E_NOTIMPL;
272 }
273
CategoryMgr_UnregisterGUIDDescription(ITfCategoryMgr * iface,REFCLSID rclsid,REFGUID rguid)274 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDescription (
275 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid)
276 {
277 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
278 FIXME("STUB:(%p)\n",This);
279 return E_NOTIMPL;
280 }
281
CategoryMgr_GetGUIDDescription(ITfCategoryMgr * iface,REFGUID rguid,BSTR * pbstrDesc)282 static HRESULT WINAPI CategoryMgr_GetGUIDDescription ( ITfCategoryMgr *iface,
283 REFGUID rguid, BSTR *pbstrDesc)
284 {
285 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
286 FIXME("STUB:(%p)\n",This);
287 return E_NOTIMPL;
288 }
289
CategoryMgr_RegisterGUIDDWORD(ITfCategoryMgr * iface,REFCLSID rclsid,REFGUID rguid,DWORD dw)290 static HRESULT WINAPI CategoryMgr_RegisterGUIDDWORD ( ITfCategoryMgr *iface,
291 REFCLSID rclsid, REFGUID rguid, DWORD dw)
292 {
293 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
294 FIXME("STUB:(%p)\n",This);
295 return E_NOTIMPL;
296 }
297
CategoryMgr_UnregisterGUIDDWORD(ITfCategoryMgr * iface,REFCLSID rclsid,REFGUID rguid)298 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDWORD ( ITfCategoryMgr *iface,
299 REFCLSID rclsid, REFGUID rguid)
300 {
301 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
302 FIXME("STUB:(%p)\n",This);
303 return E_NOTIMPL;
304 }
305
CategoryMgr_GetGUIDDWORD(ITfCategoryMgr * iface,REFGUID rguid,DWORD * pdw)306 static HRESULT WINAPI CategoryMgr_GetGUIDDWORD ( ITfCategoryMgr *iface,
307 REFGUID rguid, DWORD *pdw)
308 {
309 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
310 FIXME("STUB:(%p)\n",This);
311 return E_NOTIMPL;
312 }
313
CategoryMgr_RegisterGUID(ITfCategoryMgr * iface,REFGUID rguid,TfGuidAtom * pguidatom)314 static HRESULT WINAPI CategoryMgr_RegisterGUID ( ITfCategoryMgr *iface,
315 REFGUID rguid, TfGuidAtom *pguidatom
316 )
317 {
318 DWORD index;
319 GUID *checkguid;
320 DWORD id;
321 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
322
323 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),pguidatom);
324
325 if (!pguidatom)
326 return E_INVALIDARG;
327
328 index = 0;
329 do {
330 id = enumerate_Cookie(COOKIE_MAGIC_GUIDATOM,&index);
331 if (id && IsEqualGUID(rguid,get_Cookie_data(id)))
332 {
333 *pguidatom = id;
334 return S_OK;
335 }
336 } while(id);
337
338 checkguid = HeapAlloc(GetProcessHeap(),0,sizeof(GUID));
339 *checkguid = *rguid;
340 id = generate_Cookie(COOKIE_MAGIC_GUIDATOM,checkguid);
341
342 if (!id)
343 {
344 HeapFree(GetProcessHeap(),0,checkguid);
345 return E_FAIL;
346 }
347
348 *pguidatom = id;
349
350 return S_OK;
351 }
352
CategoryMgr_GetGUID(ITfCategoryMgr * iface,TfGuidAtom guidatom,GUID * pguid)353 static HRESULT WINAPI CategoryMgr_GetGUID ( ITfCategoryMgr *iface,
354 TfGuidAtom guidatom, GUID *pguid)
355 {
356 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
357
358 TRACE("(%p) %i\n",This,guidatom);
359
360 if (!pguid)
361 return E_INVALIDARG;
362
363 *pguid = GUID_NULL;
364
365 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM)
366 *pguid = *((REFGUID)get_Cookie_data(guidatom));
367
368 return S_OK;
369 }
370
CategoryMgr_IsEqualTfGuidAtom(ITfCategoryMgr * iface,TfGuidAtom guidatom,REFGUID rguid,BOOL * pfEqual)371 static HRESULT WINAPI CategoryMgr_IsEqualTfGuidAtom ( ITfCategoryMgr *iface,
372 TfGuidAtom guidatom, REFGUID rguid, BOOL *pfEqual)
373 {
374 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
375
376 TRACE("(%p) %i %s %p\n",This,guidatom,debugstr_guid(rguid),pfEqual);
377
378 if (!pfEqual)
379 return E_INVALIDARG;
380
381 *pfEqual = FALSE;
382 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM)
383 {
384 if (IsEqualGUID(rguid,get_Cookie_data(guidatom)))
385 *pfEqual = TRUE;
386 }
387
388 return S_OK;
389 }
390
391
392 static const ITfCategoryMgrVtbl CategoryMgrVtbl =
393 {
394 CategoryMgr_QueryInterface,
395 CategoryMgr_AddRef,
396 CategoryMgr_Release,
397 CategoryMgr_RegisterCategory,
398 CategoryMgr_UnregisterCategory,
399 CategoryMgr_EnumCategoriesInItem,
400 CategoryMgr_EnumItemsInCategory,
401 CategoryMgr_FindClosestCategory,
402 CategoryMgr_RegisterGUIDDescription,
403 CategoryMgr_UnregisterGUIDDescription,
404 CategoryMgr_GetGUIDDescription,
405 CategoryMgr_RegisterGUIDDWORD,
406 CategoryMgr_UnregisterGUIDDWORD,
407 CategoryMgr_GetGUIDDWORD,
408 CategoryMgr_RegisterGUID,
409 CategoryMgr_GetGUID,
410 CategoryMgr_IsEqualTfGuidAtom
411 };
412
CategoryMgr_Constructor(IUnknown * pUnkOuter,IUnknown ** ppOut)413 HRESULT CategoryMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
414 {
415 CategoryMgr *This;
416 if (pUnkOuter)
417 return CLASS_E_NOAGGREGATION;
418
419 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CategoryMgr));
420 if (This == NULL)
421 return E_OUTOFMEMORY;
422
423 This->ITfCategoryMgr_iface.lpVtbl = &CategoryMgrVtbl;
424 This->refCount = 1;
425
426 *ppOut = (IUnknown *)&This->ITfCategoryMgr_iface;
427 TRACE("returning %p\n", *ppOut);
428 return S_OK;
429 }
430