msctf: Implement ITfInputProcessorProfiles::EnumInputProcessorInfo.
[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 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut);
64
65 static void InputProcessorProfiles_Destructor(InputProcessorProfiles *This)
66 {
67     TRACE("destroying %p\n", This);
68     HeapFree(GetProcessHeap(),0,This);
69 }
70
71 static void add_userkey( REFCLSID rclsid, LANGID langid,
72                                 REFGUID guidProfile)
73 {
74     HKEY key;
75     WCHAR buf[39];
76     WCHAR buf2[39];
77     WCHAR fullkey[168];
78     DWORD disposition = 0;
79     ULONG res;
80
81     TRACE("\n");
82
83     StringFromGUID2(rclsid, buf, 39);
84     StringFromGUID2(guidProfile, buf2, 39);
85     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
86
87     res = RegCreateKeyExW(HKEY_CURRENT_USER,fullkey, 0, NULL, 0,
88                    KEY_READ | KEY_WRITE, NULL, &key, &disposition);
89
90     if (!res && disposition == REG_CREATED_NEW_KEY)
91     {
92         DWORD zero = 0x0;
93         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
94     }
95
96     if (!res)
97         RegCloseKey(key);
98 }
99
100 static HRESULT WINAPI InputProcessorProfiles_QueryInterface(ITfInputProcessorProfiles *iface, REFIID iid, LPVOID *ppvOut)
101 {
102     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
103     *ppvOut = NULL;
104
105     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_ITfInputProcessorProfiles))
106     {
107         *ppvOut = This;
108     }
109
110     if (*ppvOut)
111     {
112         IUnknown_AddRef(iface);
113         return S_OK;
114     }
115
116     WARN("unsupported interface: %s\n", debugstr_guid(iid));
117     return E_NOINTERFACE;
118 }
119
120 static ULONG WINAPI InputProcessorProfiles_AddRef(ITfInputProcessorProfiles *iface)
121 {
122     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
123     return InterlockedIncrement(&This->refCount);
124 }
125
126 static ULONG WINAPI InputProcessorProfiles_Release(ITfInputProcessorProfiles *iface)
127 {
128     InputProcessorProfiles *This = (InputProcessorProfiles *)iface;
129     ULONG ret;
130
131     ret = InterlockedDecrement(&This->refCount);
132     if (ret == 0)
133         InputProcessorProfiles_Destructor(This);
134     return ret;
135 }
136
137 /*****************************************************
138  * ITfInputProcessorProfiles functions
139  *****************************************************/
140 static HRESULT WINAPI InputProcessorProfiles_Register(
141         ITfInputProcessorProfiles *iface, REFCLSID rclsid)
142 {
143     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
144     HKEY tipkey;
145     WCHAR buf[39];
146     WCHAR fullkey[68];
147
148     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
149
150     StringFromGUID2(rclsid, buf, 39);
151     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
152
153     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, NULL, 0,
154                     KEY_READ | KEY_WRITE, NULL, &tipkey, NULL) != ERROR_SUCCESS)
155         return E_FAIL;
156
157     RegCloseKey(tipkey);
158
159     return S_OK;
160 }
161
162 static HRESULT WINAPI InputProcessorProfiles_Unregister(
163         ITfInputProcessorProfiles *iface, REFCLSID rclsid)
164 {
165     WCHAR buf[39];
166     WCHAR fullkey[68];
167     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
168
169     TRACE("(%p) %s\n",This,debugstr_guid(rclsid));
170
171     StringFromGUID2(rclsid, buf, 39);
172     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
173
174     RegDeleteTreeW(HKEY_LOCAL_MACHINE, fullkey);
175     RegDeleteTreeW(HKEY_CURRENT_USER, fullkey);
176
177     return S_OK;
178 }
179
180 static HRESULT WINAPI InputProcessorProfiles_AddLanguageProfile(
181         ITfInputProcessorProfiles *iface, REFCLSID rclsid,
182         LANGID langid, REFGUID guidProfile, const WCHAR *pchDesc,
183         ULONG cchDesc, const WCHAR *pchIconFile, ULONG cchFile,
184         ULONG uIconIndex)
185 {
186     HKEY tipkey,fmtkey;
187     WCHAR buf[39];
188     WCHAR fullkey[100];
189     ULONG res;
190     DWORD disposition = 0;
191
192     static const WCHAR fmt2[] = {'%','s','\\','0','x','%','0','8','x','\\','%','s',0};
193     static const WCHAR desc[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
194     static const WCHAR icnf[] = {'I','c','o','n','F','i','l','e',0};
195     static const WCHAR icni[] = {'I','c','o','n','I','n','d','e','x',0};
196
197     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
198
199     TRACE("(%p) %s %x %s %s %s %i\n",This,debugstr_guid(rclsid), langid,
200             debugstr_guid(guidProfile), debugstr_wn(pchDesc,cchDesc),
201             debugstr_wn(pchIconFile,cchFile),uIconIndex);
202
203     StringFromGUID2(rclsid, buf, 39);
204     sprintfW(fullkey,szwTipfmt,szwSystemTIPKey,buf);
205
206     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,fullkey, 0, KEY_READ | KEY_WRITE,
207                 &tipkey ) != ERROR_SUCCESS)
208         return E_FAIL;
209
210     StringFromGUID2(guidProfile, buf, 39);
211     sprintfW(fullkey,fmt2,szwLngp,langid,buf);
212
213     res = RegCreateKeyExW(tipkey,fullkey, 0, NULL, 0, KEY_READ | KEY_WRITE,
214             NULL, &fmtkey, &disposition);
215
216     if (!res)
217     {
218         DWORD zero = 0x0;
219         RegSetValueExW(fmtkey, desc, 0, REG_SZ, (LPBYTE)pchDesc, cchDesc * sizeof(WCHAR));
220         RegSetValueExW(fmtkey, icnf, 0, REG_SZ, (LPBYTE)pchIconFile, cchFile * sizeof(WCHAR));
221         RegSetValueExW(fmtkey, icni, 0, REG_DWORD, (LPBYTE)&uIconIndex, sizeof(DWORD));
222         if (disposition == REG_CREATED_NEW_KEY)
223             RegSetValueExW(fmtkey, szwEnabled, 0, REG_DWORD, (LPBYTE)&zero, sizeof(DWORD));
224         RegCloseKey(fmtkey);
225
226         add_userkey(rclsid, langid, guidProfile);
227     }
228     RegCloseKey(tipkey);
229
230     if (!res)
231         return S_OK;
232     else
233         return E_FAIL;
234 }
235
236 static HRESULT WINAPI InputProcessorProfiles_RemoveLanguageProfile(
237         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
238         REFGUID guidProfile)
239 {
240     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
241     FIXME("STUB:(%p)\n",This);
242     return E_NOTIMPL;
243 }
244
245 static HRESULT WINAPI InputProcessorProfiles_EnumInputProcessorInfo(
246         ITfInputProcessorProfiles *iface, IEnumGUID **ppEnum)
247 {
248     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
249     TRACE("(%p) %p\n",This,ppEnum);
250     return ProfilesEnumGuid_Constructor(ppEnum);
251 }
252
253 static HRESULT WINAPI InputProcessorProfiles_GetDefaultLanguageProfile(
254         ITfInputProcessorProfiles *iface, LANGID langid, REFGUID catid,
255         CLSID *pclsid, GUID *pguidProfile)
256 {
257     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
258     FIXME("STUB:(%p)\n",This);
259     return E_NOTIMPL;
260 }
261
262 static HRESULT WINAPI InputProcessorProfiles_SetDefaultLanguageProfile(
263         ITfInputProcessorProfiles *iface, LANGID langid, REFCLSID rclsid,
264         REFGUID guidProfiles)
265 {
266     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
267     FIXME("STUB:(%p)\n",This);
268     return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI InputProcessorProfiles_ActivateLanguageProfile(
272         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
273         REFGUID guidProfiles)
274 {
275     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
276     FIXME("STUB:(%p)\n",This);
277     return E_NOTIMPL;
278 }
279
280 static HRESULT WINAPI InputProcessorProfiles_GetActiveLanguageProfile(
281         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID *plangid,
282         GUID *pguidProfile)
283 {
284     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
285     FIXME("STUB:(%p)\n",This);
286     return E_NOTIMPL;
287 }
288
289 static HRESULT WINAPI InputProcessorProfiles_GetLanguageProfileDescription(
290         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
291         REFGUID guidProfile, BSTR *pbstrProfile)
292 {
293     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
294     FIXME("STUB:(%p)\n",This);
295     return E_NOTIMPL;
296 }
297
298 static HRESULT WINAPI InputProcessorProfiles_GetCurrentLanguage(
299         ITfInputProcessorProfiles *iface, LANGID *plangid)
300 {
301     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
302     TRACE("(%p) 0x%x\n",This,This->currentLanguage);
303
304     if (!plangid)
305         return E_INVALIDARG;
306
307     *plangid = This->currentLanguage;
308
309     return S_OK;
310 }
311
312 static HRESULT WINAPI InputProcessorProfiles_ChangeCurrentLanguage(
313         ITfInputProcessorProfiles *iface, LANGID langid)
314 {
315     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
316     FIXME("STUB:(%p)\n",This);
317     return E_NOTIMPL;
318 }
319
320 static HRESULT WINAPI InputProcessorProfiles_GetLanguageList(
321         ITfInputProcessorProfiles *iface, LANGID **ppLangId, ULONG *pulCount)
322 {
323     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
324     FIXME("STUB:(%p)\n",This);
325     return E_NOTIMPL;
326 }
327
328 static HRESULT WINAPI InputProcessorProfiles_EnumLanguageProfiles(
329         ITfInputProcessorProfiles *iface, LANGID langid,
330         IEnumTfLanguageProfiles **ppEnum)
331 {
332     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
333     FIXME("STUB:(%p)\n",This);
334     return E_NOTIMPL;
335 }
336
337 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfile(
338         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
339         REFGUID guidProfile, BOOL fEnable)
340 {
341     HKEY key;
342     WCHAR buf[39];
343     WCHAR buf2[39];
344     WCHAR fullkey[168];
345     ULONG res;
346
347     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
348     TRACE("(%p) %s %x %s %i\n",This, debugstr_guid(rclsid), langid, debugstr_guid(guidProfile), fEnable);
349
350     StringFromGUID2(rclsid, buf, 39);
351     StringFromGUID2(guidProfile, buf2, 39);
352     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
353
354     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
355
356     if (!res)
357     {
358         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
359         RegCloseKey(key);
360     }
361     else
362         return E_FAIL;
363
364     return S_OK;
365 }
366
367 static HRESULT WINAPI InputProcessorProfiles_IsEnabledLanguageProfile(
368         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
369         REFGUID guidProfile, BOOL *pfEnable)
370 {
371     HKEY key;
372     WCHAR buf[39];
373     WCHAR buf2[39];
374     WCHAR fullkey[168];
375     ULONG res;
376
377     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
378     TRACE("(%p) %s, %i, %s, %p\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),pfEnable);
379
380     if (!pfEnable)
381         return E_INVALIDARG;
382
383     StringFromGUID2(rclsid, buf, 39);
384     StringFromGUID2(guidProfile, buf2, 39);
385     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
386
387     res = RegOpenKeyExW(HKEY_CURRENT_USER, fullkey, 0, KEY_READ | KEY_WRITE, &key);
388
389     if (!res)
390     {
391         DWORD count = sizeof(DWORD);
392         res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
393         RegCloseKey(key);
394     }
395
396     if (res)  /* Try Default */
397     {
398         res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
399
400         if (!res)
401         {
402             DWORD count = sizeof(DWORD);
403             res = RegQueryValueExW(key, szwEnabled, 0, NULL, (LPBYTE)pfEnable, &count);
404             RegCloseKey(key);
405         }
406     }
407
408     if (!res)
409         return S_OK;
410     else
411         return E_FAIL;
412 }
413
414 static HRESULT WINAPI InputProcessorProfiles_EnableLanguageProfileByDefault(
415         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
416         REFGUID guidProfile, BOOL fEnable)
417 {
418     HKEY key;
419     WCHAR buf[39];
420     WCHAR buf2[39];
421     WCHAR fullkey[168];
422     ULONG res;
423
424     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
425     TRACE("(%p) %s %x %s %i\n",This,debugstr_guid(rclsid),langid,debugstr_guid(guidProfile),fEnable);
426
427     StringFromGUID2(rclsid, buf, 39);
428     StringFromGUID2(guidProfile, buf2, 39);
429     sprintfW(fullkey,szwFullLangfmt,szwSystemTIPKey,buf,szwLngp,langid,buf2);
430
431     res = RegOpenKeyExW(HKEY_LOCAL_MACHINE, fullkey, 0, KEY_READ | KEY_WRITE, &key);
432
433     if (!res)
434     {
435         RegSetValueExW(key, szwEnabled, 0, REG_DWORD, (LPBYTE)&fEnable, sizeof(DWORD));
436         RegCloseKey(key);
437     }
438     else
439         return E_FAIL;
440
441     return S_OK;
442 }
443
444 static HRESULT WINAPI InputProcessorProfiles_SubstituteKeyboardLayout(
445         ITfInputProcessorProfiles *iface, REFCLSID rclsid, LANGID langid,
446         REFGUID guidProfile, HKL hKL)
447 {
448     InputProcessorProfiles *This = (InputProcessorProfiles*)iface;
449     FIXME("STUB:(%p)\n",This);
450     return E_NOTIMPL;
451 }
452
453
454 static const ITfInputProcessorProfilesVtbl InputProcessorProfiles_InputProcessorProfilesVtbl =
455 {
456     InputProcessorProfiles_QueryInterface,
457     InputProcessorProfiles_AddRef,
458     InputProcessorProfiles_Release,
459
460     InputProcessorProfiles_Register,
461     InputProcessorProfiles_Unregister,
462     InputProcessorProfiles_AddLanguageProfile,
463     InputProcessorProfiles_RemoveLanguageProfile,
464     InputProcessorProfiles_EnumInputProcessorInfo,
465     InputProcessorProfiles_GetDefaultLanguageProfile,
466     InputProcessorProfiles_SetDefaultLanguageProfile,
467     InputProcessorProfiles_ActivateLanguageProfile,
468     InputProcessorProfiles_GetActiveLanguageProfile,
469     InputProcessorProfiles_GetLanguageProfileDescription,
470     InputProcessorProfiles_GetCurrentLanguage,
471     InputProcessorProfiles_ChangeCurrentLanguage,
472     InputProcessorProfiles_GetLanguageList,
473     InputProcessorProfiles_EnumLanguageProfiles,
474     InputProcessorProfiles_EnableLanguageProfile,
475     InputProcessorProfiles_IsEnabledLanguageProfile,
476     InputProcessorProfiles_EnableLanguageProfileByDefault,
477     InputProcessorProfiles_SubstituteKeyboardLayout
478 };
479
480 HRESULT InputProcessorProfiles_Constructor(IUnknown *pUnkOuter, IUnknown **ppOut)
481 {
482     InputProcessorProfiles *This;
483     if (pUnkOuter)
484         return CLASS_E_NOAGGREGATION;
485
486     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(InputProcessorProfiles));
487     if (This == NULL)
488         return E_OUTOFMEMORY;
489
490     This->InputProcessorProfilesVtbl= &InputProcessorProfiles_InputProcessorProfilesVtbl;
491     This->refCount = 1;
492     This->currentLanguage = GetUserDefaultLCID();
493
494     TRACE("returning %p\n", This);
495     *ppOut = (IUnknown *)This;
496     return S_OK;
497 }
498
499 /**************************************************
500  * IEnumGUID implementaion for ITfInputProcessorProfiles::EnumInputProcessorInfo
501  **************************************************/
502 static void ProfilesEnumGuid_Destructor(ProfilesEnumGuid *This)
503 {
504     TRACE("destroying %p\n", This);
505     RegCloseKey(This->key);
506     HeapFree(GetProcessHeap(),0,This);
507 }
508
509 static HRESULT WINAPI ProfilesEnumGuid_QueryInterface(IEnumGUID *iface, REFIID iid, LPVOID *ppvOut)
510 {
511     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
512     *ppvOut = NULL;
513
514     if (IsEqualIID(iid, &IID_IUnknown) || IsEqualIID(iid, &IID_IEnumGUID))
515     {
516         *ppvOut = This;
517     }
518
519     if (*ppvOut)
520     {
521         IUnknown_AddRef(iface);
522         return S_OK;
523     }
524
525     WARN("unsupported interface: %s\n", debugstr_guid(iid));
526     return E_NOINTERFACE;
527 }
528
529 static ULONG WINAPI ProfilesEnumGuid_AddRef(IEnumGUID *iface)
530 {
531     ProfilesEnumGuid *This = (ProfilesEnumGuid*)iface;
532     return InterlockedIncrement(&This->refCount);
533 }
534
535 static ULONG WINAPI ProfilesEnumGuid_Release(IEnumGUID *iface)
536 {
537     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
538     ULONG ret;
539
540     ret = InterlockedDecrement(&This->refCount);
541     if (ret == 0)
542         ProfilesEnumGuid_Destructor(This);
543     return ret;
544 }
545
546 /*****************************************************
547  * IEnumGuid functions
548  *****************************************************/
549 static HRESULT WINAPI ProfilesEnumGuid_Next( LPENUMGUID iface,
550     ULONG celt, GUID *rgelt, ULONG *pceltFetched)
551 {
552     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
553     ULONG fetched = 0;
554
555     TRACE("(%p)\n",This);
556
557     if (rgelt == NULL) return E_POINTER;
558
559     if (This->key) while (fetched < celt)
560     {
561         LSTATUS res;
562         HRESULT hr;
563         WCHAR catid[39];
564         DWORD cName = 39;
565
566         res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
567                     NULL, NULL, NULL, NULL);
568         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
569         ++(This->next_index);
570
571         hr = CLSIDFromString(catid, rgelt);
572         if (FAILED(hr)) continue;
573
574         ++fetched;
575         ++rgelt;
576     }
577
578     if (pceltFetched) *pceltFetched = fetched;
579     return fetched == celt ? S_OK : S_FALSE;
580 }
581
582 static HRESULT WINAPI ProfilesEnumGuid_Skip( LPENUMGUID iface, ULONG celt)
583 {
584     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
585     TRACE("(%p)\n",This);
586
587     This->next_index += celt;
588     return S_OK;
589 }
590
591 static HRESULT WINAPI ProfilesEnumGuid_Reset( LPENUMGUID iface)
592 {
593     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
594     TRACE("(%p)\n",This);
595     This->next_index = 0;
596     return S_OK;
597 }
598
599 static HRESULT WINAPI ProfilesEnumGuid_Clone( LPENUMGUID iface,
600     IEnumGUID **ppenum)
601 {
602     ProfilesEnumGuid *This = (ProfilesEnumGuid *)iface;
603     HRESULT res;
604
605     TRACE("(%p)\n",This);
606
607     if (ppenum == NULL) return E_POINTER;
608
609     res = ProfilesEnumGuid_Constructor(ppenum);
610     if (SUCCEEDED(res))
611     {
612         ProfilesEnumGuid *new_This = (ProfilesEnumGuid *)*ppenum;
613         new_This->next_index = This->next_index;
614     }
615     return res;
616 }
617
618 static const IEnumGUIDVtbl IEnumGUID_Vtbl ={
619     ProfilesEnumGuid_QueryInterface,
620     ProfilesEnumGuid_AddRef,
621     ProfilesEnumGuid_Release,
622
623     ProfilesEnumGuid_Next,
624     ProfilesEnumGuid_Skip,
625     ProfilesEnumGuid_Reset,
626     ProfilesEnumGuid_Clone
627 };
628
629 static HRESULT ProfilesEnumGuid_Constructor(IEnumGUID **ppOut)
630 {
631     ProfilesEnumGuid *This;
632
633     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(ProfilesEnumGuid));
634     if (This == NULL)
635         return E_OUTOFMEMORY;
636
637     This->Vtbl= &IEnumGUID_Vtbl;
638     This->refCount = 1;
639
640     if (RegCreateKeyExW(HKEY_LOCAL_MACHINE, szwSystemTIPKey, 0, NULL, 0,
641                     KEY_READ | KEY_WRITE, NULL, &This->key, NULL) != ERROR_SUCCESS)
642         return E_FAIL;
643
644     TRACE("returning %p\n", This);
645     *ppOut = (IEnumGUID*)This;
646     return S_OK;
647 }