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