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