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