rpcrt4: Free the resources associated with server protocol sequences on DLL unload.
[wine] / dlls / msctf / inputprocessor.c
1 /*
2  *  ITfInputProcessorProfiles 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 static const WCHAR szwLngp[] = {'L','a','n','g','u','a','g','e','P','r','o','f','i','l','e',0};
44 static const WCHAR szwEnabled[] = {'E','n','a','b','l','e','d',0};
45 static const WCHAR szwTipfmt[] = {'%','s','\\','%','s',0};
46 static const WCHAR szwFullLangfmt[] = {'%','s','\\','%','s','\\','%','s','\\','0','x','%','0','8','x','\\','%','s',0};
47
48 typedef struct tagInputProcessorProfiles {
49     const ITfInputProcessorProfilesVtbl *InputProcessorProfilesVtbl;
50     LONG refCount;
51
52     LANGID  currentLanguage;
53 } InputProcessorProfiles;
54
55 typedef struct tagProfilesEnumGuid {
56     const IEnumGUIDVtbl *Vtbl;
57     LONG refCount;
58
59     HKEY key;
60     DWORD next_index;
61 } ProfilesEnumGuid;
62
63 typedef struct tagEnumTfLanguageProfiles {
64     const IEnumTfLanguageProfilesVtbl *Vtbl;
65     LONG refCount;
66
67     HKEY    tipkey;
68     DWORD   tip_index;
69     WCHAR   szwCurrentClsid[39];
70
71     HKEY    langkey;
72     DWORD   lang_index;
73
74     LANGID  langid;
75     ITfCategoryMgr *catmgr;
76 } EnumTfLanguageProfiles;
77
78 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut);
79 static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut);
80
81 static void InputProcessorProfiles_Destructor(InputProcessorProfiles *This)
82 {
83     TRACE("destroying %p\n", This);
84     HeapFree(GetProcessHeap(),0,This);
85 }
86
87 static void add_userkey( REFCLSID rclsid, LANGID langid,
88                                 REFGUID guidProfile)
89 {
90     HKEY key;
91     WCHAR buf[39];
92     WCHAR buf2[39];
93     WCHAR fullkey[168];
94     DWORD disposition = 0;
95     ULONG res;
96
97     TRACE("\n");
98
99     StringFromGUID2(rclsid, buf, 39);
100     StringFromGUID2(guidProfile, buf2, 39);
101     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
102
103     res = RegCreateKeyExW(HKEY_CURRENT_USER,fullkey, 0, NULL, 0,
104                    KEY_READ | KEY_WRITE, NULL, &key, &disposition);
105
106     if (!res && disposition == REG_CREATED_NEW_KEY)
107     {
108         DWORD zero = 0x0;
109         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
110     }
111
112     if (!res)
113         RegCloseKey(key);
114 }
115
116 static HRESULT WINAPI InputProcessorProfiles_QueryInterface(ITfInputProcessorProfiles *iface, REFIID iid, LPVOID *ppvOut)
117 {
118     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
119     *ppvOut = NULL;
120
121     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfInputProcessorProfiles))
122     {
123         *ppvOut = This;
124     }
125
126     if (*ppvOut)
127     {
128         IUnknown_AddRef(iface);
129         return S_OK;
130     }
131
132     WARN("unsupported interface: %s\n", debugstr_guid(iid));
133     return E_NOINTERFACE;
134 }
135
136 static ULONG WINAPI InputProcessorProfiles_AddRef(ITfInputProcessorProfiles *iface)
137 {
138     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
139     return InterlockedIncrement(&This->refCount);
140 }
141
142 static ULONG WINAPI InputProcessorProfiles_Release(ITfInputProcessorProfiles *iface)
143 {
144     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
145     ULONG ret;
146
147     ret = InterlockedDecrement(&This->refCount);
148     if (ret == 0)
149         InputProcessorProfiles_Destructor(This);
150     return ret;
151 }
152
153 /*****************************************************
154  * ITfInputProcessorProfiles functions
155  *****************************************************/
156 static HRESULT WINAPI InputProcessorProfiles_Register(
157         ITfInputProcessorProfiles *iface, REFCLSID rclsid)
158 {
159     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
160     HKEY tipkey;
161     WCHAR buf[39];
162     WCHAR fullkey[68];
163
164     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
165
166     StringFromGUID2(rclsid, buf, 39);
167     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
168
169     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, NULL, 0,
170                     KEY_READ | KEY_WRITE, NULL, &tipkey, NULL) != ERROR_SUCCESS)
171         return E_FAIL;
172
173     RegCloseKey(tipkey);
174
175     return S_OK;
176 }
177
178 static HRESULT WINAPI InputProcessorProfiles_Unregister(
179         ITfInputProcessorProfiles *iface, REFCLSID rclsid)
180 {
181     WCHAR buf[39];
182     WCHAR fullkey[68];
183     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
184
185     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
186
187     StringFromGUID2(rclsid, buf, 39);
188     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
189
190     RegDeleteTreeW(HKEY_LOCAL_MACHINE, fullkey);
191     RegDeleteTreeW(HKEY_CURRENT_USER, fullkey);
192
193     return S_OK;
194 }
195
196 static HRESULT WINAPI InputProcessorProfiles_AddLanguageProfile(
197         ITfInputProcessorProfiles *iface, REFCLSID rclsid,
198         LANGID langid, REFGUID guidProfile, const WCHAR *pchDesc,
199         ULONG cchDesc, const WCHAR *pchIconFile, ULONG cchFile,
200         ULONG uIconIndex)
201 {
202     HKEY tipkey,fmtkey;
203     WCHAR buf[39];
204     WCHAR fullkey[100];
205     ULONG res;
206     DWORD disposition = 0;
207
208     static const WCHAR fmt2[] = {'%','s','\\','0','x','%','0','8','x','\\','%','s',0};
209     static const WCHAR desc[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
210     static const WCHAR icnf[] = {'I','c','o','n','F','i','l','e',0};
211     static const WCHAR icni[] = {'I','c','o','n','I','n','d','e','x',0};
212
213     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
214
215     TRACE("(%p) %s %x %s %s %s %i\n",This,debugstr_guid(rclsid), langid,
216             debugstr_guid(guidProfile), debugstr_wn(pchDesc,cchDesc),
217             debugstr_wn(pchIconFile,cchFile),uIconIndex);
218
219     StringFromGUID2(rclsid, buf, 39);
220     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
221
222     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
223                 &tipkey ) != ERROR_SUCCESS)
224         return E_FAIL;
225
226     StringFromGUID2(guidProfile, buf, 39);
227     sprintfW(fullkey,fmt2,szwLngp,langid,buf);
228
229     res = RegCreateKeyExW(tipkey,fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
230             NULL, &fmtkey, &disposition);
231
232     if (!res)
233     {
234         DWORD zero = 0x0;
235         RegSetValueExW(fmtkey, desc, 0, REG_SZ, (LPBYTE)pchDesc, cchDesc * sizeof(WCHAR));
236         RegSetValueExW(fmtkey, icnf, 0, REG_SZ, (LPBYTE)pchIconFile, cchFile * sizeof(WCHAR));
237         RegSetValueExW(fmtkey, icni, 0, REG_DWORD, (LPBYTE)&uIconIndex, sizeof(DWORD));
238         if (disposition == REG_CREATED_NEW_KEY)
239             RegSetValueExW(fmtkey, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
240         RegCloseKey(fmtkey);
241
242         add_userkey(rclsid, langid, guidProfile);
243     }
244     RegCloseKey(tipkey);
245
246     if (!res)
247         return S_OK;
248     else
249         return E_FAIL;
250 }
251
252 static HRESULT WINAPI InputProcessorProfiles_RemoveLanguageProfile(
253         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
254         REFGUID guidProfile)
255 {
256     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
257     FIXME("STUB:(%p)\n",This);
258     return E_NOTIMPL;
259 }
260
261 static HRESULT WINAPI InputProcessorProfiles_EnumInputProcessorInfo(
262         ITfInputProcessorProfiles *iface, IEnumGUID **ppEnum)
263 {
264     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
265     TRACE("(%p) %p\n",This,ppEnum);
266     return ProfilesEnumGuid_Constructor(ppEnum);
267 }
268
269 static HRESULT WINAPI InputProcessorProfiles_GetDefaultLanguageProfile(
270         ITfInputProcessorProfiles *iface, LANGID langid, REFGUID catid,
271         CLSID *pclsid, GUID *pguidProfile)
272 {
273     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
274     FIXME("STUB:(%p)\n",This);
275     return E_NOTIMPL;
276 }
277
278 static HRESULT WINAPI InputProcessorProfiles_SetDefaultLanguageProfile(
279         ITfInputProcessorProfiles *iface, LANGID langid, REFCLSID rclsid,
280         REFGUID guidProfiles)
281 {
282     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
283     FIXME("STUB:(%p)\n",This);
284     return E_NOTIMPL;
285 }
286
287 static HRESULT WINAPI InputProcessorProfiles_ActivateLanguageProfile(
288         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
289         REFGUID guidProfiles)
290 {
291     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
292     FIXME("STUB:(%p)\n",This);
293     return E_NOTIMPL;
294 }
295
296 static HRESULT WINAPI InputProcessorProfiles_GetActiveLanguageProfile(
297         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID *plangid,
298         GUID *pguidProfile)
299 {
300     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
301     FIXME("STUB:(%p)\n",This);
302     return E_NOTIMPL;
303 }
304
305 static HRESULT WINAPI InputProcessorProfiles_GetLanguageProfileDescription(
306         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
307         REFGUID guidProfile, BSTR *pbstrProfile)
308 {
309     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
310     FIXME("STUB:(%p)\n",This);
311     return E_NOTIMPL;
312 }
313
314 static HRESULT WINAPI InputProcessorProfiles_GetCurrentLanguage(
315         ITfInputProcessorProfiles *iface, LANGID *plangid)
316 {
317     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
318     TRACE("(%p) 0x%x\n",This,This->currentLanguage);
319
320     if (!plangid)
321         return E_INVALIDARG;
322
323     *plangid = This->currentLanguage;
324
325     return S_OK;
326 }
327
328 static HRESULT WINAPI InputProcessorProfiles_ChangeCurrentLanguage(
329         ITfInputProcessorProfiles *iface, LANGID langid)
330 {
331     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
332     FIXME("STUB:(%p)\n",This);
333     return E_NOTIMPL;
334 }
335
336 static HRESULT WINAPI InputProcessorProfiles_GetLanguageList(
337         ITfInputProcessorProfiles *iface, LANGID **ppLangId, ULONG *pulCount)
338 {
339     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
340     FIXME("STUB:(%p)\n",This);
341     return E_NOTIMPL;
342 }
343
344 static HRESULT WINAPI InputProcessorProfiles_EnumLanguageProfiles(
345         ITfInputProcessorProfiles *iface, LANGID langid,
346         IEnumTfLanguageProfiles **ppEnum)
347 {
348     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
349     TRACE("(%p) %x %p\n",This,langid,ppEnum);
350     return EnumTfLanguageProfiles_Constructor(langid, ppEnum);
351 }
352
353 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfile(
354         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
355         REFGUID guidProfile, BOOL fEnable)
356 {
357     HKEY key;
358     WCHAR buf[39];
359     WCHAR buf2[39];
360     WCHAR fullkey[168];
361     ULONG res;
362
363     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
364     TRACE("(%p) %s %x %s %i\n",This, debugstr_guid(rclsid), langid, debugstr_guid(guidProfile), fEnable);
365
366     StringFromGUID2(rclsid, buf, 39);
367     StringFromGUID2(guidProfile, buf2, 39);
368     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
369
370     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
371
372     if (!res)
373     {
374         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
375         RegCloseKey(key);
376     }
377     else
378         return E_FAIL;
379
380     return S_OK;
381 }
382
383 static HRESULT WINAPI InputProcessorProfiles_IsEnabledLanguageProfile(
384         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
385         REFGUID guidProfile, BOOL *pfEnable)
386 {
387     HKEY key;
388     WCHAR buf[39];
389     WCHAR buf2[39];
390     WCHAR fullkey[168];
391     ULONG res;
392
393     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
394     TRACE("(%p) %s, %i, %s, %p\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),pfEnable);
395
396     if (!pfEnable)
397         return E_INVALIDARG;
398
399     StringFromGUID2(rclsid, buf, 39);
400     StringFromGUID2(guidProfile, buf2, 39);
401     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
402
403     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
404
405     if (!res)
406     {
407         DWORD count = sizeof(DWORD);
408         res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
409         RegCloseKey(key);
410     }
411
412     if (res)  /* Try Default */
413     {
414         res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
415
416         if (!res)
417         {
418             DWORD count = sizeof(DWORD);
419             res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
420             RegCloseKey(key);
421         }
422     }
423
424     if (!res)
425         return S_OK;
426     else
427         return E_FAIL;
428 }
429
430 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfileByDefault(
431         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
432         REFGUID guidProfile, BOOL fEnable)
433 {
434     HKEY key;
435     WCHAR buf[39];
436     WCHAR buf2[39];
437     WCHAR fullkey[168];
438     ULONG res;
439
440     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
441     TRACE("(%p) %s %x %s %i\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),fEnable);
442
443     StringFromGUID2(rclsid, buf, 39);
444     StringFromGUID2(guidProfile, buf2, 39);
445     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
446
447     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
448
449     if (!res)
450     {
451         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
452         RegCloseKey(key);
453     }
454     else
455         return E_FAIL;
456
457     return S_OK;
458 }
459
460 static HRESULT WINAPI InputProcessorProfiles_SubstituteKeyboardLayout(
461         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
462         REFGUID guidProfile, HKL hKL)
463 {
464     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
465     FIXME("STUB:(%p)\n",This);
466     return E_NOTIMPL;
467 }
468
469
470 static const ITfInputProcessorProfilesVtbl InputProcessorProfiles_InputProcessorProfilesVtbl =
471 {
472     InputProcessorProfiles_QueryInterface,
473     InputProcessorProfiles_AddRef,
474     InputProcessorProfiles_Release,
475
476     InputProcessorProfiles_Register,
477     InputProcessorProfiles_Unregister,
478     InputProcessorProfiles_AddLanguageProfile,
479     InputProcessorProfiles_RemoveLanguageProfile,
480     InputProcessorProfiles_EnumInputProcessorInfo,
481     InputProcessorProfiles_GetDefaultLanguageProfile,
482     InputProcessorProfiles_SetDefaultLanguageProfile,
483     InputProcessorProfiles_ActivateLanguageProfile,
484     InputProcessorProfiles_GetActiveLanguageProfile,
485     InputProcessorProfiles_GetLanguageProfileDescription,
486     InputProcessorProfiles_GetCurrentLanguage,
487     InputProcessorProfiles_ChangeCurrentLanguage,
488     InputProcessorProfiles_GetLanguageList,
489     InputProcessorProfiles_EnumLanguageProfiles,
490     InputProcessorProfiles_EnableLanguageProfile,
491     InputProcessorProfiles_IsEnabledLanguageProfile,
492     InputProcessorProfiles_EnableLanguageProfileByDefault,
493     InputProcessorProfiles_SubstituteKeyboardLayout
494 };
495
496 HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
497 {
498     InputProcessorProfiles *This;
499     if (pUnkOuter)
500         return CLASS_E_NOAGGREGATION;
501
502     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputProcessorProfiles));
503     if (This == NULL)
504         return E_OUTOFMEMORY;
505
506     This->InputProcessorProfilesVtbl= &InputProcessorProfiles_InputProcessorProfilesVtbl;
507     This->refCount = 1;
508     This->currentLanguage = GetUserDefaultLCID();
509
510     TRACE("returning %p\n", This);
511     *ppOut = (IUnknown *)This;
512     return S_OK;
513 }
514
515 /**************************************************
516  * IEnumGUID implementaion for ITfInputProcessorProfiles::EnumInputProcessorInfo
517  **************************************************/
518 static void ProfilesEnumGuid_Destructor(ProfilesEnumGuid *This)
519 {
520     TRACE("destroying %p\n", This);
521     RegCloseKey(This->key);
522     HeapFree(GetProcessHeap(),0,This);
523 }
524
525 static HRESULT WINAPI ProfilesEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
526 {
527     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
528     *ppvOut = NULL;
529
530     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
531     {
532         *ppvOut = This;
533     }
534
535     if (*ppvOut)
536     {
537         IUnknown_AddRef(iface);
538         return S_OK;
539     }
540
541     WARN("unsupported interface: %s\n", debugstr_guid(iid));
542     return E_NOINTERFACE;
543 }
544
545 static ULONG WINAPI ProfilesEnumGuid_AddRef(IEnumGUID *iface)
546 {
547     ProfilesEnumGuid *This = (ProfilesEnumGuid*)iface;
548     return InterlockedIncrement(&This->refCount);
549 }
550
551 static ULONG WINAPI ProfilesEnumGuid_Release(IEnumGUID *iface)
552 {
553     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
554     ULONG ret;
555
556     ret = InterlockedDecrement(&This->refCount);
557     if (ret == 0)
558         ProfilesEnumGuid_Destructor(This);
559     return ret;
560 }
561
562 /*****************************************************
563  * IEnumGuid functions
564  *****************************************************/
565 static HRESULT WINAPI ProfilesEnumGuid_Next( LPENUMGUID iface,
566     ULONG celt, GUID *rgelt, ULONG *pceltFetched)
567 {
568     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
569     ULONG fetched = 0;
570
571     TRACE("(%p)\n",This);
572
573     if (rgelt == NULL) return E_POINTER;
574
575     if (This->key) while (fetched < celt)
576     {
577         LSTATUS res;
578         HRESULT hr;
579         WCHAR catid[39];
580         DWORD cName = 39;
581
582         res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
583                     NULL, NULL, NULL, NULL);
584         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
585         ++(This->next_index);
586
587         hr = CLSIDFromString(catid, rgelt);
588         if (FAILED(hr)) continue;
589
590         ++fetched;
591         ++rgelt;
592     }
593
594     if (pceltFetched) *pceltFetched = fetched;
595     return fetched == celt ? S_OK : S_FALSE;
596 }
597
598 static HRESULT WINAPI ProfilesEnumGuid_Skip( LPENUMGUID iface, ULONG celt)
599 {
600     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
601     TRACE("(%p)\n",This);
602
603     This->next_index += celt;
604     return S_OK;
605 }
606
607 static HRESULT WINAPI ProfilesEnumGuid_Reset( LPENUMGUID iface)
608 {
609     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
610     TRACE("(%p)\n",This);
611     This->next_index = 0;
612     return S_OK;
613 }
614
615 static HRESULT WINAPI ProfilesEnumGuid_Clone( LPENUMGUID iface,
616     IEnumGUID **ppenum)
617 {
618     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
619     HRESULT res;
620
621     TRACE("(%p)\n",This);
622
623     if (ppenum == NULL) return E_POINTER;
624
625     res = ProfilesEnumGuid_Constructor(ppenum);
626     if (SUCCEEDED(res))
627     {
628         ProfilesEnumGuid *new_This = (ProfilesEnumGuid *)*ppenum;
629         new_This->next_index = This->next_index;
630     }
631     return res;
632 }
633
634 static const IEnumGUIDVtbl IEnumGUID_Vtbl ={
635     ProfilesEnumGuid_QueryInterface,
636     ProfilesEnumGuid_AddRef,
637     ProfilesEnumGuid_Release,
638
639     ProfilesEnumGuid_Next,
640     ProfilesEnumGuid_Skip,
641     ProfilesEnumGuid_Reset,
642     ProfilesEnumGuid_Clone
643 };
644
645 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut)
646 {
647     ProfilesEnumGuid *This;
648
649     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ProfilesEnumGuid));
650     if (This == NULL)
651         return E_OUTOFMEMORY;
652
653     This->Vtbl= &IEnumGUID_Vtbl;
654     This->refCount = 1;
655
656     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
657                     KEY_READ | KEY_WRITE, NULL, &This->key, NULL) != ERROR_SUCCESS)
658         return E_FAIL;
659
660     TRACE("returning %p\n", This);
661     *ppOut = (IEnumGUID*)This;
662     return S_OK;
663 }
664
665 /**************************************************
666  * IEnumTfLanguageProfiles implementaion
667  **************************************************/
668 static void EnumTfLanguageProfiles_Destructor(EnumTfLanguageProfiles *This)
669 {
670     TRACE("destroying %p\n", This);
671     RegCloseKey(This->tipkey);
672     if (This->langkey)
673         RegCloseKey(This->langkey);
674     ITfCategoryMgr_Release(This->catmgr);
675     HeapFree(GetProcessHeap(),0,This);
676 }
677
678 static HRESULT WINAPI EnumTfLanguageProfiles_QueryInterface(IEnumTfLanguageProfiles *iface, REFIID iid, LPVOID *ppvOut)
679 {
680     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
681     *ppvOut = NULL;
682
683     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfLanguageProfiles))
684     {
685         *ppvOut = This;
686     }
687
688     if (*ppvOut)
689     {
690         IUnknown_AddRef(iface);
691         return S_OK;
692     }
693
694     WARN("unsupported interface: %s\n", debugstr_guid(iid));
695     return E_NOINTERFACE;
696 }
697
698 static ULONG WINAPI EnumTfLanguageProfiles_AddRef(IEnumTfLanguageProfiles *iface)
699 {
700     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles*)iface;
701     return InterlockedIncrement(&This->refCount);
702 }
703
704 static ULONG WINAPI EnumTfLanguageProfiles_Release(IEnumTfLanguageProfiles *iface)
705 {
706     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
707     ULONG ret;
708
709     ret = InterlockedDecrement(&This->refCount);
710     if (ret == 0)
711         EnumTfLanguageProfiles_Destructor(This);
712     return ret;
713 }
714
715 /*****************************************************
716  * IEnumGuid functions
717  *****************************************************/
718 static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LANGUAGEPROFILE *tflp)
719 {
720     WCHAR fullkey[168];
721     ULONG res;
722     WCHAR profileid[39];
723     DWORD cName = 39;
724     GUID  profile;
725
726     static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
727
728     if (This->langkey == NULL)
729     {
730         sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
731         res = RegOpenKeyExW(This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
732         if (res)
733         {
734             This->langkey = NULL;
735             return -1;
736         }
737         This->lang_index = 0;
738     }
739     res = RegEnumKeyExW(This->langkey, This->lang_index, profileid, &cName,
740                 NULL, NULL, NULL, NULL);
741     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
742     {
743         RegCloseKey(This->langkey);
744         This->langkey = NULL;
745         return -1;
746     }
747     ++(This->lang_index);
748
749     if (tflp)
750     {
751         static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
752                                            &GUID_TFCAT_TIP_SPEECH,
753                                            &GUID_TFCAT_TIP_HANDWRITING };
754         res = CLSIDFromString(profileid, &profile);
755         if (FAILED(res)) return 0;
756
757         tflp->clsid = clsid;
758         tflp->langid = This->langid;
759         /* FIXME */
760         tflp->fActive = FALSE;
761         tflp->guidProfile = profile;
762         if (ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
763                 &tflp->catid, tipcats, 3) != S_OK)
764             ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
765                     &tflp->catid, NULL, 0);
766     }
767
768     return 1;
769 }
770
771 static HRESULT WINAPI EnumTfLanguageProfiles_Next(IEnumTfLanguageProfiles *iface,
772     ULONG ulCount, TF_LANGUAGEPROFILE *pProfile, ULONG *pcFetch)
773 {
774     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
775     ULONG fetched = 0;
776
777     TRACE("(%p)\n",This);
778
779     if (pProfile == NULL) return E_POINTER;
780
781     if (This->tipkey) while (fetched < ulCount)
782     {
783         LSTATUS res;
784         HRESULT hr;
785         DWORD cName = 39;
786         GUID clsid;
787
788         res = RegEnumKeyExW(This->tipkey, This->tip_index,
789                     This->szwCurrentClsid, &cName, NULL, NULL, NULL, NULL);
790         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
791         ++(This->tip_index);
792         hr = CLSIDFromString(This->szwCurrentClsid, &clsid);
793         if (FAILED(hr)) continue;
794
795         while ( fetched < ulCount)
796         {
797             INT res = next_LanguageProfile(This, clsid, pProfile);
798             if (res == 1)
799             {
800                 ++fetched;
801                 ++pProfile;
802             }
803             else if (res == -1)
804                 break;
805             else
806                 continue;
807         }
808     }
809
810     if (pcFetch) *pcFetch = fetched;
811     return fetched == ulCount ? S_OK : S_FALSE;
812 }
813
814 static HRESULT WINAPI EnumTfLanguageProfiles_Skip( IEnumTfLanguageProfiles* iface, ULONG celt)
815 {
816     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
817     FIXME("STUB (%p)\n",This);
818     return E_NOTIMPL;
819 }
820
821 static HRESULT WINAPI EnumTfLanguageProfiles_Reset( IEnumTfLanguageProfiles* iface)
822 {
823     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
824     TRACE("(%p)\n",This);
825     This->tip_index = 0;
826     if (This->langkey)
827         RegCloseKey(This->langkey);
828     This->langkey = NULL;
829     This->lang_index = 0;
830     return S_OK;
831 }
832
833 static HRESULT WINAPI EnumTfLanguageProfiles_Clone( IEnumTfLanguageProfiles *iface,
834     IEnumTfLanguageProfiles **ppenum)
835 {
836     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
837     HRESULT res;
838
839     TRACE("(%p)\n",This);
840
841     if (ppenum == NULL) return E_POINTER;
842
843     res = EnumTfLanguageProfiles_Constructor(This->langid, ppenum);
844     if (SUCCEEDED(res))
845     {
846         EnumTfLanguageProfiles *new_This = (EnumTfLanguageProfiles *)*ppenum;
847         new_This->tip_index = This->tip_index;
848         lstrcpynW(new_This->szwCurrentClsid,This->szwCurrentClsid,39);
849
850         if (This->langkey)
851         {
852             WCHAR fullkey[168];
853             static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
854
855             sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
856             res = RegOpenKeyExW(new_This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
857             new_This->lang_index = This->lang_index;
858         }
859     }
860     return res;
861 }
862
863 static const IEnumTfLanguageProfilesVtbl IEnumTfLanguageProfiles_Vtbl ={
864     EnumTfLanguageProfiles_QueryInterface,
865     EnumTfLanguageProfiles_AddRef,
866     EnumTfLanguageProfiles_Release,
867
868     EnumTfLanguageProfiles_Clone,
869     EnumTfLanguageProfiles_Next,
870     EnumTfLanguageProfiles_Reset,
871     EnumTfLanguageProfiles_Skip
872 };
873
874 static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut)
875 {
876     HRESULT hr;
877     EnumTfLanguageProfiles *This;
878
879     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfLanguageProfiles));
880     if (This == NULL)
881         return E_OUTOFMEMORY;
882
883     This->Vtbl= &IEnumTfLanguageProfiles_Vtbl;
884     This->refCount = 1;
885     This->langid = langid;
886
887     hr = CategoryMgr_Constructor(NULL,(IUnknown**)&This->catmgr);
888     if (FAILED(hr))
889     {
890         HeapFree(GetProcessHeap(),0,This);
891         return hr;
892     }
893
894     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
895                     KEY_READ | KEY_WRITE, NULL, &This->tipkey, NULL) != ERROR_SUCCESS)
896         return E_FAIL;
897
898     TRACE("returning %p\n", This);
899     *ppOut = (IEnumTfLanguageProfiles*)This;
900     return S_OK;
901 }