msctf: Implement ITfInputProcessorProfiles::ActivateLanguageProfile.
[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     HRESULT hr;
292     BOOL enabled;
293     TF_LANGUAGEPROFILE LanguageProfile;
294     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
295
296     TRACE("(%p) %s %x %s\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfiles));
297
298     if (langid != This->currentLanguage) return E_INVALIDARG;
299
300     if (get_active_textservice(rclsid,NULL))
301     {
302         TRACE("Already Active\n");
303         return E_FAIL;
304     }
305
306     hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(iface, rclsid,
307             langid, guidProfiles, &enabled);
308     if (FAILED(hr) || !enabled)
309     {
310         TRACE("Not Enabled\n");
311         return E_FAIL;
312     }
313
314     LanguageProfile.clsid = *rclsid;
315     LanguageProfile.langid = langid;
316     LanguageProfile.guidProfile = *guidProfiles;
317
318     hr = add_active_textservice(&LanguageProfile);
319
320     return hr;
321 }
322
323 static HRESULT WINAPI InputProcessorProfiles_GetActiveLanguageProfile(
324         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID *plangid,
325         GUID *pguidProfile)
326 {
327     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
328     FIXME("STUB:(%p)\n",This);
329     return E_NOTIMPL;
330 }
331
332 static HRESULT WINAPI InputProcessorProfiles_GetLanguageProfileDescription(
333         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
334         REFGUID guidProfile, BSTR *pbstrProfile)
335 {
336     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
337     FIXME("STUB:(%p)\n",This);
338     return E_NOTIMPL;
339 }
340
341 static HRESULT WINAPI InputProcessorProfiles_GetCurrentLanguage(
342         ITfInputProcessorProfiles *iface, LANGID *plangid)
343 {
344     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
345     TRACE("(%p) 0x%x\n",This,This->currentLanguage);
346
347     if (!plangid)
348         return E_INVALIDARG;
349
350     *plangid = This->currentLanguage;
351
352     return S_OK;
353 }
354
355 static HRESULT WINAPI InputProcessorProfiles_ChangeCurrentLanguage(
356         ITfInputProcessorProfiles *iface, LANGID langid)
357 {
358     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
359     FIXME("STUB:(%p)\n",This);
360     return E_NOTIMPL;
361 }
362
363 static HRESULT WINAPI InputProcessorProfiles_GetLanguageList(
364         ITfInputProcessorProfiles *iface, LANGID **ppLangId, ULONG *pulCount)
365 {
366     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
367     FIXME("STUB:(%p)\n",This);
368     return E_NOTIMPL;
369 }
370
371 static HRESULT WINAPI InputProcessorProfiles_EnumLanguageProfiles(
372         ITfInputProcessorProfiles *iface, LANGID langid,
373         IEnumTfLanguageProfiles **ppEnum)
374 {
375     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
376     TRACE("(%p) %x %p\n",This,langid,ppEnum);
377     return EnumTfLanguageProfiles_Constructor(langid, ppEnum);
378 }
379
380 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfile(
381         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
382         REFGUID guidProfile, BOOL fEnable)
383 {
384     HKEY key;
385     WCHAR buf[39];
386     WCHAR buf2[39];
387     WCHAR fullkey[168];
388     ULONG res;
389
390     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
391     TRACE("(%p) %s %x %s %i\n",This, debugstr_guid(rclsid), langid, debugstr_guid(guidProfile), fEnable);
392
393     StringFromGUID2(rclsid, buf, 39);
394     StringFromGUID2(guidProfile, buf2, 39);
395     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
396
397     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
398
399     if (!res)
400     {
401         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
402         RegCloseKey(key);
403     }
404     else
405         return E_FAIL;
406
407     return S_OK;
408 }
409
410 static HRESULT WINAPI InputProcessorProfiles_IsEnabledLanguageProfile(
411         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
412         REFGUID guidProfile, BOOL *pfEnable)
413 {
414     HKEY key;
415     WCHAR buf[39];
416     WCHAR buf2[39];
417     WCHAR fullkey[168];
418     ULONG res;
419
420     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
421     TRACE("(%p) %s, %i, %s, %p\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),pfEnable);
422
423     if (!pfEnable)
424         return E_INVALIDARG;
425
426     StringFromGUID2(rclsid, buf, 39);
427     StringFromGUID2(guidProfile, buf2, 39);
428     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
429
430     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
431
432     if (!res)
433     {
434         DWORD count = sizeof(DWORD);
435         res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
436         RegCloseKey(key);
437     }
438
439     if (res)  /* Try Default */
440     {
441         res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
442
443         if (!res)
444         {
445             DWORD count = sizeof(DWORD);
446             res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
447             RegCloseKey(key);
448         }
449     }
450
451     if (!res)
452         return S_OK;
453     else
454         return E_FAIL;
455 }
456
457 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfileByDefault(
458         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
459         REFGUID guidProfile, BOOL fEnable)
460 {
461     HKEY key;
462     WCHAR buf[39];
463     WCHAR buf2[39];
464     WCHAR fullkey[168];
465     ULONG res;
466
467     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
468     TRACE("(%p) %s %x %s %i\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),fEnable);
469
470     StringFromGUID2(rclsid, buf, 39);
471     StringFromGUID2(guidProfile, buf2, 39);
472     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
473
474     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
475
476     if (!res)
477     {
478         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
479         RegCloseKey(key);
480     }
481     else
482         return E_FAIL;
483
484     return S_OK;
485 }
486
487 static HRESULT WINAPI InputProcessorProfiles_SubstituteKeyboardLayout(
488         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
489         REFGUID guidProfile, HKL hKL)
490 {
491     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
492     FIXME("STUB:(%p)\n",This);
493     return E_NOTIMPL;
494 }
495
496
497 static const ITfInputProcessorProfilesVtbl InputProcessorProfiles_InputProcessorProfilesVtbl =
498 {
499     InputProcessorProfiles_QueryInterface,
500     InputProcessorProfiles_AddRef,
501     InputProcessorProfiles_Release,
502
503     InputProcessorProfiles_Register,
504     InputProcessorProfiles_Unregister,
505     InputProcessorProfiles_AddLanguageProfile,
506     InputProcessorProfiles_RemoveLanguageProfile,
507     InputProcessorProfiles_EnumInputProcessorInfo,
508     InputProcessorProfiles_GetDefaultLanguageProfile,
509     InputProcessorProfiles_SetDefaultLanguageProfile,
510     InputProcessorProfiles_ActivateLanguageProfile,
511     InputProcessorProfiles_GetActiveLanguageProfile,
512     InputProcessorProfiles_GetLanguageProfileDescription,
513     InputProcessorProfiles_GetCurrentLanguage,
514     InputProcessorProfiles_ChangeCurrentLanguage,
515     InputProcessorProfiles_GetLanguageList,
516     InputProcessorProfiles_EnumLanguageProfiles,
517     InputProcessorProfiles_EnableLanguageProfile,
518     InputProcessorProfiles_IsEnabledLanguageProfile,
519     InputProcessorProfiles_EnableLanguageProfileByDefault,
520     InputProcessorProfiles_SubstituteKeyboardLayout
521 };
522
523 HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
524 {
525     InputProcessorProfiles *This;
526     if (pUnkOuter)
527         return CLASS_E_NOAGGREGATION;
528
529     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputProcessorProfiles));
530     if (This == NULL)
531         return E_OUTOFMEMORY;
532
533     This->InputProcessorProfilesVtbl= &InputProcessorProfiles_InputProcessorProfilesVtbl;
534     This->refCount = 1;
535     This->currentLanguage = GetUserDefaultLCID();
536
537     TRACE("returning %p\n", This);
538     *ppOut = (IUnknown *)This;
539     return S_OK;
540 }
541
542 /**************************************************
543  * IEnumGUID implementaion for ITfInputProcessorProfiles::EnumInputProcessorInfo
544  **************************************************/
545 static void ProfilesEnumGuid_Destructor(ProfilesEnumGuid *This)
546 {
547     TRACE("destroying %p\n", This);
548     RegCloseKey(This->key);
549     HeapFree(GetProcessHeap(),0,This);
550 }
551
552 static HRESULT WINAPI ProfilesEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
553 {
554     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
555     *ppvOut = NULL;
556
557     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
558     {
559         *ppvOut = This;
560     }
561
562     if (*ppvOut)
563     {
564         IUnknown_AddRef(iface);
565         return S_OK;
566     }
567
568     WARN("unsupported interface: %s\n", debugstr_guid(iid));
569     return E_NOINTERFACE;
570 }
571
572 static ULONG WINAPI ProfilesEnumGuid_AddRef(IEnumGUID *iface)
573 {
574     ProfilesEnumGuid *This = (ProfilesEnumGuid*)iface;
575     return InterlockedIncrement(&This->refCount);
576 }
577
578 static ULONG WINAPI ProfilesEnumGuid_Release(IEnumGUID *iface)
579 {
580     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
581     ULONG ret;
582
583     ret = InterlockedDecrement(&This->refCount);
584     if (ret == 0)
585         ProfilesEnumGuid_Destructor(This);
586     return ret;
587 }
588
589 /*****************************************************
590  * IEnumGuid functions
591  *****************************************************/
592 static HRESULT WINAPI ProfilesEnumGuid_Next( LPENUMGUID iface,
593     ULONG celt, GUID *rgelt, ULONG *pceltFetched)
594 {
595     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
596     ULONG fetched = 0;
597
598     TRACE("(%p)\n",This);
599
600     if (rgelt == NULL) return E_POINTER;
601
602     if (This->key) while (fetched < celt)
603     {
604         LSTATUS res;
605         HRESULT hr;
606         WCHAR catid[39];
607         DWORD cName = 39;
608
609         res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
610                     NULL, NULL, NULL, NULL);
611         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
612         ++(This->next_index);
613
614         hr = CLSIDFromString(catid, rgelt);
615         if (FAILED(hr)) continue;
616
617         ++fetched;
618         ++rgelt;
619     }
620
621     if (pceltFetched) *pceltFetched = fetched;
622     return fetched == celt ? S_OK : S_FALSE;
623 }
624
625 static HRESULT WINAPI ProfilesEnumGuid_Skip( LPENUMGUID iface, ULONG celt)
626 {
627     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
628     TRACE("(%p)\n",This);
629
630     This->next_index += celt;
631     return S_OK;
632 }
633
634 static HRESULT WINAPI ProfilesEnumGuid_Reset( LPENUMGUID iface)
635 {
636     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
637     TRACE("(%p)\n",This);
638     This->next_index = 0;
639     return S_OK;
640 }
641
642 static HRESULT WINAPI ProfilesEnumGuid_Clone( LPENUMGUID iface,
643     IEnumGUID **ppenum)
644 {
645     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
646     HRESULT res;
647
648     TRACE("(%p)\n",This);
649
650     if (ppenum == NULL) return E_POINTER;
651
652     res = ProfilesEnumGuid_Constructor(ppenum);
653     if (SUCCEEDED(res))
654     {
655         ProfilesEnumGuid *new_This = (ProfilesEnumGuid *)*ppenum;
656         new_This->next_index = This->next_index;
657     }
658     return res;
659 }
660
661 static const IEnumGUIDVtbl IEnumGUID_Vtbl ={
662     ProfilesEnumGuid_QueryInterface,
663     ProfilesEnumGuid_AddRef,
664     ProfilesEnumGuid_Release,
665
666     ProfilesEnumGuid_Next,
667     ProfilesEnumGuid_Skip,
668     ProfilesEnumGuid_Reset,
669     ProfilesEnumGuid_Clone
670 };
671
672 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut)
673 {
674     ProfilesEnumGuid *This;
675
676     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ProfilesEnumGuid));
677     if (This == NULL)
678         return E_OUTOFMEMORY;
679
680     This->Vtbl= &IEnumGUID_Vtbl;
681     This->refCount = 1;
682
683     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
684                     KEY_READ | KEY_WRITE, NULL, &This->key, NULL) != ERROR_SUCCESS)
685         return E_FAIL;
686
687     TRACE("returning %p\n", This);
688     *ppOut = (IEnumGUID*)This;
689     return S_OK;
690 }
691
692 /**************************************************
693  * IEnumTfLanguageProfiles implementaion
694  **************************************************/
695 static void EnumTfLanguageProfiles_Destructor(EnumTfLanguageProfiles *This)
696 {
697     TRACE("destroying %p\n", This);
698     RegCloseKey(This->tipkey);
699     if (This->langkey)
700         RegCloseKey(This->langkey);
701     ITfCategoryMgr_Release(This->catmgr);
702     HeapFree(GetProcessHeap(),0,This);
703 }
704
705 static HRESULT WINAPI EnumTfLanguageProfiles_QueryInterface(IEnumTfLanguageProfiles *iface, REFIID iid, LPVOID *ppvOut)
706 {
707     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
708     *ppvOut = NULL;
709
710     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfLanguageProfiles))
711     {
712         *ppvOut = This;
713     }
714
715     if (*ppvOut)
716     {
717         IUnknown_AddRef(iface);
718         return S_OK;
719     }
720
721     WARN("unsupported interface: %s\n", debugstr_guid(iid));
722     return E_NOINTERFACE;
723 }
724
725 static ULONG WINAPI EnumTfLanguageProfiles_AddRef(IEnumTfLanguageProfiles *iface)
726 {
727     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles*)iface;
728     return InterlockedIncrement(&This->refCount);
729 }
730
731 static ULONG WINAPI EnumTfLanguageProfiles_Release(IEnumTfLanguageProfiles *iface)
732 {
733     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
734     ULONG ret;
735
736     ret = InterlockedDecrement(&This->refCount);
737     if (ret == 0)
738         EnumTfLanguageProfiles_Destructor(This);
739     return ret;
740 }
741
742 /*****************************************************
743  * IEnumGuid functions
744  *****************************************************/
745 static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LANGUAGEPROFILE *tflp)
746 {
747     WCHAR fullkey[168];
748     ULONG res;
749     WCHAR profileid[39];
750     DWORD cName = 39;
751     GUID  profile;
752
753     static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
754
755     if (This->langkey == NULL)
756     {
757         sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
758         res = RegOpenKeyExW(This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
759         if (res)
760         {
761             This->langkey = NULL;
762             return -1;
763         }
764         This->lang_index = 0;
765     }
766     res = RegEnumKeyExW(This->langkey, This->lang_index, profileid, &cName,
767                 NULL, NULL, NULL, NULL);
768     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
769     {
770         RegCloseKey(This->langkey);
771         This->langkey = NULL;
772         return -1;
773     }
774     ++(This->lang_index);
775
776     if (tflp)
777     {
778         static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
779                                            &GUID_TFCAT_TIP_SPEECH,
780                                            &GUID_TFCAT_TIP_HANDWRITING };
781         res = CLSIDFromString(profileid, &profile);
782         if (FAILED(res)) return 0;
783
784         tflp->clsid = clsid;
785         tflp->langid = This->langid;
786         tflp->fActive = get_active_textservice(&clsid, NULL);
787         tflp->guidProfile = profile;
788         if (ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
789                 &tflp->catid, tipcats, 3) != S_OK)
790             ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
791                     &tflp->catid, NULL, 0);
792     }
793
794     return 1;
795 }
796
797 static HRESULT WINAPI EnumTfLanguageProfiles_Next(IEnumTfLanguageProfiles *iface,
798     ULONG ulCount, TF_LANGUAGEPROFILE *pProfile, ULONG *pcFetch)
799 {
800     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
801     ULONG fetched = 0;
802
803     TRACE("(%p)\n",This);
804
805     if (pProfile == NULL) return E_POINTER;
806
807     if (This->tipkey) while (fetched < ulCount)
808     {
809         LSTATUS res;
810         HRESULT hr;
811         DWORD cName = 39;
812         GUID clsid;
813
814         res = RegEnumKeyExW(This->tipkey, This->tip_index,
815                     This->szwCurrentClsid, &cName, NULL, NULL, NULL, NULL);
816         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
817         ++(This->tip_index);
818         hr = CLSIDFromString(This->szwCurrentClsid, &clsid);
819         if (FAILED(hr)) continue;
820
821         while ( fetched < ulCount)
822         {
823             INT res = next_LanguageProfile(This, clsid, pProfile);
824             if (res == 1)
825             {
826                 ++fetched;
827                 ++pProfile;
828             }
829             else if (res == -1)
830                 break;
831             else
832                 continue;
833         }
834     }
835
836     if (pcFetch) *pcFetch = fetched;
837     return fetched == ulCount ? S_OK : S_FALSE;
838 }
839
840 static HRESULT WINAPI EnumTfLanguageProfiles_Skip( IEnumTfLanguageProfiles* iface, ULONG celt)
841 {
842     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
843     FIXME("STUB (%p)\n",This);
844     return E_NOTIMPL;
845 }
846
847 static HRESULT WINAPI EnumTfLanguageProfiles_Reset( IEnumTfLanguageProfiles* iface)
848 {
849     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
850     TRACE("(%p)\n",This);
851     This->tip_index = 0;
852     if (This->langkey)
853         RegCloseKey(This->langkey);
854     This->langkey = NULL;
855     This->lang_index = 0;
856     return S_OK;
857 }
858
859 static HRESULT WINAPI EnumTfLanguageProfiles_Clone( IEnumTfLanguageProfiles *iface,
860     IEnumTfLanguageProfiles **ppenum)
861 {
862     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
863     HRESULT res;
864
865     TRACE("(%p)\n",This);
866
867     if (ppenum == NULL) return E_POINTER;
868
869     res = EnumTfLanguageProfiles_Constructor(This->langid, ppenum);
870     if (SUCCEEDED(res))
871     {
872         EnumTfLanguageProfiles *new_This = (EnumTfLanguageProfiles *)*ppenum;
873         new_This->tip_index = This->tip_index;
874         lstrcpynW(new_This->szwCurrentClsid,This->szwCurrentClsid,39);
875
876         if (This->langkey)
877         {
878             WCHAR fullkey[168];
879             static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
880
881             sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
882             res = RegOpenKeyExW(new_This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
883             new_This->lang_index = This->lang_index;
884         }
885     }
886     return res;
887 }
888
889 static const IEnumTfLanguageProfilesVtbl IEnumTfLanguageProfiles_Vtbl ={
890     EnumTfLanguageProfiles_QueryInterface,
891     EnumTfLanguageProfiles_AddRef,
892     EnumTfLanguageProfiles_Release,
893
894     EnumTfLanguageProfiles_Clone,
895     EnumTfLanguageProfiles_Next,
896     EnumTfLanguageProfiles_Reset,
897     EnumTfLanguageProfiles_Skip
898 };
899
900 static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut)
901 {
902     HRESULT hr;
903     EnumTfLanguageProfiles *This;
904
905     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfLanguageProfiles));
906     if (This == NULL)
907         return E_OUTOFMEMORY;
908
909     This->Vtbl= &IEnumTfLanguageProfiles_Vtbl;
910     This->refCount = 1;
911     This->langid = langid;
912
913     hr = CategoryMgr_Constructor(NULL,(IUnknown**)&This->catmgr);
914     if (FAILED(hr))
915     {
916         HeapFree(GetProcessHeap(),0,This);
917         return hr;
918     }
919
920     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
921                     KEY_READ | KEY_WRITE, NULL, &This->tipkey, NULL) != ERROR_SUCCESS)
922         return E_FAIL;
923
924     TRACE("returning %p\n", This);
925     *ppOut = (IEnumTfLanguageProfiles*)This;
926     return S_OK;
927 }