setupapi: Enable Browse action on SetupPromptForDisk dialog.
[wine] / dlls / msctf / inputprocessor.c
1 /*
2  *  ITfInputProcessorProfiles implementation
3  *
4  *  Copyright 2009 Aric Stewart, CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #define COBJMACROS
26
27 #include "wine/debug.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winreg.h"
31 #include "winuser.h"
32 #include "shlwapi.h"
33 #include "winerror.h"
34 #include "objbase.h"
35
36 #include "wine/unicode.h"
37
38 #include "msctf.h"
39 #include "msctf_internal.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msctf);
42
43 static const WCHAR szwLngp[] = {'L','a','n','g','u','a','g','e','P','r','o','f','i','l','e',0};
44 static const WCHAR szwEnabled[] = {'E','n','a','b','l','e','d',0};
45 static const WCHAR szwTipfmt[] = {'%','s','\\','%','s',0};
46 static const WCHAR szwFullLangfmt[] = {'%','s','\\','%','s','\\','%','s','\\','0','x','%','0','8','x','\\','%','s',0};
47
48 typedef struct tagInputProcessorProfiles {
49     const ITfInputProcessorProfilesVtbl *InputProcessorProfilesVtbl;
50     LONG refCount;
51
52     LANGID  currentLanguage;
53 } InputProcessorProfiles;
54
55 typedef struct tagProfilesEnumGuid {
56     const IEnumGUIDVtbl *Vtbl;
57     LONG refCount;
58
59     HKEY key;
60     DWORD next_index;
61 } ProfilesEnumGuid;
62
63 typedef struct tagEnumTfLanguageProfiles {
64     const IEnumTfLanguageProfilesVtbl *Vtbl;
65     LONG refCount;
66
67     HKEY    tipkey;
68     DWORD   tip_index;
69     WCHAR   szwCurrentClsid[39];
70
71     HKEY    langkey;
72     DWORD   lang_index;
73
74     LANGID  langid;
75 } EnumTfLanguageProfiles;
76
77 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut);
78 static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut);
79
80 static void InputProcessorProfiles_Destructor(InputProcessorProfiles *This)
81 {
82     TRACE("destroying %p\n", This);
83     HeapFree(GetProcessHeap(),0,This);
84 }
85
86 static void add_userkey( REFCLSID rclsid, LANGID langid,
87                                 REFGUID guidProfile)
88 {
89     HKEY key;
90     WCHAR buf[39];
91     WCHAR buf2[39];
92     WCHAR fullkey[168];
93     DWORD disposition = 0;
94     ULONG res;
95
96     TRACE("\n");
97
98     StringFromGUID2(rclsid, buf, 39);
99     StringFromGUID2(guidProfile, buf2, 39);
100     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
101
102     res = RegCreateKeyExW(HKEY_CURRENT_USER,fullkey, 0, NULL, 0,
103                    KEY_READ | KEY_WRITE, NULL, &key, &disposition);
104
105     if (!res && disposition == REG_CREATED_NEW_KEY)
106     {
107         DWORD zero = 0x0;
108         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
109     }
110
111     if (!res)
112         RegCloseKey(key);
113 }
114
115 static HRESULT WINAPI InputProcessorProfiles_QueryInterface(ITfInputProcessorProfiles *iface, REFIID iid, LPVOID *ppvOut)
116 {
117     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
118     *ppvOut = NULL;
119
120     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfInputProcessorProfiles))
121     {
122         *ppvOut = This;
123     }
124
125     if (*ppvOut)
126     {
127         IUnknown_AddRef(iface);
128         return S_OK;
129     }
130
131     WARN("unsupported interface: %s\n", debugstr_guid(iid));
132     return E_NOINTERFACE;
133 }
134
135 static ULONG WINAPI InputProcessorProfiles_AddRef(ITfInputProcessorProfiles *iface)
136 {
137     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
138     return InterlockedIncrement(&This->refCount);
139 }
140
141 static ULONG WINAPI InputProcessorProfiles_Release(ITfInputProcessorProfiles *iface)
142 {
143     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
144     ULONG ret;
145
146     ret = InterlockedDecrement(&This->refCount);
147     if (ret == 0)
148         InputProcessorProfiles_Destructor(This);
149     return ret;
150 }
151
152 /*****************************************************
153  * ITfInputProcessorProfiles functions
154  *****************************************************/
155 static HRESULT WINAPI InputProcessorProfiles_Register(
156         ITfInputProcessorProfiles *iface, REFCLSID rclsid)
157 {
158     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
159     HKEY tipkey;
160     WCHAR buf[39];
161     WCHAR fullkey[68];
162
163     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
164
165     StringFromGUID2(rclsid, buf, 39);
166     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
167
168     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, NULL, 0,
169                     KEY_READ | KEY_WRITE, NULL, &tipkey, NULL) != ERROR_SUCCESS)
170         return E_FAIL;
171
172     RegCloseKey(tipkey);
173
174     return S_OK;
175 }
176
177 static HRESULT WINAPI InputProcessorProfiles_Unregister(
178         ITfInputProcessorProfiles *iface, REFCLSID rclsid)
179 {
180     WCHAR buf[39];
181     WCHAR fullkey[68];
182     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
183
184     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
185
186     StringFromGUID2(rclsid, buf, 39);
187     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
188
189     RegDeleteTreeW(HKEY_LOCAL_MACHINE, fullkey);
190     RegDeleteTreeW(HKEY_CURRENT_USER, fullkey);
191
192     return S_OK;
193 }
194
195 static HRESULT WINAPI InputProcessorProfiles_AddLanguageProfile(
196         ITfInputProcessorProfiles *iface, REFCLSID rclsid,
197         LANGID langid, REFGUID guidProfile, const WCHAR *pchDesc,
198         ULONG cchDesc, const WCHAR *pchIconFile, ULONG cchFile,
199         ULONG uIconIndex)
200 {
201     HKEY tipkey,fmtkey;
202     WCHAR buf[39];
203     WCHAR fullkey[100];
204     ULONG res;
205     DWORD disposition = 0;
206
207     static const WCHAR fmt2[] = {'%','s','\\','0','x','%','0','8','x','\\','%','s',0};
208     static const WCHAR desc[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
209     static const WCHAR icnf[] = {'I','c','o','n','F','i','l','e',0};
210     static const WCHAR icni[] = {'I','c','o','n','I','n','d','e','x',0};
211
212     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
213
214     TRACE("(%p) %s %x %s %s %s %i\n",This,debugstr_guid(rclsid), langid,
215             debugstr_guid(guidProfile), debugstr_wn(pchDesc,cchDesc),
216             debugstr_wn(pchIconFile,cchFile),uIconIndex);
217
218     StringFromGUID2(rclsid, buf, 39);
219     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
220
221     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
222                 &tipkey ) != ERROR_SUCCESS)
223         return E_FAIL;
224
225     StringFromGUID2(guidProfile, buf, 39);
226     sprintfW(fullkey,fmt2,szwLngp,langid,buf);
227
228     res = RegCreateKeyExW(tipkey,fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
229             NULL, &fmtkey, &disposition);
230
231     if (!res)
232     {
233         DWORD zero = 0x0;
234         RegSetValueExW(fmtkey, desc, 0, REG_SZ, (LPBYTE)pchDesc, cchDesc * sizeof(WCHAR));
235         RegSetValueExW(fmtkey, icnf, 0, REG_SZ, (LPBYTE)pchIconFile, cchFile * sizeof(WCHAR));
236         RegSetValueExW(fmtkey, icni, 0, REG_DWORD, (LPBYTE)&uIconIndex, sizeof(DWORD));
237         if (disposition == REG_CREATED_NEW_KEY)
238             RegSetValueExW(fmtkey, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
239         RegCloseKey(fmtkey);
240
241         add_userkey(rclsid, langid, guidProfile);
242     }
243     RegCloseKey(tipkey);
244
245     if (!res)
246         return S_OK;
247     else
248         return E_FAIL;
249 }
250
251 static HRESULT WINAPI InputProcessorProfiles_RemoveLanguageProfile(
252         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
253         REFGUID guidProfile)
254 {
255     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
256     FIXME("STUB:(%p)\n",This);
257     return E_NOTIMPL;
258 }
259
260 static HRESULT WINAPI InputProcessorProfiles_EnumInputProcessorInfo(
261         ITfInputProcessorProfiles *iface, IEnumGUID **ppEnum)
262 {
263     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
264     TRACE("(%p) %p\n",This,ppEnum);
265     return ProfilesEnumGuid_Constructor(ppEnum);
266 }
267
268 static HRESULT WINAPI InputProcessorProfiles_GetDefaultLanguageProfile(
269         ITfInputProcessorProfiles *iface, LANGID langid, REFGUID catid,
270         CLSID *pclsid, GUID *pguidProfile)
271 {
272     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
273     FIXME("STUB:(%p)\n",This);
274     return E_NOTIMPL;
275 }
276
277 static HRESULT WINAPI InputProcessorProfiles_SetDefaultLanguageProfile(
278         ITfInputProcessorProfiles *iface, LANGID langid, REFCLSID rclsid,
279         REFGUID guidProfiles)
280 {
281     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
282     FIXME("STUB:(%p)\n",This);
283     return E_NOTIMPL;
284 }
285
286 static HRESULT WINAPI InputProcessorProfiles_ActivateLanguageProfile(
287         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
288         REFGUID guidProfiles)
289 {
290     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
291     FIXME("STUB:(%p)\n",This);
292     return E_NOTIMPL;
293 }
294
295 static HRESULT WINAPI InputProcessorProfiles_GetActiveLanguageProfile(
296         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID *plangid,
297         GUID *pguidProfile)
298 {
299     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
300     FIXME("STUB:(%p)\n",This);
301     return E_NOTIMPL;
302 }
303
304 static HRESULT WINAPI InputProcessorProfiles_GetLanguageProfileDescription(
305         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
306         REFGUID guidProfile, BSTR *pbstrProfile)
307 {
308     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
309     FIXME("STUB:(%p)\n",This);
310     return E_NOTIMPL;
311 }
312
313 static HRESULT WINAPI InputProcessorProfiles_GetCurrentLanguage(
314         ITfInputProcessorProfiles *iface, LANGID *plangid)
315 {
316     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
317     TRACE("(%p) 0x%x\n",This,This->currentLanguage);
318
319     if (!plangid)
320         return E_INVALIDARG;
321
322     *plangid = This->currentLanguage;
323
324     return S_OK;
325 }
326
327 static HRESULT WINAPI InputProcessorProfiles_ChangeCurrentLanguage(
328         ITfInputProcessorProfiles *iface, LANGID langid)
329 {
330     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
331     FIXME("STUB:(%p)\n",This);
332     return E_NOTIMPL;
333 }
334
335 static HRESULT WINAPI InputProcessorProfiles_GetLanguageList(
336         ITfInputProcessorProfiles *iface, LANGID **ppLangId, ULONG *pulCount)
337 {
338     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
339     FIXME("STUB:(%p)\n",This);
340     return E_NOTIMPL;
341 }
342
343 static HRESULT WINAPI InputProcessorProfiles_EnumLanguageProfiles(
344         ITfInputProcessorProfiles *iface, LANGID langid,
345         IEnumTfLanguageProfiles **ppEnum)
346 {
347     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
348     TRACE("(%p) %x %p\n",This,langid,ppEnum);
349     return EnumTfLanguageProfiles_Constructor(langid, ppEnum);
350 }
351
352 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfile(
353         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
354         REFGUID guidProfile, BOOL fEnable)
355 {
356     HKEY key;
357     WCHAR buf[39];
358     WCHAR buf2[39];
359     WCHAR fullkey[168];
360     ULONG res;
361
362     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
363     TRACE("(%p) %s %x %s %i\n",This, debugstr_guid(rclsid), langid, debugstr_guid(guidProfile), fEnable);
364
365     StringFromGUID2(rclsid, buf, 39);
366     StringFromGUID2(guidProfile, buf2, 39);
367     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
368
369     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
370
371     if (!res)
372     {
373         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
374         RegCloseKey(key);
375     }
376     else
377         return E_FAIL;
378
379     return S_OK;
380 }
381
382 static HRESULT WINAPI InputProcessorProfiles_IsEnabledLanguageProfile(
383         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
384         REFGUID guidProfile, BOOL *pfEnable)
385 {
386     HKEY key;
387     WCHAR buf[39];
388     WCHAR buf2[39];
389     WCHAR fullkey[168];
390     ULONG res;
391
392     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
393     TRACE("(%p) %s, %i, %s, %p\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),pfEnable);
394
395     if (!pfEnable)
396         return E_INVALIDARG;
397
398     StringFromGUID2(rclsid, buf, 39);
399     StringFromGUID2(guidProfile, buf2, 39);
400     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
401
402     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
403
404     if (!res)
405     {
406         DWORD count = sizeof(DWORD);
407         res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
408         RegCloseKey(key);
409     }
410
411     if (res)  /* Try Default */
412     {
413         res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
414
415         if (!res)
416         {
417             DWORD count = sizeof(DWORD);
418             res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
419             RegCloseKey(key);
420         }
421     }
422
423     if (!res)
424         return S_OK;
425     else
426         return E_FAIL;
427 }
428
429 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfileByDefault(
430         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
431         REFGUID guidProfile, BOOL fEnable)
432 {
433     HKEY key;
434     WCHAR buf[39];
435     WCHAR buf2[39];
436     WCHAR fullkey[168];
437     ULONG res;
438
439     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
440     TRACE("(%p) %s %x %s %i\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),fEnable);
441
442     StringFromGUID2(rclsid, buf, 39);
443     StringFromGUID2(guidProfile, buf2, 39);
444     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
445
446     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
447
448     if (!res)
449     {
450         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
451         RegCloseKey(key);
452     }
453     else
454         return E_FAIL;
455
456     return S_OK;
457 }
458
459 static HRESULT WINAPI InputProcessorProfiles_SubstituteKeyboardLayout(
460         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
461         REFGUID guidProfile, HKL hKL)
462 {
463     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
464     FIXME("STUB:(%p)\n",This);
465     return E_NOTIMPL;
466 }
467
468
469 static const ITfInputProcessorProfilesVtbl InputProcessorProfiles_InputProcessorProfilesVtbl =
470 {
471     InputProcessorProfiles_QueryInterface,
472     InputProcessorProfiles_AddRef,
473     InputProcessorProfiles_Release,
474
475     InputProcessorProfiles_Register,
476     InputProcessorProfiles_Unregister,
477     InputProcessorProfiles_AddLanguageProfile,
478     InputProcessorProfiles_RemoveLanguageProfile,
479     InputProcessorProfiles_EnumInputProcessorInfo,
480     InputProcessorProfiles_GetDefaultLanguageProfile,
481     InputProcessorProfiles_SetDefaultLanguageProfile,
482     InputProcessorProfiles_ActivateLanguageProfile,
483     InputProcessorProfiles_GetActiveLanguageProfile,
484     InputProcessorProfiles_GetLanguageProfileDescription,
485     InputProcessorProfiles_GetCurrentLanguage,
486     InputProcessorProfiles_ChangeCurrentLanguage,
487     InputProcessorProfiles_GetLanguageList,
488     InputProcessorProfiles_EnumLanguageProfiles,
489     InputProcessorProfiles_EnableLanguageProfile,
490     InputProcessorProfiles_IsEnabledLanguageProfile,
491     InputProcessorProfiles_EnableLanguageProfileByDefault,
492     InputProcessorProfiles_SubstituteKeyboardLayout
493 };
494
495 HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
496 {
497     InputProcessorProfiles *This;
498     if (pUnkOuter)
499         return CLASS_E_NOAGGREGATION;
500
501     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputProcessorProfiles));
502     if (This == NULL)
503         return E_OUTOFMEMORY;
504
505     This->InputProcessorProfilesVtbl= &InputProcessorProfiles_InputProcessorProfilesVtbl;
506     This->refCount = 1;
507     This->currentLanguage = GetUserDefaultLCID();
508
509     TRACE("returning %p\n", This);
510     *ppOut = (IUnknown *)This;
511     return S_OK;
512 }
513
514 /**************************************************
515  * IEnumGUID implementaion for ITfInputProcessorProfiles::EnumInputProcessorInfo
516  **************************************************/
517 static void ProfilesEnumGuid_Destructor(ProfilesEnumGuid *This)
518 {
519     TRACE("destroying %p\n", This);
520     RegCloseKey(This->key);
521     HeapFree(GetProcessHeap(),0,This);
522 }
523
524 static HRESULT WINAPI ProfilesEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
525 {
526     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
527     *ppvOut = NULL;
528
529     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
530     {
531         *ppvOut = This;
532     }
533
534     if (*ppvOut)
535     {
536         IUnknown_AddRef(iface);
537         return S_OK;
538     }
539
540     WARN("unsupported interface: %s\n", debugstr_guid(iid));
541     return E_NOINTERFACE;
542 }
543
544 static ULONG WINAPI ProfilesEnumGuid_AddRef(IEnumGUID *iface)
545 {
546     ProfilesEnumGuid *This = (ProfilesEnumGuid*)iface;
547     return InterlockedIncrement(&This->refCount);
548 }
549
550 static ULONG WINAPI ProfilesEnumGuid_Release(IEnumGUID *iface)
551 {
552     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
553     ULONG ret;
554
555     ret = InterlockedDecrement(&This->refCount);
556     if (ret == 0)
557         ProfilesEnumGuid_Destructor(This);
558     return ret;
559 }
560
561 /*****************************************************
562  * IEnumGuid functions
563  *****************************************************/
564 static HRESULT WINAPI ProfilesEnumGuid_Next( LPENUMGUID iface,
565     ULONG celt, GUID *rgelt, ULONG *pceltFetched)
566 {
567     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
568     ULONG fetched = 0;
569
570     TRACE("(%p)\n",This);
571
572     if (rgelt == NULL) return E_POINTER;
573
574     if (This->key) while (fetched < celt)
575     {
576         LSTATUS res;
577         HRESULT hr;
578         WCHAR catid[39];
579         DWORD cName = 39;
580
581         res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
582                     NULL, NULL, NULL, NULL);
583         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
584         ++(This->next_index);
585
586         hr = CLSIDFromString(catid, rgelt);
587         if (FAILED(hr)) continue;
588
589         ++fetched;
590         ++rgelt;
591     }
592
593     if (pceltFetched) *pceltFetched = fetched;
594     return fetched == celt ? S_OK : S_FALSE;
595 }
596
597 static HRESULT WINAPI ProfilesEnumGuid_Skip( LPENUMGUID iface, ULONG celt)
598 {
599     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
600     TRACE("(%p)\n",This);
601
602     This->next_index += celt;
603     return S_OK;
604 }
605
606 static HRESULT WINAPI ProfilesEnumGuid_Reset( LPENUMGUID iface)
607 {
608     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
609     TRACE("(%p)\n",This);
610     This->next_index = 0;
611     return S_OK;
612 }
613
614 static HRESULT WINAPI ProfilesEnumGuid_Clone( LPENUMGUID iface,
615     IEnumGUID **ppenum)
616 {
617     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
618     HRESULT res;
619
620     TRACE("(%p)\n",This);
621
622     if (ppenum == NULL) return E_POINTER;
623
624     res = ProfilesEnumGuid_Constructor(ppenum);
625     if (SUCCEEDED(res))
626     {
627         ProfilesEnumGuid *new_This = (ProfilesEnumGuid *)*ppenum;
628         new_This->next_index = This->next_index;
629     }
630     return res;
631 }
632
633 static const IEnumGUIDVtbl IEnumGUID_Vtbl ={
634     ProfilesEnumGuid_QueryInterface,
635     ProfilesEnumGuid_AddRef,
636     ProfilesEnumGuid_Release,
637
638     ProfilesEnumGuid_Next,
639     ProfilesEnumGuid_Skip,
640     ProfilesEnumGuid_Reset,
641     ProfilesEnumGuid_Clone
642 };
643
644 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut)
645 {
646     ProfilesEnumGuid *This;
647
648     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ProfilesEnumGuid));
649     if (This == NULL)
650         return E_OUTOFMEMORY;
651
652     This->Vtbl= &IEnumGUID_Vtbl;
653     This->refCount = 1;
654
655     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
656                     KEY_READ | KEY_WRITE, NULL, &This->key, NULL) != ERROR_SUCCESS)
657         return E_FAIL;
658
659     TRACE("returning %p\n", This);
660     *ppOut = (IEnumGUID*)This;
661     return S_OK;
662 }
663
664 /**************************************************
665  * IEnumTfLanguageProfiles implementaion
666  **************************************************/
667 static void EnumTfLanguageProfiles_Destructor(EnumTfLanguageProfiles *This)
668 {
669     TRACE("destroying %p\n", This);
670     RegCloseKey(This->tipkey);
671     if (This->langkey)
672         RegCloseKey(This->langkey);
673     HeapFree(GetProcessHeap(),0,This);
674 }
675
676 static HRESULT WINAPI EnumTfLanguageProfiles_QueryInterface(IEnumTfLanguageProfiles *iface, REFIID iid, LPVOID *ppvOut)
677 {
678     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
679     *ppvOut = NULL;
680
681     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumTfLanguageProfiles))
682     {
683         *ppvOut = This;
684     }
685
686     if (*ppvOut)
687     {
688         IUnknown_AddRef(iface);
689         return S_OK;
690     }
691
692     WARN("unsupported interface: %s\n", debugstr_guid(iid));
693     return E_NOINTERFACE;
694 }
695
696 static ULONG WINAPI EnumTfLanguageProfiles_AddRef(IEnumTfLanguageProfiles *iface)
697 {
698     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles*)iface;
699     return InterlockedIncrement(&This->refCount);
700 }
701
702 static ULONG WINAPI EnumTfLanguageProfiles_Release(IEnumTfLanguageProfiles *iface)
703 {
704     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
705     ULONG ret;
706
707     ret = InterlockedDecrement(&This->refCount);
708     if (ret == 0)
709         EnumTfLanguageProfiles_Destructor(This);
710     return ret;
711 }
712
713 /*****************************************************
714  * IEnumGuid functions
715  *****************************************************/
716 static INT next_LanguageProfile(EnumTfLanguageProfiles *This, CLSID clsid, TF_LANGUAGEPROFILE *tflp)
717 {
718     WCHAR fullkey[168];
719     ULONG res;
720     WCHAR profileid[39];
721     DWORD cName = 39;
722     GUID  profile;
723
724     static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
725
726     if (This->langkey == NULL)
727     {
728         sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
729         res = RegOpenKeyExW(This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
730         if (res)
731         {
732             This->langkey = NULL;
733             return -1;
734         }
735         This->lang_index = 0;
736     }
737     res = RegEnumKeyExW(This->langkey, This->lang_index, profileid, &cName,
738                 NULL, NULL, NULL, NULL);
739     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
740     {
741         RegCloseKey(This->langkey);
742         This->langkey = NULL;
743         return -1;
744     }
745     ++(This->lang_index);
746
747     if (tflp)
748     {
749         res = CLSIDFromString(profileid, &profile);
750         if (FAILED(res)) return 0;
751
752         tflp->clsid = clsid;
753         tflp->langid = This->langid;
754         /* FIXME */
755         tflp->fActive = FALSE;
756         tflp->guidProfile = profile;
757         /* FIXME set catid */
758     }
759
760     return 1;
761 }
762
763 static HRESULT WINAPI EnumTfLanguageProfiles_Next(IEnumTfLanguageProfiles *iface,
764     ULONG ulCount, TF_LANGUAGEPROFILE *pProfile, ULONG *pcFetch)
765 {
766     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
767     ULONG fetched = 0;
768
769     TRACE("(%p)\n",This);
770
771     if (pProfile == NULL) return E_POINTER;
772
773     if (This->tipkey) while (fetched < ulCount)
774     {
775         LSTATUS res;
776         HRESULT hr;
777         DWORD cName = 39;
778         GUID clsid;
779
780         res = RegEnumKeyExW(This->tipkey, This->tip_index,
781                     This->szwCurrentClsid, &cName, NULL, NULL, NULL, NULL);
782         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
783         ++(This->tip_index);
784         hr = CLSIDFromString(This->szwCurrentClsid, &clsid);
785         if (FAILED(hr)) continue;
786
787         while ( fetched < ulCount)
788         {
789             INT res = next_LanguageProfile(This, clsid, pProfile);
790             if (res == 1)
791             {
792                 ++fetched;
793                 ++pProfile;
794             }
795             else if (res == -1)
796                 break;
797             else
798                 continue;
799         }
800     }
801
802     if (pcFetch) *pcFetch = fetched;
803     return fetched == ulCount ? S_OK : S_FALSE;
804 }
805
806 static HRESULT WINAPI EnumTfLanguageProfiles_Skip( IEnumTfLanguageProfiles* iface, ULONG celt)
807 {
808     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
809     FIXME("STUB (%p)\n",This);
810     return E_NOTIMPL;
811 }
812
813 static HRESULT WINAPI EnumTfLanguageProfiles_Reset( IEnumTfLanguageProfiles* iface)
814 {
815     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
816     TRACE("(%p)\n",This);
817     This->tip_index = 0;
818     if (This->langkey)
819         RegCloseKey(This->langkey);
820     This->langkey = NULL;
821     This->lang_index = 0;
822     return S_OK;
823 }
824
825 static HRESULT WINAPI EnumTfLanguageProfiles_Clone( IEnumTfLanguageProfiles *iface,
826     IEnumTfLanguageProfiles **ppenum)
827 {
828     EnumTfLanguageProfiles *This = (EnumTfLanguageProfiles *)iface;
829     HRESULT res;
830
831     TRACE("(%p)\n",This);
832
833     if (ppenum == NULL) return E_POINTER;
834
835     res = EnumTfLanguageProfiles_Constructor(This->langid, ppenum);
836     if (SUCCEEDED(res))
837     {
838         EnumTfLanguageProfiles *new_This = (EnumTfLanguageProfiles *)*ppenum;
839         new_This->tip_index = This->tip_index;
840         lstrcpynW(new_This->szwCurrentClsid,This->szwCurrentClsid,39);
841
842         if (This->langkey)
843         {
844             WCHAR fullkey[168];
845             static const WCHAR fmt[] = {'%','s','\\','%','s','\\','0','x','%','0','8','x',0};
846
847             sprintfW(fullkey,fmt,This->szwCurrentClsid,szwLngp,This->langid);
848             res = RegOpenKeyExW(new_This->tipkey, fullkey, 0, KEY_READ | KEY_WRITE, &This->langkey);
849             new_This->lang_index = This->lang_index;
850         }
851     }
852     return res;
853 }
854
855 static const IEnumTfLanguageProfilesVtbl IEnumTfLanguageProfiles_Vtbl ={
856     EnumTfLanguageProfiles_QueryInterface,
857     EnumTfLanguageProfiles_AddRef,
858     EnumTfLanguageProfiles_Release,
859
860     EnumTfLanguageProfiles_Clone,
861     EnumTfLanguageProfiles_Next,
862     EnumTfLanguageProfiles_Reset,
863     EnumTfLanguageProfiles_Skip
864 };
865
866 static HRESULT EnumTfLanguageProfiles_Constructor(LANGID langid, IEnumTfLanguageProfiles **ppOut)
867 {
868     EnumTfLanguageProfiles *This;
869
870     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(EnumTfLanguageProfiles));
871     if (This == NULL)
872         return E_OUTOFMEMORY;
873
874     This->Vtbl= &IEnumTfLanguageProfiles_Vtbl;
875     This->refCount = 1;
876     This->langid = langid;
877
878     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
879                     KEY_READ | KEY_WRITE, NULL, &This->tipkey, NULL) != ERROR_SUCCESS)
880         return E_FAIL;
881
882     TRACE("returning %p\n", This);
883     *ppOut = (IEnumTfLanguageProfiles*)This;
884     return S_OK;
885 }