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