ole32: Use existing MTA in CoGetContextToken and CoGetObjectContext.
[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     WCHAR fullkey[168];
362     WCHAR buf[39];
363     HKEY hkey;
364     GUID catid;
365     HRESULT hr;
366     ITfCategoryMgr *catmgr;
367     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
368     static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
369                                        &GUID_TFCAT_TIP_SPEECH,
370                                        &GUID_TFCAT_TIP_HANDWRITING };
371
372     TRACE("%p) %x %s %s\n",This, langid, debugstr_guid(rclsid),debugstr_guid(guidProfiles));
373
374     if (!rclsid || !guidProfiles)
375         return E_INVALIDARG;
376
377     hr = CategoryMgr_Constructor(NULL,(IUnknown**)&catmgr);
378
379     if (FAILED(hr))
380         return hr;
381
382     if (ITfCategoryMgr_FindClosestCategory(catmgr, rclsid,
383             &catid, tipcats, 3) != S_OK)
384         hr = ITfCategoryMgr_FindClosestCategory(catmgr, rclsid,
385                 &catid, NULL, 0);
386     ITfCategoryMgr_Release(catmgr);
387
388     if (FAILED(hr))
389         return E_FAIL;
390
391     StringFromGUID2(&catid, buf, 39);
392     sprintfW(fullkey, szwDefaultFmt, szwSystemCTFKey, szwAssemblies, langid, buf);
393
394     if (RegCreateKeyExW(HKEY_CURRENT_USER, fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
395                 NULL, &hkey, NULL ) != ERROR_SUCCESS)
396         return E_FAIL;
397
398     StringFromGUID2(rclsid, buf, 39);
399     RegSetValueExW(hkey, szwDefault, 0, REG_SZ, (LPBYTE)buf, sizeof(buf));
400     StringFromGUID2(guidProfiles, buf, 39);
401     RegSetValueExW(hkey, szwProfile, 0, REG_SZ, (LPBYTE)buf, sizeof(buf));
402     RegCloseKey(hkey);
403
404     return S_OK;
405 }
406
407 static HRESULT WINAPI InputProcessorProfiles_ActivateLanguageProfile(
408         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
409         REFGUID guidProfiles)
410 {
411     HRESULT hr;
412     BOOL enabled;
413     TF_LANGUAGEPROFILE LanguageProfile;
414     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
415
416     TRACE("(%p) %s %x %s\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfiles));
417
418     if (langid != This->currentLanguage) return E_INVALIDARG;
419
420     if (get_active_textservice(rclsid,NULL))
421     {
422         TRACE("Already Active\n");
423         return E_FAIL;
424     }
425
426     hr = ITfInputProcessorProfiles_IsEnabledLanguageProfile(iface, rclsid,
427             langid, guidProfiles, &enabled);
428     if (FAILED(hr) || !enabled)
429     {
430         TRACE("Not Enabled\n");
431         return E_FAIL;
432     }
433
434     LanguageProfile.clsid = *rclsid;
435     LanguageProfile.langid = langid;
436     LanguageProfile.guidProfile = *guidProfiles;
437
438     hr = add_active_textservice(&LanguageProfile);
439
440     return hr;
441 }
442
443 static HRESULT WINAPI InputProcessorProfiles_GetActiveLanguageProfile(
444         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID *plangid,
445         GUID *pguidProfile)
446 {
447     TF_LANGUAGEPROFILE profile;
448     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
449
450     TRACE("(%p) %s %p %p\n",This,debugstr_guid(rclsid),plangid,pguidProfile);
451
452     if (!rclsid || !plangid || !pguidProfile)
453         return E_INVALIDARG;
454
455     if (get_active_textservice(rclsid, &profile))
456     {
457         *plangid = profile.langid;
458         *pguidProfile = profile.guidProfile;
459         return S_OK;
460     }
461     else
462     {
463         *pguidProfile = GUID_NULL;
464         return S_FALSE;
465     }
466 }
467
468 static HRESULT WINAPI InputProcessorProfiles_GetLanguageProfileDescription(
469         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
470         REFGUID guidProfile, BSTR *pbstrProfile)
471 {
472     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
473     FIXME("STUB:(%p)\n",This);
474     return E_NOTIMPL;
475 }
476
477 static HRESULT WINAPI InputProcessorProfiles_GetCurrentLanguage(
478         ITfInputProcessorProfiles *iface, LANGID *plangid)
479 {
480     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
481     TRACE("(%p) 0x%x\n",This,This->currentLanguage);
482
483     if (!plangid)
484         return E_INVALIDARG;
485
486     *plangid = This->currentLanguage;
487
488     return S_OK;
489 }
490
491 static HRESULT WINAPI InputProcessorProfiles_ChangeCurrentLanguage(
492         ITfInputProcessorProfiles *iface, LANGID langid)
493 {
494     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
495     FIXME("STUB:(%p)\n",This);
496     return E_NOTIMPL;
497 }
498
499 static HRESULT WINAPI InputProcessorProfiles_GetLanguageList(
500         ITfInputProcessorProfiles *iface, LANGID **ppLangId, ULONG *pulCount)
501 {
502     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
503     FIXME("Semi-STUB:(%p)\n",This);
504     *ppLangId = CoTaskMemAlloc(sizeof(LANGID));
505     **ppLangId = This->currentLanguage;
506     *pulCount = 1;
507     return S_OK;
508 }
509
510 static HRESULT WINAPI InputProcessorProfiles_EnumLanguageProfiles(
511         ITfInputProcessorProfiles *iface, LANGID langid,
512         IEnumTfLanguageProfiles **ppEnum)
513 {
514     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
515     TRACE("(%p) %x %p\n",This,langid,ppEnum);
516     return EnumTfLanguageProfiles_Constructor(langid, ppEnum);
517 }
518
519 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfile(
520         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
521         REFGUID guidProfile, BOOL fEnable)
522 {
523     HKEY key;
524     WCHAR buf[39];
525     WCHAR buf2[39];
526     WCHAR fullkey[168];
527     ULONG res;
528
529     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
530     TRACE("(%p) %s %x %s %i\n",This, debugstr_guid(rclsid), langid, debugstr_guid(guidProfile), fEnable);
531
532     StringFromGUID2(rclsid, buf, 39);
533     StringFromGUID2(guidProfile, buf2, 39);
534     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
535
536     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
537
538     if (!res)
539     {
540         RegSetValueExW(key, szwEnable, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
541         RegCloseKey(key);
542     }
543     else
544         return E_FAIL;
545
546     return S_OK;
547 }
548
549 static HRESULT WINAPI InputProcessorProfiles_IsEnabledLanguageProfile(
550         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
551         REFGUID guidProfile, BOOL *pfEnable)
552 {
553     HKEY key;
554     WCHAR buf[39];
555     WCHAR buf2[39];
556     WCHAR fullkey[168];
557     ULONG res;
558
559     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
560     TRACE("(%p) %s, %i, %s, %p\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),pfEnable);
561
562     if (!pfEnable)
563         return E_INVALIDARG;
564
565     StringFromGUID2(rclsid, buf, 39);
566     StringFromGUID2(guidProfile, buf2, 39);
567     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
568
569     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
570
571     if (!res)
572     {
573         DWORD count = sizeof(DWORD);
574         res = RegQueryValueExW(key, szwEnable, 0, NULL, (LPBYTE)pfEnable, &count);
575         RegCloseKey(key);
576     }
577
578     if (res)  /* Try Default */
579     {
580         res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
581
582         if (!res)
583         {
584             DWORD count = sizeof(DWORD);
585             res = RegQueryValueExW(key, szwEnable, 0, NULL, (LPBYTE)pfEnable, &count);
586             RegCloseKey(key);
587         }
588     }
589
590     if (!res)
591         return S_OK;
592     else
593         return E_FAIL;
594 }
595
596 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfileByDefault(
597         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
598         REFGUID guidProfile, BOOL fEnable)
599 {
600     HKEY key;
601     WCHAR buf[39];
602     WCHAR buf2[39];
603     WCHAR fullkey[168];
604     ULONG res;
605
606     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
607     TRACE("(%p) %s %x %s %i\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),fEnable);
608
609     StringFromGUID2(rclsid, buf, 39);
610     StringFromGUID2(guidProfile, buf2, 39);
611     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
612
613     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
614
615     if (!res)
616     {
617         RegSetValueExW(key, szwEnable, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
618         RegCloseKey(key);
619     }
620     else
621         return E_FAIL;
622
623     return S_OK;
624 }
625
626 static HRESULT WINAPI InputProcessorProfiles_SubstituteKeyboardLayout(
627         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
628         REFGUID guidProfile, HKL hKL)
629 {
630     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
631     FIXME("STUB:(%p)\n",This);
632     return E_NOTIMPL;
633 }
634
635
636 static const ITfInputProcessorProfilesVtbl InputProcessorProfiles_InputProcessorProfilesVtbl =
637 {
638     InputProcessorProfiles_QueryInterface,
639     InputProcessorProfiles_AddRef,
640     InputProcessorProfiles_Release,
641
642     InputProcessorProfiles_Register,
643     InputProcessorProfiles_Unregister,
644     InputProcessorProfiles_AddLanguageProfile,
645     InputProcessorProfiles_RemoveLanguageProfile,
646     InputProcessorProfiles_EnumInputProcessorInfo,
647     InputProcessorProfiles_GetDefaultLanguageProfile,
648     InputProcessorProfiles_SetDefaultLanguageProfile,
649     InputProcessorProfiles_ActivateLanguageProfile,
650     InputProcessorProfiles_GetActiveLanguageProfile,
651     InputProcessorProfiles_GetLanguageProfileDescription,
652     InputProcessorProfiles_GetCurrentLanguage,
653     InputProcessorProfiles_ChangeCurrentLanguage,
654     InputProcessorProfiles_GetLanguageList,
655     InputProcessorProfiles_EnumLanguageProfiles,
656     InputProcessorProfiles_EnableLanguageProfile,
657     InputProcessorProfiles_IsEnabledLanguageProfile,
658     InputProcessorProfiles_EnableLanguageProfileByDefault,
659     InputProcessorProfiles_SubstituteKeyboardLayout
660 };
661
662 /*****************************************************
663  * ITfSource functions
664  *****************************************************/
665 static HRESULT WINAPI IPPSource_QueryInterface(ITfSource *iface, REFIID iid, LPVOID *ppvOut)
666 {
667     InputProcessorProfiles *This = impl_from_ITfSourceVtbl(iface);
668     return InputProcessorProfiles_QueryInterface((ITfInputProcessorProfiles *)This, iid, *ppvOut);
669 }
670
671 static ULONG WINAPI IPPSource_AddRef(ITfSource *iface)
672 {
673     InputProcessorProfiles *This = impl_from_ITfSourceVtbl(iface);
674     return InputProcessorProfiles_AddRef((ITfInputProcessorProfiles*)This);
675 }
676
677 static ULONG WINAPI IPPSource_Release(ITfSource *iface)
678 {
679     InputProcessorProfiles *This = impl_from_ITfSourceVtbl(iface);
680     return InputProcessorProfiles_Release((ITfInputProcessorProfiles *)This);
681 }
682
683 static WINAPI HRESULT IPPSource_AdviseSink(ITfSource *iface,
684         REFIID riid, IUnknown *punk, DWORD *pdwCookie)
685 {
686     InputProcessorProfilesSink *ipps;
687     InputProcessorProfiles *This = impl_from_ITfSourceVtbl(iface);
688
689     TRACE("(%p) %s %p %p\n",This,debugstr_guid(riid),punk,pdwCookie);
690
691     if (!riid || !punk || !pdwCookie)
692         return E_INVALIDARG;
693
694     if (IsEqualIID(riid, &IID_ITfLanguageProfileNotifySink))
695     {
696         ipps = HeapAlloc(GetProcessHeap(),0,sizeof(InputProcessorProfilesSink));
697         if (!ipps)
698             return E_OUTOFMEMORY;
699         if (FAILED(IUnknown_QueryInterface(punk, riid, (LPVOID *)&ipps->interfaces.pITfLanguageProfileNotifySink)))
700         {
701             HeapFree(GetProcessHeap(),0,ipps);
702             return CONNECT_E_CANNOTCONNECT;
703         }
704         list_add_head(&This->LanguageProfileNotifySink,&ipps->entry);
705         *pdwCookie = generate_Cookie(COOKIE_MAGIC_IPPSINK, ipps);
706     }
707     else
708     {
709         FIXME("(%p) Unhandled Sink: %s\n",This,debugstr_guid(riid));
710         return E_NOTIMPL;
711     }
712
713     TRACE("cookie %x\n",*pdwCookie);
714
715     return S_OK;
716 }
717
718 static WINAPI HRESULT IPPSource_UnadviseSink(ITfSource *iface, DWORD pdwCookie)
719 {
720     InputProcessorProfilesSink *sink;
721     InputProcessorProfiles *This = impl_from_ITfSourceVtbl(iface);
722
723     TRACE("(%p) %x\n",This,pdwCookie);
724
725     if (get_Cookie_magic(pdwCookie)!=COOKIE_MAGIC_IPPSINK)
726         return E_INVALIDARG;
727
728     sink = (InputProcessorProfilesSink*)remove_Cookie(pdwCookie);
729     if (!sink)
730         return CONNECT_E_NOCONNECTION;
731
732     list_remove(&sink->entry);
733     free_sink(sink);
734
735     return S_OK;
736 }
737
738 static const ITfSourceVtbl InputProcessorProfiles_SourceVtbl =
739 {
740     IPPSource_QueryInterface,
741     IPPSource_AddRef,
742     IPPSource_Release,
743
744     IPPSource_AdviseSink,
745     IPPSource_UnadviseSink,
746 };
747
748 HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
749 {
750     InputProcessorProfiles *This;
751     if (pUnkOuter)
752         return CLASS_E_NOAGGREGATION;
753
754     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputProcessorProfiles));
755     if (This == NULL)
756         return E_OUTOFMEMORY;
757
758     This->InputProcessorProfilesVtbl= &InputProcessorProfiles_InputProcessorProfilesVtbl;
759     This->SourceVtbl = &InputProcessorProfiles_SourceVtbl;
760     This->refCount = 1;
761     This->currentLanguage = GetUserDefaultLCID();
762
763     list_init(&This->LanguageProfileNotifySink);
764
765     TRACE("returning %p\n", This);
766     *ppOut = (IUnknown *)This;
767     return S_OK;
768 }
769
770 /**************************************************
771  * IEnumGUID implementaion for ITfInputProcessorProfiles::EnumInputProcessorInfo
772  **************************************************/
773 static void ProfilesEnumGuid_Destructor(ProfilesEnumGuid *This)
774 {
775     TRACE("destroying %p\n", This);
776     RegCloseKey(This->key);
777     HeapFree(GetProcessHeap(),0,This);
778 }
779
780 static HRESULT WINAPI ProfilesEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
781 {
782     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
783     *ppvOut = NULL;
784
785     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
786     {
787         *ppvOut = This;
788     }
789
790     if (*ppvOut)
791     {
792         IUnknown_AddRef(iface);
793         return S_OK;
794     }
795
796     WARN("unsupported interface: %s\n", debugstr_guid(iid));
797     return E_NOINTERFACE;
798 }
799
800 static ULONG WINAPI ProfilesEnumGuid_AddRef(IEnumGUID *iface)
801 {
802     ProfilesEnumGuid *This = (ProfilesEnumGuid*)iface;
803     return InterlockedIncrement(&This->refCount);
804 }
805
806 static ULONG WINAPI ProfilesEnumGuid_Release(IEnumGUID *iface)
807 {
808     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
809     ULONG ret;
810
811     ret = InterlockedDecrement(&This->refCount);
812     if (ret == 0)
813         ProfilesEnumGuid_Destructor(This);
814     return ret;
815 }
816
817 /*****************************************************
818  * IEnumGuid functions
819  *****************************************************/
820 static HRESULT WINAPI ProfilesEnumGuid_Next( LPENUMGUID iface,
821     ULONG celt, GUID *rgelt, ULONG *pceltFetched)
822 {
823     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
824     ULONG fetched = 0;
825
826     TRACE("(%p)\n",This);
827
828     if (rgelt == NULL) return E_POINTER;
829
830     if (This->key) while (fetched < celt)
831     {
832         LSTATUS res;
833         HRESULT hr;
834         WCHAR catid[39];
835         DWORD cName = 39;
836
837         res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
838                     NULL, NULL, NULL, NULL);
839         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
840         ++(This->next_index);
841
842         hr = CLSIDFromString(catid, rgelt);
843         if (FAILED(hr)) continue;
844
845         ++fetched;
846         ++rgelt;
847     }
848
849     if (pceltFetched) *pceltFetched = fetched;
850     return fetched == celt ? S_OK : S_FALSE;
851 }
852
853 static HRESULT WINAPI ProfilesEnumGuid_Skip( LPENUMGUID iface, ULONG celt)
854 {
855     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
856     TRACE("(%p)\n",This);
857
858     This->next_index += celt;
859     return S_OK;
860 }
861
862 static HRESULT WINAPI ProfilesEnumGuid_Reset( LPENUMGUID iface)
863 {
864     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
865     TRACE("(%p)\n",This);
866     This->next_index = 0;
867     return S_OK;
868 }
869
870 static HRESULT WINAPI ProfilesEnumGuid_Clone( LPENUMGUID iface,
871     IEnumGUID **ppenum)
872 {
873     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
874     HRESULT res;
875
876     TRACE("(%p)\n",This);
877
878     if (ppenum == NULL) return E_POINTER;
879
880     res = ProfilesEnumGuid_Constructor(ppenum);
881     if (SUCCEEDED(res))
882     {
883         ProfilesEnumGuid *new_This = (ProfilesEnumGuid *)*ppenum;
884         new_This->next_index = This->next_index;
885     }
886     return res;
887 }
888
889 static const IEnumGUIDVtbl IEnumGUID_Vtbl ={
890     ProfilesEnumGuid_QueryInterface,
891     ProfilesEnumGuid_AddRef,
892     ProfilesEnumGuid_Release,
893
894     ProfilesEnumGuid_Next,
895     ProfilesEnumGuid_Skip,
896     ProfilesEnumGuid_Reset,
897     ProfilesEnumGuid_Clone
898 };
899
900 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut)
901 {
902     ProfilesEnumGuid *This;
903
904     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ProfilesEnumGuid));
905     if (This == NULL)
906         return E_OUTOFMEMORY;
907
908     This->Vtbl= &IEnumGUID_Vtbl;
909     This->refCount = 1;
910
911     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
912                     KEY_READ | KEY_WRITE, NULL, &This->key, NULL) != ERROR_SUCCESS)
913         return E_FAIL;
914
915     TRACE("returning %p\n", This);
916     *ppOut = (IEnumGUID*)This;
917     return S_OK;
918 }
919
920 /**************************************************
921  * IEnumTfLanguageProfiles implementaion
922  **************************************************/
923 static void EnumTfLanguageProfiles_Destructor(EnumTfLanguageProfiles *This)
924 {
925     TRACE("destroying %p\n", This);
926     RegCloseKey(This->tipkey);
927     if (This->langkey)
928         RegCloseKey(This->langkey);
929     ITfCategoryMgr_Release(This->catmgr);
930     HeapFree(GetProcessHeap(),0,This);
931 }
932
933 static HRESULT WINAPI EnumTfLanguageProfiles_QueryInterface(IEnumTfLanguageProfiles *iface, REFIID iid, LPVOID *ppvOut)
934 {
935     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
936     *ppvOut = NULL;
937
938     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfLanguageProfiles))
939     {
940         *ppvOut = This;
941     }
942
943     if (*ppvOut)
944     {
945         IUnknown_AddRef(iface);
946         return S_OK;
947     }
948
949     WARN("unsupported interface: %s\n", debugstr_guid(iid));
950     return E_NOINTERFACE;
951 }
952
953 static ULONG WINAPI EnumTfLanguageProfiles_AddRef(IEnumTfLanguageProfiles *iface)
954 {
955     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles*)iface;
956     return InterlockedIncrement(&This->refCount);
957 }
958
959 static ULONG WINAPI EnumTfLanguageProfiles_Release(IEnumTfLanguageProfiles *iface)
960 {
961     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
962     ULONG ret;
963
964     ret = InterlockedDecrement(&This->refCount);
965     if (ret == 0)
966         EnumTfLanguageProfiles_Destructor(This);
967     return ret;
968 }
969
970 /*****************************************************
971  * IEnumGuid functions
972  *****************************************************/
973 static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LANGUAGEPROFILE *tflp)
974 {
975     WCHAR fullkey[168];
976     ULONG res;
977     WCHAR profileid[39];
978     DWORD cName = 39;
979     GUID  profile;
980
981     static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
982
983     if (This->langkey == NULL)
984     {
985         sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
986         res = RegOpenKeyExW(This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
987         if (res)
988         {
989             This->langkey = NULL;
990             return -1;
991         }
992         This->lang_index = 0;
993     }
994     res = RegEnumKeyExW(This->langkey, This->lang_index, profileid, &cName,
995                 NULL, NULL, NULL, NULL);
996     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
997     {
998         RegCloseKey(This->langkey);
999         This->langkey = NULL;
1000         return -1;
1001     }
1002     ++(This->lang_index);
1003
1004     if (tflp)
1005     {
1006         static const GUID * tipcats[3] = { &GUID_TFCAT_TIP_KEYBOARD,
1007                                            &GUID_TFCAT_TIP_SPEECH,
1008                                            &GUID_TFCAT_TIP_HANDWRITING };
1009         res = CLSIDFromString(profileid, &profile);
1010         if (FAILED(res)) return 0;
1011
1012         tflp->clsid = clsid;
1013         tflp->langid = This->langid;
1014         tflp->fActive = get_active_textservice(&clsid, NULL);
1015         tflp->guidProfile = profile;
1016         if (ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
1017                 &tflp->catid, tipcats, 3) != S_OK)
1018             ITfCategoryMgr_FindClosestCategory(This->catmgr, &clsid,
1019                     &tflp->catid, NULL, 0);
1020     }
1021
1022     return 1;
1023 }
1024
1025 static HRESULT WINAPI EnumTfLanguageProfiles_Next(IEnumTfLanguageProfiles *iface,
1026     ULONG ulCount, TF_LANGUAGEPROFILE *pProfile, ULONG *pcFetch)
1027 {
1028     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
1029     ULONG fetched = 0;
1030
1031     TRACE("(%p)\n",This);
1032
1033     if (pProfile == NULL) return E_POINTER;
1034
1035     if (This->tipkey) while (fetched < ulCount)
1036     {
1037         LSTATUS res;
1038         HRESULT hr;
1039         DWORD cName = 39;
1040         GUID clsid;
1041
1042         res = RegEnumKeyExW(This->tipkey, This->tip_index,
1043                     This->szwCurrentClsid, &cName, NULL, NULL, NULL, NULL);
1044         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
1045         ++(This->tip_index);
1046         hr = CLSIDFromString(This->szwCurrentClsid, &clsid);
1047         if (FAILED(hr)) continue;
1048
1049         while ( fetched < ulCount)
1050         {
1051             INT res = next_LanguageProfile(This, clsid, pProfile);
1052             if (res == 1)
1053             {
1054                 ++fetched;
1055                 ++pProfile;
1056             }
1057             else if (res == -1)
1058                 break;
1059             else
1060                 continue;
1061         }
1062     }
1063
1064     if (pcFetch) *pcFetch = fetched;
1065     return fetched == ulCount ? S_OK : S_FALSE;
1066 }
1067
1068 static HRESULT WINAPI EnumTfLanguageProfiles_Skip( IEnumTfLanguageProfiles* iface, ULONG celt)
1069 {
1070     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
1071     FIXME("STUB (%p)\n",This);
1072     return E_NOTIMPL;
1073 }
1074
1075 static HRESULT WINAPI EnumTfLanguageProfiles_Reset( IEnumTfLanguageProfiles* iface)
1076 {
1077     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
1078     TRACE("(%p)\n",This);
1079     This->tip_index = 0;
1080     if (This->langkey)
1081         RegCloseKey(This->langkey);
1082     This->langkey = NULL;
1083     This->lang_index = 0;
1084     return S_OK;
1085 }
1086
1087 static HRESULT WINAPI EnumTfLanguageProfiles_Clone( IEnumTfLanguageProfiles *iface,
1088     IEnumTfLanguageProfiles **ppenum)
1089 {
1090     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
1091     HRESULT res;
1092
1093     TRACE("(%p)\n",This);
1094
1095     if (ppenum == NULL) return E_POINTER;
1096
1097     res = EnumTfLanguageProfiles_Constructor(This->langid, ppenum);
1098     if (SUCCEEDED(res))
1099     {
1100         EnumTfLanguageProfiles *new_This = (EnumTfLanguageProfiles *)*ppenum;
1101         new_This->tip_index = This->tip_index;
1102         lstrcpynW(new_This->szwCurrentClsid,This->szwCurrentClsid,39);
1103
1104         if (This->langkey)
1105         {
1106             WCHAR fullkey[168];
1107             static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
1108
1109             sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
1110             res = RegOpenKeyExW(new_This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
1111             new_This->lang_index = This->lang_index;
1112         }
1113     }
1114     return res;
1115 }
1116
1117 static const IEnumTfLanguageProfilesVtbl IEnumTfLanguageProfiles_Vtbl ={
1118     EnumTfLanguageProfiles_QueryInterface,
1119     EnumTfLanguageProfiles_AddRef,
1120     EnumTfLanguageProfiles_Release,
1121
1122     EnumTfLanguageProfiles_Clone,
1123     EnumTfLanguageProfiles_Next,
1124     EnumTfLanguageProfiles_Reset,
1125     EnumTfLanguageProfiles_Skip
1126 };
1127
1128 static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut)
1129 {
1130     HRESULT hr;
1131     EnumTfLanguageProfiles *This;
1132
1133     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfLanguageProfiles));
1134     if (This == NULL)
1135         return E_OUTOFMEMORY;
1136
1137     This->Vtbl= &IEnumTfLanguageProfiles_Vtbl;
1138     This->refCount = 1;
1139     This->langid = langid;
1140
1141     hr = CategoryMgr_Constructor(NULL,(IUnknown**)&This->catmgr);
1142     if (FAILED(hr))
1143     {
1144         HeapFree(GetProcessHeap(),0,This);
1145         return hr;
1146     }
1147
1148     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
1149                     KEY_READ | KEY_WRITE, NULL, &This->tipkey, NULL) != ERROR_SUCCESS)
1150         return E_FAIL;
1151
1152     TRACE("returning %p\n", This);
1153     *ppOut = (IEnumTfLanguageProfiles*)This;
1154     return S_OK;
1155 }