[MSCTF]
[reactos.git] / reactos / dll / win32 / msctf / categorymgr.c
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 "msctf_internal.h"
22
23 typedef struct tagCategoryMgr {
24 ITfCategoryMgr ITfCategoryMgr_iface;
25 LONG refCount;
26 } CategoryMgr;
27
28 static inline CategoryMgr *impl_from_ITfCategoryMgr(ITfCategoryMgr *iface)
29 {
30 return CONTAINING_RECORD(iface, CategoryMgr, ITfCategoryMgr_iface);
31 }
32
33 static void CategoryMgr_Destructor(CategoryMgr *This)
34 {
35 TRACE("destroying %p\n", This);
36 HeapFree(GetProcessHeap(),0,This);
37 }
38
39 static HRESULT WINAPI CategoryMgr_QueryInterface(ITfCategoryMgr *iface, REFIID iid, LPVOID *ppvOut)
40 {
41 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
42 *ppvOut = NULL;
43
44 if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfCategoryMgr))
45 {
46 *ppvOut = &This->ITfCategoryMgr_iface;
47 }
48
49 if (*ppvOut)
50 {
51 ITfCategoryMgr_AddRef(iface);
52 return S_OK;
53 }
54
55 WARN("unsupported interface: %s\n", debugstr_guid(iid));
56 return E_NOINTERFACE;
57 }
58
59 static ULONG WINAPI CategoryMgr_AddRef(ITfCategoryMgr *iface)
60 {
61 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
62 return InterlockedIncrement(&This->refCount);
63 }
64
65 static ULONG WINAPI CategoryMgr_Release(ITfCategoryMgr *iface)
66 {
67 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
68 ULONG ret;
69
70 ret = InterlockedDecrement(&This->refCount);
71 if (ret == 0)
72 CategoryMgr_Destructor(This);
73 return ret;
74 }
75
76 /*****************************************************
77 * ITfCategoryMgr functions
78 *****************************************************/
79
80 static HRESULT WINAPI CategoryMgr_RegisterCategory ( ITfCategoryMgr *iface,
81 REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
82 {
83 WCHAR fullkey[110];
84 WCHAR buf[39];
85 WCHAR buf2[39];
86 ULONG res;
87 HKEY tipkey,catkey,itmkey;
88 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
89
90 static const WCHAR ctg[] = {'C','a','t','e','g','o','r','y',0};
91 static const WCHAR itm[] = {'I','t','e','m',0};
92 static const WCHAR fmt[] = {'%','s','\\','%','s',0};
93 static const WCHAR fmt2[] = {'%','s','\\','%','s','\\','%','s','\\','%','s',0};
94
95 TRACE("(%p) %s %s %s\n",This,debugstr_guid(rclsid), debugstr_guid(rcatid), debugstr_guid(rguid));
96
97 StringFromGUID2(rclsid, buf, 39);
98 sprintfW(fullkey,fmt,szwSystemTIPKey,buf);
99
100 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
101 &tipkey ) != ERROR_SUCCESS)
102 return E_FAIL;
103
104 StringFromGUID2(rcatid, buf, 39);
105 StringFromGUID2(rguid, buf2, 39);
106 sprintfW(fullkey,fmt2,ctg,ctg,buf,buf2);
107
108 res = RegCreateKeyExW(tipkey, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
109 NULL, &catkey, NULL);
110 RegCloseKey(catkey);
111
112 if (!res)
113 {
114 sprintfW(fullkey,fmt2,ctg,itm,buf2,buf);
115 res = RegCreateKeyExW(tipkey, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
116 NULL, &itmkey, NULL);
117
118 RegCloseKey(itmkey);
119 }
120
121 RegCloseKey(tipkey);
122
123 if (!res)
124 return S_OK;
125 else
126 return E_FAIL;
127 }
128
129 static HRESULT WINAPI CategoryMgr_UnregisterCategory ( ITfCategoryMgr *iface,
130 REFCLSID rclsid, REFGUID rcatid, REFGUID rguid)
131 {
132 WCHAR fullkey[110];
133 WCHAR buf[39];
134 WCHAR buf2[39];
135 HKEY tipkey;
136 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
137
138 static const WCHAR ctg[] = {'C','a','t','e','g','o','r','y',0};
139 static const WCHAR itm[] = {'I','t','e','m',0};
140 static const WCHAR fmt[] = {'%','s','\\','%','s',0};
141 static const WCHAR fmt2[] = {'%','s','\\','%','s','\\','%','s','\\','%','s',0};
142
143 TRACE("(%p) %s %s %s\n",This,debugstr_guid(rclsid), debugstr_guid(rcatid), debugstr_guid(rguid));
144
145 StringFromGUID2(rclsid, buf, 39);
146 sprintfW(fullkey,fmt,szwSystemTIPKey,buf);
147
148 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
149 &tipkey ) != ERROR_SUCCESS)
150 return E_FAIL;
151
152 StringFromGUID2(rcatid, buf, 39);
153 StringFromGUID2(rguid, buf2, 39);
154 sprintfW(fullkey,fmt2,ctg,ctg,buf,buf2);
155
156 sprintfW(fullkey,fmt2,ctg,itm,buf2,buf);
157 SHDeleteKeyW(tipkey, fullkey);
158 sprintfW(fullkey,fmt2,ctg,itm,buf2,buf);
159 SHDeleteKeyW(tipkey, fullkey);
160
161 RegCloseKey(tipkey);
162 return S_OK;
163 }
164
165 static HRESULT WINAPI CategoryMgr_EnumCategoriesInItem ( ITfCategoryMgr *iface,
166 REFGUID rguid, IEnumGUID **ppEnum)
167 {
168 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
169 FIXME("STUB:(%p)\n",This);
170 return E_NOTIMPL;
171 }
172
173 static HRESULT WINAPI CategoryMgr_EnumItemsInCategory ( ITfCategoryMgr *iface,
174 REFGUID rcatid, IEnumGUID **ppEnum)
175 {
176 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
177 FIXME("STUB:(%p)\n",This);
178 return E_NOTIMPL;
179 }
180
181 static HRESULT WINAPI CategoryMgr_FindClosestCategory ( ITfCategoryMgr *iface,
182 REFGUID rguid, GUID *pcatid, const GUID **ppcatidList, ULONG ulCount)
183 {
184 static const WCHAR fmt[] = { '%','s','\\','%','s','\\','C','a','t','e','g','o','r','y','\\','I','t','e','m','\\','%','s',0};
185
186 WCHAR fullkey[120];
187 WCHAR buf[39];
188 HKEY key;
189 HRESULT hr = S_FALSE;
190 INT index = 0;
191 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
192
193 TRACE("(%p)\n",This);
194
195 if (!pcatid || (ulCount && ppcatidList == NULL))
196 return E_INVALIDARG;
197
198 StringFromGUID2(rguid, buf, 39);
199 sprintfW(fullkey,fmt,szwSystemTIPKey,buf,buf);
200 *pcatid = GUID_NULL;
201
202 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ, &key ) !=
203 ERROR_SUCCESS)
204 return S_FALSE;
205
206 while (1)
207 {
208 HRESULT hr2;
209 ULONG res;
210 GUID guid;
211 WCHAR catid[39];
212 DWORD cName;
213
214 cName = 39;
215 res = RegEnumKeyExW(key, index, catid, &cName, NULL, NULL, NULL, NULL);
216 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
217 index ++;
218
219 hr2 = CLSIDFromString(catid, &guid);
220 if (FAILED(hr2)) continue;
221
222 if (ulCount)
223 {
224 ULONG j;
225 BOOL found = FALSE;
226 for (j = 0; j < ulCount; j++)
227 if (IsEqualGUID(&guid, ppcatidList[j]))
228 {
229 found = TRUE;
230 *pcatid = guid;
231 hr = S_OK;
232 break;
233 }
234 if (found) break;
235 }
236 else
237 {
238 *pcatid = guid;
239 hr = S_OK;
240 break;
241 }
242 }
243
244 return hr;
245 }
246
247 static HRESULT WINAPI CategoryMgr_RegisterGUIDDescription (
248 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid,
249 const WCHAR *pchDesc, ULONG cch)
250 {
251 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
252 FIXME("STUB:(%p)\n",This);
253 return E_NOTIMPL;
254 }
255
256 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDescription (
257 ITfCategoryMgr *iface, REFCLSID rclsid, REFGUID rguid)
258 {
259 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
260 FIXME("STUB:(%p)\n",This);
261 return E_NOTIMPL;
262 }
263
264 static HRESULT WINAPI CategoryMgr_GetGUIDDescription ( ITfCategoryMgr *iface,
265 REFGUID rguid, BSTR *pbstrDesc)
266 {
267 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
268 FIXME("STUB:(%p)\n",This);
269 return E_NOTIMPL;
270 }
271
272 static HRESULT WINAPI CategoryMgr_RegisterGUIDDWORD ( ITfCategoryMgr *iface,
273 REFCLSID rclsid, REFGUID rguid, DWORD dw)
274 {
275 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
276 FIXME("STUB:(%p)\n",This);
277 return E_NOTIMPL;
278 }
279
280 static HRESULT WINAPI CategoryMgr_UnregisterGUIDDWORD ( ITfCategoryMgr *iface,
281 REFCLSID rclsid, REFGUID rguid)
282 {
283 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
284 FIXME("STUB:(%p)\n",This);
285 return E_NOTIMPL;
286 }
287
288 static HRESULT WINAPI CategoryMgr_GetGUIDDWORD ( ITfCategoryMgr *iface,
289 REFGUID rguid, DWORD *pdw)
290 {
291 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
292 FIXME("STUB:(%p)\n",This);
293 return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI CategoryMgr_RegisterGUID ( ITfCategoryMgr *iface,
297 REFGUID rguid, TfGuidAtom *pguidatom
298 )
299 {
300 DWORD index;
301 GUID *checkguid;
302 DWORD id;
303 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
304
305 TRACE("(%p) %s %p\n",This,debugstr_guid(rguid),pguidatom);
306
307 if (!pguidatom)
308 return E_INVALIDARG;
309
310 index = 0;
311 do {
312 id = enumerate_Cookie(COOKIE_MAGIC_GUIDATOM,&index);
313 if (id && IsEqualGUID(rguid,get_Cookie_data(id)))
314 {
315 *pguidatom = id;
316 return S_OK;
317 }
318 } while(id);
319
320 checkguid = HeapAlloc(GetProcessHeap(),0,sizeof(GUID));
321 *checkguid = *rguid;
322 id = generate_Cookie(COOKIE_MAGIC_GUIDATOM,checkguid);
323
324 if (!id)
325 {
326 HeapFree(GetProcessHeap(),0,checkguid);
327 return E_FAIL;
328 }
329
330 *pguidatom = id;
331
332 return S_OK;
333 }
334
335 static HRESULT WINAPI CategoryMgr_GetGUID ( ITfCategoryMgr *iface,
336 TfGuidAtom guidatom, GUID *pguid)
337 {
338 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
339
340 TRACE("(%p) %i\n",This,guidatom);
341
342 if (!pguid)
343 return E_INVALIDARG;
344
345 *pguid = GUID_NULL;
346
347 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM)
348 *pguid = *((REFGUID)get_Cookie_data(guidatom));
349
350 return S_OK;
351 }
352
353 static HRESULT WINAPI CategoryMgr_IsEqualTfGuidAtom ( ITfCategoryMgr *iface,
354 TfGuidAtom guidatom, REFGUID rguid, BOOL *pfEqual)
355 {
356 CategoryMgr *This = impl_from_ITfCategoryMgr(iface);
357
358 TRACE("(%p) %i %s %p\n",This,guidatom,debugstr_guid(rguid),pfEqual);
359
360 if (!pfEqual)
361 return E_INVALIDARG;
362
363 *pfEqual = FALSE;
364 if (get_Cookie_magic(guidatom) == COOKIE_MAGIC_GUIDATOM)
365 {
366 if (IsEqualGUID(rguid,get_Cookie_data(guidatom)))
367 *pfEqual = TRUE;
368 }
369
370 return S_OK;
371 }
372
373
374 static const ITfCategoryMgrVtbl CategoryMgrVtbl =
375 {
376 CategoryMgr_QueryInterface,
377 CategoryMgr_AddRef,
378 CategoryMgr_Release,
379 CategoryMgr_RegisterCategory,
380 CategoryMgr_UnregisterCategory,
381 CategoryMgr_EnumCategoriesInItem,
382 CategoryMgr_EnumItemsInCategory,
383 CategoryMgr_FindClosestCategory,
384 CategoryMgr_RegisterGUIDDescription,
385 CategoryMgr_UnregisterGUIDDescription,
386 CategoryMgr_GetGUIDDescription,
387 CategoryMgr_RegisterGUIDDWORD,
388 CategoryMgr_UnregisterGUIDDWORD,
389 CategoryMgr_GetGUIDDWORD,
390 CategoryMgr_RegisterGUID,
391 CategoryMgr_GetGUID,
392 CategoryMgr_IsEqualTfGuidAtom
393 };
394
395 HRESULT CategoryMgr_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
396 {
397 CategoryMgr *This;
398 if (pUnkOuter)
399 return CLASS_E_NOAGGREGATION;
400
401 This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CategoryMgr));
402 if (This == NULL)
403 return E_OUTOFMEMORY;
404
405 This->ITfCategoryMgr_iface.lpVtbl = &CategoryMgrVtbl;
406 This->refCount = 1;
407
408 *ppOut = (IUnknown *)&This->ITfCategoryMgr_iface;
409 TRACE("returning %p\n", *ppOut);
410 return S_OK;
411 }