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